emahiro/b.log

勉強記録と書評とたまに長めの呟きを書きます

go get 時の `import path does not begin with hostname` でハマった話

1年近くGo書いててGOROOTの設定が間違ってたっていう話を書くのもお恥ずかしい話ではあるんですが備忘録のため

環境としては

  • brewでgoを入れている
  • gorootをテキトーにしか設定してなかった($HOME/goみたいな)

エラーの内容は go get コマンドを叩くと

package bufio: unrecognized import path "bufio"
# 以下標準packageのimportに失敗する

というエラーでした。

普段app-engineしかいじってないので正規のgoをいじってpackageを入れようとしたら入らなくて色々こねくり回してました。 最終的には brew で goを入れた場合のlibexecのpathをgorootに指定することで解決しました。

標準packageのところでミスっているのでGOROOT周りの設定がおかしいのでは?っていうところにはすぐ行き着いたのですが、それにしても設定の仕方がおかしかったところで大分時間を食ってしまいました...
local環境も定期的にメンテしておかないと行けないなーと反省しました。

以下 fishの設定

# go
set -x GOROOT /usr/local/opt/go/libexec
set -x GOPATH $HOME/.go
set -x PATH $GOPATH/bin $GOROOT/bin $PATH

「Vueの学習を始めたぞ」の巻

大したこと書いてません。 Vue を覚えないとそろそろいけないので触りからはじめました。

手順

環境

go + vue.js
※ 静的なファイルをサーブできればなんでもいいのでgoじゃなくてもいいと思います。

環境用意

goの環境用意

mkdir todo; and mkdir todo/src; and mkdir todo/src/todo
cd todo; and touch .envrc

emacs .envrc
export GOPATH=$(pwd)

direnv allow
direnv: loading .envrc
direnv: export ~GOPATH

cd todo/src/todo
dep init
touch main.go

とりあえずざっくりこんな感じでgoの動く環境を用意します。

ディレクトリ構成
todos
  /src
    /todo
        main.gp
        handler/main.gp
  /tmpl
    /layout
      index.tmpl 

静的ファイルを表示させる

Vueを書いていくHTMLファイルを用意します。

index.tmpl

<!DOCTYPE HTML>
<html>
<body>
<div id="app">
    <p>This is sample Vue app</p>
</div>
<script src="https://unpkg.com/vue"></script>
</body>
</html>

とりあえず簡単なvueの動作確認だけしたいので、CDNからDLするようにします。(ビルド周りとか、*.vueファイル使うのはまた次回)

Vueでコードを書く

イベントを作成する

イベントを作成します。 カウントアップするだけのコードを書きます。

new Vue({
    // describe options
    el: '#app',
    data: {
        count:0,
    },
    methods: {
        countUp: function () {
            this.count++
        }
    }
})

イベントリスナーを登録する

methods に記載した countUp をclickイベントに登録します。登録の仕方は以下の2つの記法があります。

<button v-on:click="countUp">countUp</button>
<button @click="countUp">countUp</button>

@ が省略記法らしい。この辺どちらを使うのがVueっぽいのだろうか...

双方向データバインディングを書く

<div id="app">
  <input type="text" v-model="text">
  <p v-html="text"></p>
</div>
new Vue({
    // describe options
    el: '#app',
    data: {
        text:""
    },
    methods: {
        // 何も書かなくていい
    }
})

(これだけで最小限の双方向データバインディング書けるの結構感動しました。ロジックに何も書いてない...)

textareaを使用した場合は改行た適切に反映されないので出力側のスタイルを調整します。 cf. フォーム入力バインディング — Vue.js - 複数行テキスト

その他、フォーム入力バインディング — Vue.js - 基本的な使い方 に各種要素の使い方が記載せれてますが、 methods にロジックを追加せずとも双方向データバインディングできるのはマジで便利。

コンポーネントを作る

Vueでは機能ごとのコンポーネントを作成してそれを組み合わせることによって画面を組みたてることができるので、そのパーツを作ってみました。

以下のように Vueインスタンスの内部でコンポーネントを追加します。

new Vue({
    // describe options
    el: '#app',
},
// componentを作成
Vue.component('item', {
    template: '<div><span v-html="content"></span> world</div>',
    props: ['content']
}))

※ #appにVueがマウントされている必要があります。

props

テンプレに値を渡すときには props を使います。 props にproperty名を指定しておくと、それをテンプレートにbindしてくれます。

API経由で取得した値なんかを props を使ってbindしておくとかに使えそうだなっと思いました。

まとめ

関わっているプロジェクトでも使っているのでVueの触りを学習し直してみましたが、ドキュメントの豊富と記法の容易さというのは非常に良い点だと思いました。
正直触りしかやってませんし、コンポーネントの考え方とvuexまで追いつかないといけないのでこれからですが、jqueryを脱CDN経由で入れれば実行環境問わないし、単純なプロジェクトで考えればこれでいいのではとも思ってます。
ライフサイクルも単純なのでマウント以前にAPI通信をするなど、各Vueのライフサイクルでやることをはっきりさせることができそうだなという印象も持っています。

もう少し色々触ってみたいと思います。

コードはこちら

github.com

【Go】WebサーバーでLogを表示する

やりたいこと

Goで立てた簡易webサーバーにアクセスした時に標準出力でLogを表示させるようにします。

webサーバーを立てる

/src/todo
  main.gp
  handler/main.gp

main.go

package main

import (
    "fmt"
    "net/http"

    "todos/handler"
)

var addr =  ":3000"

func main() {
    router := http.NewServeMux()
    router.HandleFunc("/", handler.Index)
    fmt.Printf("[START] server. port: %s\n", addr)
    if err := http.ListenAndServe(addr, router); err != nil {
        panic(fmt.Errorf("[FAILED] start sever. err: %v", err))
    }
}

handler/main.go

package handler

import "net/http"

func Index(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello"))
}

ただし、このWeb Serverを起動(go run main.go)して、 http://localhost:3000 にアクセスしてもターミナル上で標準出力でありがちなリクエストログはされません。

go run main.go
[START] server. port: :3000
# ここに標準出力でリクエストをログを表示させたい。

ログを表示させる

ログを表示させるには、Log用のhandlerを用意して、Listenする時にそのログを出力するhandlerを通るように登録します。。 cf. Google グループ - Http Server and logging?

handler/log.go

package handler

import (
    "fmt"
    "net/http"
)

func Log(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        rAddr := r.RemoteAddr
        method := r.Method
        path := r.URL.Path
        fmt.Printf("Remote: %s [%s] %s", rAddr, method, path)
        h.ServeHTTP(w, r)
    })
}

main.goを以下の用に修正します。

if err := http.ListenAndServe(addr, handler.Log(router)); err != nil {
  panic(fmt.Errorf("[FAILED] start sever. err: %v", err))
}

ポイントはLogのhandlerの登録の仕方です。 Log出力用のhandlerを登録する場合は http.ListenAndServe(addr, hanlder) のhandlerの引数にrouterを単にrouterを追加すればいいのですが、以下のように middleware的な handlerの登録の記法が使えます。

func SomeMethod(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
}

return で返す http.HandlerFunc method内部でリクエスト毎に行いことをつらつら書いていけばなんでもできます。

まとめ

FWとか使っていると、この辺いつもFWが吸収してくれててブラックボックス化されてたんだなと痛感しました。
そういったところ、FW側でどう動いているのかわからずに使っていることが多かったので、どんな言語でも簡易的でいいので一旦web server作ってみるというのは学習としてはいい「車輪の再発明」だと思いました。

Vue.js書くのに役に立ちそうなリンクまとめ

vue書くのに役に立ちそうなリンクを備忘録でまとめます。

Links

少しずつここを更新してく(予定)

『エンジニアリング組織論への招待』を読んだ

話題の『エンジニアリング組織論への招待~不確実性に向き合う思考と組織のリファクタリング』をGWに読みましたので感想をまとめてみます。

感想

話題になっている書籍は読んでみるタイプでざっと通読したあと気になるところを二度読みました。
個人的な感想としては、かなり「確かに」とか「わかるわかる」と何度も頷きながら読み進めてましたし、普段の仕事をしている中で感じていた課題感をうまく解説してくれている書籍で、読んでてすっと内容が頭に入ってくる良い書籍でした。

章立て

内容は実際に書籍を読んでみて欲しいのですが、章立てが以下のようになっています。

  1. 思考のリファクタリング
  2. メンタリングの技術
  3. アジャイルなチームの原理
  4. 学習するチームと不確実性のマネジメント
  5. 技術組織の力学とアーキテクチャ

この中で個人的に印象に残っていたのは1章の内容です。1章でも本当に最初の方で本書を読むに当たっての頭の整理の内容が自分の中では強く頭に残っています。

印象的だった内容

第一章から「リファクタリング」という言葉が使われているとおり

頭の中で発生してしまう無駄なプロセスを削除して、考えるときの指針をもつことで、問題解決に向かって明確に行動出来るように促すもの

と章の頭で説明しています。

この書籍を読んだからと行って、「問題解決能力が爆発的に上がる」とか「不確実性に対する有効なソリューションを得た」ということはありませんが、NEXT ACTIONを明確にできる、というは確かにあると思います。

そもそも、この書籍を読むまで普段の業務中で「あれ?なんかうまく進まないな?」っという漠然とした感覚が湧いてくるし、そういうのが蓄積されると、テンパって思考が停止してしまうことが自分はよくありました。ただ、それがどういう原因なのか、考えてもうまく言語化出来ないことがあったのですが、それが 不確実なものを潰してない、そもそも何が不確実なものかがわかってない し、その 不確実なものと向き合ってない ことって結構多かったなと気づきました。

1章で最初の方で語られている内容は以下の三点が中心です。

  • 論理的思考の盲点
  • 経験主義と仮説思考
  • システム思考

この中で 論理的思考の盲点 については個人的にも共感するところが大きかったです。
何より納得感が大きかったのが、論理的思考って基本的にもてはやされる類のものであるんですが、本書では

他人が介在する問題について、私たちは感情的にならざる得ない生き物

というように、人間が他社とコミュニケーションを取る際にベースが論理的でないということを先に言ってしまっています。その上で

  • 共同作業を行う上で無意識的に感情的になってしまうこと
  • 複数人で問題解決の仕事を行う上で、コミュニケーションの失敗が生まれること
  • ここでの失敗とは
    • 「私はあなたではない」という単純なことを忘れる
    • 自分の事情が全て相手に伝わっているのだという勘違い

を指摘しています。

論理的思考は重要な能力ですが、コミュニケーションの失敗によって、制限されたり、自分の正解は相手にとっての正解でないという前提を忘れてしまうと、途端に論理的なコミュニケーションは破綻する、というそもそものスタート地点を理解しておくって他人と仕事上のコミュニケーションをする上で大事だと思います。

もう一つ、1章で印象に残ったことが 「アンガーマネジメント」 です。

僕は他人に対してアンガーを抱いたことはほぼありません(怒られたことは数知れず...(笑))
そもそも怒るのが苦手、というもありますし、沸点が上がりにくいという性格が起因しているような気もしています。

ただ、もし自分が他者の所為に対して、何か指摘しないといけない、場合によっては叱った上で、うまくコミュニケーションを取って、改善につなげてほしいというときが来た時にどう伝えるのがいいのかわからないなと思っていたんですが、本書に1つの手法としてあった以下の内容は「確かに!」と思わされました。

「怒り」を「悲しみ」として伝える

これはかなり目からウロコでした。自分も怒りをぶつけられるとどうしても自己防衛本能が働いてしまい、相手の意見を素直に受け入れることができないことがたまにありますが、「〇〇をわかってくれなくて(自分が大事にしている価値観がぞんざいに扱われて)悲しい」と、相手の価値観と怒った(悲しみの)原因もセットでコンテキストとして伝えられると、相手を理解できなかった自分に否があると自責で考えることが出来るようになると思います。
(あくまで個人の主観です。)

怒りと悲しみって対極にある感情だと思うんですが、真逆であるということで、相手にとっては怒られると思っていたのに、何故か悲しみ(悔しさ、無念さもあると更に有効?)を伝えられると、そもそもガードが緩んで、何故怒っているのか(悲しんでいるのか)の原因がすっと届くのでは、という仮説は確かに確度が高いように感じますし、自分事で考えてみてもそうだと思います。

当分今の自分のおかれている状況で、他人を怒るなんてことはないと思いますが、1つの手法として覚えておこうと思えるくらいいい内容でした。

まとめ

感想にも記載しましたが、エンジニアとして働いている中で日々疑問に感じていたり、うまくいかないなーって思っていたことをうまく言い得ていて、とても納得感をもって読み進められる書籍でした。
エンジニアだけでなく、エンジニアと業務で関わる方はきっと面白く読めると思います。
また、これから働くというより、ある程度業務をこなしてからの方が頭に入ってきやすいように感じました。
やらないとわからないことはある と考えるタイプなので、エンジニアってこういう生き物、コミュニケーションにはこういう齟齬が生じる、様々な不確実性と日々戦わなければならない、というのはある程度経験(少なくとも1年くらい)してみないと実感として湧いてこないものだと思っています。

プロマネの友人にも薦めましたし、非エンジニアの方である程度業務をこなしたことがある方であれば3->4->1->2->5という風に読み進めるのがいいのでは?と思います。
理由は具体的な手法やユースケースを理解した上で、その大本の議論を見ると良いと思ったからです。
5章を最後に置いたのは、エンジニア的な内容が多かったので5は非エンジニアの方が読むと難しいのでは?と思ったからですが、普通に読めるとも思います。

久しぶりに頭の中が整理されたと実感できるいい本に出会いました。

『教養としてのテクノロジー』 を読んだ

『教養としてのテクノロジーーAI、仮想通貨、ブロックチェーン』を読みました。

GWに帰省するときの下りの新幹線での時間潰しに読んだんですが、去年辺りから話題になりつつあるワードの大枠を理解するには良い書籍だと思いました。

章立てとしては前半のテクノロジーの概略を俯瞰しつつ、後半の「教育」「人間」「日本人」についての議論を展開していて、個人的には後半の方が楽しめました。

トレンドワードを使ったビジネスモデルやサービスを目にするたびに、それらは 手段であって目的じゃない ということをいつも感じます。

ブロックチェーンにしろAIにしろ、それらは「何かの目的を達成するために使うもの」でしかないと思っているので、そもそも使ったことでどう変わるんだっけ?ということや、自分たちは何がしたくて、それらのツールを使用するのか?といったことを大本におかないと行けないなーと。

ちなみに、目次だけですが、両親が目を通していて、親世代もニュースや新聞でよく目にするワードだから興味はあるんだなーということが結構新鮮に感じました。

ポインタ型のvarでの初期化でハマった話

ハマったところ

CLIで特定の画像をbinary化してから画像にしてPostで送信する、というコードを書こうと思った時にポインタ型の初期化についてハマったのでメモ。

ざっくり書きたかったコードは以下(※ コードは適当)

func UploadImgFile() error {
  // 画像を開く
  f, _ := os.Open("imagePath")
  
  // form-dataを入れるバイナリを箱を用意
  buf := new(bytes.Buffer)
  
  // 箱は multipart型にする
  w := multipart.NewWriter(buf)
  
  // form-dataを作成する
  ff, _ := w.CreateFormFile("filedName", "test.png")
  
  // io.Copyでform-dataにOpenで取得した画像を書き込む
  if _ , err := io.Copy(ff, f); err != nil {
    panic(err)
  }
  w.Close()
  
  // upload処理hogehoge
  client := http.Client{}
  req, _ := http.NewRequest("POST", "Upload先のURL", buf)
  resp, _ := client.Do(req)
}

cf. multipart - The Go Programming Language

こういった処理を書こうと思った時の以下の箇所

// form-dataを入れるバイナリを箱を用意
buf := new(bytes.Buffer)

// 箱は multipart型にする
w := multipart.NewWriter(buf)

ここでのbytes.Bufferの初期化方法についてハマりました。

multipart型でWriterを初期化可能なパターン > The Go Playground

Writer初期化時点でpanicが起きるパターン > The Go Playground

panicになってしまうかどうかはぬるぽを踏んでしまうかどうか、という1点に尽きるのですが、panicになるケースにおいては ポインタ型の変数領域だけ宣言しても、初期値のままなんでゼロ値でポインタ型なのでnilになる

panicにならないケースについては newで領域確保してそのポインタを返しているのでnilでないのでうまくいく

multipart - The Go Programming Language

を見ると引数に指定するのは io.Writer 。しかし、io.Writer が実装されているのはポインタ型に対してなので、引数に渡すべき butes.Buffer はポインタ型でなければなりません。
cf. src/bytes/buffer.go - The Go Programming Language

そのため、varで単に初期化した場合でもアドレス型にして渡してあげればコンパイルエラーは起きず、処理を続けることが可能です。> The Go Playground

まとめ

golangのvarによる初期化についてはたまに思いっきりはまってしまうことが多いのでdocument読み返しながら進めないと思わぬ所で時間を食ってしまうなー。