emahiro/b.log

Drastically Repeat Yourself !!!!

Kyash meetup #2 Server Sideに参加してきた。

※ 公開していいところをザクッとメモった備忘録です。

Date/Place

2018/07/31@Kyash

kyash.connpass.com

開発環境をDockernizeした話

技術スタック

  • ServerSede:go
  • MicroService
  • AWS

開発環境の構築手順書

  • 手順書が実際の状況とsyncしていない。
  • AWSは編集後自動でバイナリにしてほしい。
    • GAEとかはできるけどAWSはできない。

Dokcerの構造

  • 各コンテナにIPを割り振っている。
  • DBにアクセスするときはIP制限をかけている。

Realize

Docker化してよかったこと

  • 構成管理をコード化
  • コマンド一発ですべての環境が立ち上がる。
  • Imageの共有

今後やりたいこと

  • AWSに直でアクセスしている箇所とかDocker化したい。
  • データ入りのDB Imageを提供できるにしていきたい。(一部なっている)

Kyashのシステム全容

Kyashはクレジットカードのissuer(発行者)でもある。 オーソリングとかクリアリングの業務について説明してもらった上で、

実際のシステム全容

  • WebAPI
  • フロントエンドプロセッサ(クレカ決済周り)-> ここ、HTTPじゃなくて独自のTCP喋っているらしく、ゴリゴリに実装しているらしいです。
    • VISA
    • QuickPay

が前段にいて、後ろにMicroservice群がいる。

決済、送金時自動チャージ

※ ここは非公開でした。

パネルディスカッション

※ 全部は載せてません。(追いきれなかったり、非公開情報もあり)

テストについて - 外部環境とのやりとり。 - 基本はmock。 - 外部とは繋がない。

  • リリース頻度とか?

    • 決められたリリースは2週間に一回。
    • サーバーサイド周りはサクサクリリースしてる。
  • 運用面

    • お問い合わせとか丁寧に応えるよね。
  • 負荷面

    • サーバー側はGoで書いてるのであんまり負荷という面はない。
    • DB側の最適化が足りてなかった。
  • APIドキュメントの運用は?

    • いい感じで運用はできてない。
    • 今はmarkdownAPIで管理している。
    • クライアント側はViewに集中している。
    • API部分はアプリエンジニアも書いていった方がいい?
      • アプリエンジニアもAPIのサービスを書いていったりもしている。
  • GoのFWは?

    • ginとかechoとか。
    • 標準のnet/httpを使ってるケースが多い。
    • GRPCに寄せていってる最中。
  • PosgreSQLの理由

    • 歴史的経緯
  • 新しくしたい部分とか?

    • GRPC化はしていきたい。
    • APIDocsもprotoファイルが大体できるし。
  • マイクロサービスの辛かったところ

    • マイクロサービスの切り方を変えようとしても、既存のアセットがガツガツ変わっていくので、結局マージできなかった...
  • APIは公開しないのか?

    • API公開は一プロダクトを出すのに等しい
      • ドキュメント
      • フォーラム

その他

お寿司美味しかったです。 オフィス見学させてもらえました。ルンバが掃除してて可愛かったです。。

社内のホワイトボードのクレジットカードのビジネスモデル全般からKyashのビジネスモデルをPMの方に俯瞰して説明してもらえました。
この領域、色んなプレーヤーが出揃いつつあるけど、みんなそれぞれ解釈を持ってキャッシュレスの世界に貢献していてとてもいい印象を受けました。

感想

とにかく少人数で回している事実がすごかったです。 そして結構公開ギリギリにことも話してくれたり、普段自分の使っているサービスの裏側を知るのはやはり面白いですね。

それにしてもクレジットカードビジネスの仕組み理解してなくて、ここを共通の業務知識として知った上で開発していることは本当にすごいと思いました。

そして最後にこれからもKyashをガンガン使っていこうと思いました。

kyash.co

localでのgoの管理においてbrewをやめた話

Overview

goのversionを複数使いたいケースにおいて brewを使ってしまうと常に最新のgoのversionになってしまいます。
複数versionを管理するために goenv もありますが、高々goのversion管理のためだけに新しいツールを入れたりすると無駄な依存を発生させてしまい、環境が壊れることもあります。 そこで最も簡単にgoのversionを複数管理するためには、そういったツールから脱却して直でGOROOTを書き換えながら対応するのが一番楽だと気づきました。

github.com

やりたいこと

  • 複数のgoのversionを扱いたい
  • goenvみたいな余計なツールを使わずにシンプルに管理したい
    • 余計なツールを入れると依存関係だったりversion違いで死ぬみたいなことが起こって原因特定しづらいから

手順

  • goをversionごとに管理する専用のディレクトリを作成する。
  • wgetでsrc(https://golang.org/dl/) からgoの欲しいversionをDownloadする。
    • macを使っている場合は goX.XX.darwin-amd64.tar.gz という darwin-amd64 とついているversionをDLしてきます。
  • 使いたいgoのversionをGOROOTに指定します。
  • 他のversionを使いたい時はshellの設定ファイル(zshrcやfish.config)でGOROOTを切り替えてpathを通し直せば簡単にversionを切りかえることは可能です。
$ wget https://dl.google.com/go/goX.XX.darwin-amd64.tar.gz
$ tar -C /usr/local -xzf goX.XX.darwin-amd64.tar.gz
# goというディレクトリ名になるのでversionがわかるように修正する
$ mv go goX.XX

ref: https://golang.org/doc/install#installLinux のタブ参照

fishでの管理の仕方

config.shのGOROOTの設定箇所は以下。

# go
set GOROOT_PATH $HOME/.goroots/goX.XX.X
set -x PATH $GOROOT_PATH/bin $PATH
set -x GOROOT $GOROOT_PATH
set -x GOPATH $HOME/.go
set -x PATH $GOPATH/bin $GOROOT/bin $PATH

これをそのまま反映することで使いたいGoのversionにpathが通ります。

cf. https://medium.com/@vCabbage/go-installing-multiple-go-versions-from-source-db5573067c

今の部署に移動して1年経った

去年の今頃諸々あって転籍してきてからちょうど今週で1年と1ヶ月経ったので、この1年を振り返ってみます。

Overview

まずはよく1年乗り切ったと思うし、その事実については自分を褒めたい。 正直大変なことたくさんあったし、エンジニアとしての自分自身の経験不足を痛感し続けた1年でした。

大まかに以下の観点について振り返って見ようと思います。

  • エンジニアリングについて
  • キャリアについて
  • 今後について

エンジニアリングについて

Go

Goを1年間触れてきました。個人としては歴が2番目に長いソフトウェアになりました。(ちなみに1番書いていたのはPHPで大体2年くらい書いてました。)

blogのエントリの傾向見るとわかりますが、Goに触れたことでGoが大好きになりました。これは今の部署で1年過ごしたことで得た嬉しいことの一つです。趣味プロですらサーバーサイド書こうと思ったらいつもGo選んでます。最近はNodeやKotlinにもちょっと興味あります。

GAE

これも僕の中では一つの革命的なサービスでした。今となってはAWSと対をなす標準的なPaaSですが、GCPの中でもとりわけGAEを1年間触れてきたことでPaasへの理解が一歩前に進んだ気がします。

異動して当初は全く何がなんだかわからなかったですが、最近になってようやく周辺サービスを使うようになってちゃんとdocumentをベースで知見を広げて開発を進めていくというPaaSならではの開発の仕方に少し馴染めてきました。

マイクロサービス

今関わっているプロダクトはマイクロサービスアーキテクチャを採用しています。

モノリシックなサービスしか関わってこなかったので、マイクロサービスをどう運用するのか、これを採用することでどういう嬉しいことがあるのか、一方でどういうしんどいことがあるのか、色々見ることができています。

個人的には下記のドキュメンテーションとも関係するのですが、マイクロサービスをマイクロサービスとして機能させるためにはある意味力技でマイクロサービスとしてしっかり保つことが必要であるということを知ることができました。

運用周り

ドキュメンテーション

wiki力が上がりました。キャリアの中でドキュメントをちゃんと書いたことなんかありませんでしたし、UMLとかも書いたことがありませんでした。これを続けた結果、頭の中身を文章に起こすスキルも少しだけ向上しました。

あまりにも移動当初wiki力がなさすぎて、これはいかんと思い、wiki力を伸ばす一環でブログをちゃんと書き始めました。結果としてなんだかんだ100記事以上書くことができて、ある程度は継続させることができています。
副次的には、ブログ書いてて声かけてもらうときに「ブログ見ました」みたいなことを言われる機会が増えたので文章にまとめる姿勢をもったことでいいことが少なからずありました。

チーム開発

githubを使ったチーム開発自体ははじめての経験ではなかったのですが、そもそも「何故そのコードを書くのか?」ということをずっと意識してきた一年でした。作ること、動かすことが目的になっていた自分からほんの少しは進歩したのかなと思います。

PRのディスクリプションちゃんと書くようにしたりとか、最近は指摘されてコミットメッセージの粒度や内容ちゃんと考えるようになったりとか、自分感覚でコミットしていた頃とはまたずいぶん様変わりしたなと実感します。

なお、その分開発速度という面ではかなり犠牲になりました。
ただ、あれほど重視していたスピードってなんだ?品質落としてまで重要視するものか?みたいな新しい見方をできるようになったと思います。

コミュニケーション

しゃべるのは好きだけど、仕事でしっかり議論するということはあんまりしてなかったし、相手に自分自身の意図を伝えきるということが如何に難しいか、そんな当たり前のことを課題に感じてました。

ただ、この根本は自分が相手の意見を鵜呑みにして、脳死状態に陥って事が原因でした。結局のところ、自分の経験不足を逃げ場にして、相手の言うことを聞いてればいいと思っていたことが全ての元凶でこれを改めるところからが自分のスタートでした。

エンジニアがエンジニアに説明するときですら、苦労するんだから、非エンジニアの人がエンジニアとコミュニケーション取るなんてマジで大変だろうなと思います。

開発における基本的なあれこれ

一人で開発していた頃と違ってバックグラウンドが様々なエンジニアの方々と仕事をすることが増え、それこそコードをレビューしてもらう中で様々なことを学びました。実装におけるtipsなどの比較的具体的なところから、ログの出し方や検証観点、検証の仕方、QAの意義など小さいところでとにかく作ることが優先されていた頃には意識すらしなかったことを多く学びました。

キャリアについて

課題

やはり 引き出しの少なさ に集約されるかなと感じます。 エンジニアとしての経験の少なさがそのまま、自信のなさだったり、逃げだったり、実際の開発における能力不足に直結している気がします。 この辺はもう経験で補うしかないのかなと思いつつ、どうしたらもっと伸ばせるのか、少なくとも自信を持って開発に望めるのか、その辺をもっと突き詰めていかないとなーとも思っています。

優秀な同世代のみなさま

新卒の方もめちゃめちゃ優秀だし、同僚の方も百戦錬磨のエンジニアの方達ばかりで常に劣等感を感じながら仕事しているということそれ自体はあまり変わっていないと思います。 ただ、ふと思うのはこれだけ優秀な人に囲まれて仕事できる機会もキャリアを通してそう多くないと感じているのでとにかく学べるだけ学んでやろう、という気持ちは変わりないです。

今後について

よくわからない、というのが本音だったりします。
おそらく1年前の自分では思いもしなかったことを色々と学んでいった中で、実際いまの自分って「何がしたいんだっけ?」っていう課題にぶち当たっています。
実際、昔は作りたいものとかがたくさんあった気もしているのですが最近はその辺が全く見えなくなって来ました。正確には、足りないものがありすぎで、作りたいもの作る前にちゃんと自分自身の現状の能力と向き合って、伸ばしていかないと 本当の意味で作りたいものは作れないんじゃないか? という危機感が大きくなって来たというのが本音です。

この危機感はおそらく消えることはないんでしょうが、少しでも払拭できたといえるタイミングでまた次のことを考えようかなーくらいの感じでしばらくはやっていこうかなと思っています。

【雑記】改善の難しさについて

コードの改善、という作業をここ数日ちゃんと向き合った中で気づいたことをまとめてみる。

Overview

あるモデルレイヤーでユースケースごとに無限にメソッドが増えていきそうなポイントをある程度柔軟にパラメータでユースケースを指定して処理を共通化し、コードの見通しを良くする作業です。 該当のコードは僕が現在の案件にジョインしてからも歴史的な経緯を優先してユースケースごとに(同じようなコードが微妙に異なって書かれている)メソッドを追加することで要件の実現を図ってきた箇所であるが、あるユースケースを実現するときに流石にそろそろ限界では?と僕自身が常々感じていたことを改善するために時間を取ってコードの改善を行いました。

パラメータを柔軟に出し入れするために functional options pattern を使ってみたりいろんなコード書きながら、都度方針を説明して、レビューしてもらってあれこれやりくりした結果、ユースケースごとの責務は一つ下のレイヤー(apiとの接合部分)で負わせることにしてモデルレイヤーではユースケースのみを指定するという方針でコードを書き直しました。
※ もっとキレイにリファクタリングできるとbestだったんですが、色々な制約のもとで場所を移す、という方針になりました。(まぁありがちですが)

結果 モデルに露出していた複雑性は一つ下の階層に移動したので、モデル自体はある程度わかりやすくなりました。

わかったこと

以下の2点を痛感しました。

  • ある時点で動いているコードの改善は難しい
  • 非機能要件を求めるには基礎が必要

ある時点で動いているコードの改善は難しい

コードが動いている という状態はそれ自体に価値があり、それを改善という大義名分のもとにいじることは、いらぬバグを混入する可能性もあり、既存の挙動を保証しないということにも繋がるので、慎重さが求められます。
また、歴史的な経緯があって、 今時点の状態 が作られている、という事実もあるので、その歴史的な経緯を理解した上で、改善の内容を定義(何をもって改善とするのか) して レビューを受ける 必要があります。

つまり、普通に考えれば 超めんどくさい 作業です。しないほうがさっさと次の作業に進めますし、問題を未来に先送りすることそれ自体は悪いことではないと思います。

非機能要件を求めるには基礎が必要

同僚のエンジニアの皆様にも助けてもらいながら、時間はかかったものの、ある程度ステークホルダーが納得する形で改善することができましたが、その議論を進めていく中で自分には 基礎がない ことを痛感しました。

リファクタリング、コードの改善なんていうものは言ってしまえは 非機能要件 であり エンドユーザーにはそれ自体は一切メリットがない ことです。やらなくたってサービスにすぐに悪影響があるわけではありません。(すぐにと言ったのは長期的には悪影響があるからです。ex. 拡張性のなさとかメンテナンス性の低下とか)

実装パターンだったり、設計パターンだったり、そもそもの設計の知識やノウハウが不足していて、議論を追っかけるのが精一杯だったり、僕の見えてなかったところをガンガンfeedbackもらったり、その結果思ったより時間がかかって心折れそうになったり、とまぁこういったことがあって、そこそこ大変だったわけです。

エンジニアとして 機能要件を満たすこと はさほど難しいことではないけれど、一度非機能要件にこだわると基礎が必要になるということを実感しました。

cf. エンジニアになる覚悟 - Speaker Deck
上記のスライドがすごく勉強になります。

このケース以外にもいろんなケースで非機能要件を追求するには、基礎が必要な場面があると思います。

改善しようと思った理由

思ったより大変だったことに対して、避けることもできたんですが、なんでやろうと思ったかと言うと 将来の自分が絶対に今の自分を恨むだろうなー と思ったからです。

改善したかった箇所は僕もずっと触れてる中で「なんで同じような実装があるメソッドが大量にあるねん、ユースケースごとに分けてもいいけど中の実装は共通化しろや」って割と温度感高めに感じていた箇所でもありました。
今まで自分が書いてきた箇所も、ある程度違和感は感じつつ、それに蓋をして、目の前の案件を仕事を進めるためにコードの綺麗さを犠牲にしてきたのも事実です。

今回もそうすることもできましたが、別案件で、今までに想定してなかったユースケースを提示されて、流石にこれを実現するにはまたメソッドと実装を増やすしかないなと感じて、改めてコードを目の当たりにしたときに「これ以上増やしては行けない」という思いがふつふつと湧いてきたし、まだ案件に入っていなかったので、リファクタリングの時間を取るなら今しかないと思って「えいや」で進めました。

違和感で立ち止まる勇気

進めるにあたっての課題感は前述したとおりで、自分には基礎がなかったので、リファクタリングを始める時点でどういう形が最終的にいいのかはイメージしきれていませんでした。

そもそも何がイケててイケてないのか、ということもまだまだわからないことが多いです。でもその中でも、日々コードを書いている中で 違和感 を感じることはできます。
※ ex) なんか同じコード多いなー、とかそういうやつ

エンジニアがコード書いてるときに違和感を感じたときは、多分何かがおかしい(責務とか、設計とか)ことが多いです。
その何かが具体化できなくても、違和感に蓋をせずに一度立ち止まって何がおかしいのか考えてみることは大事です。もしわからなければ有識者に違和感をそのまま伝えてみるのもいいかと思います。
過去の歴史的経緯を知ることで、違和感の正体を具体化し、必要なことが見えてきます。

立ち止まってリファクタリングすることまでできたら最高ですが、違和感を放置せずに、正体を知る努力をするだけでもコードへの理解は一段進むかも知れません。(ほぼ自戒)

仕事を進めることはもちろん大事です。ただ、なにか違和感を感じたときに、仕事の手を止めて考える時間を取るには勇気がいります。
手を止めて改善策を考えた結果、もっと大変になりそう、、、という未来が見えることがあるかも知れません。その結果仕事を進めてるほうが楽だから、とりあえず臭いものには蓋をしておこうと思っても不思議はありません。

でもあえて手を止めて一度考えてみるという機会を設けてみることで、今のコードに対する見方が変わるかも知れません。

安易に安い解決策を求めた結果あとで苦労する or 恨まれるくらいなら今時間とっても大した事はありません。

まとめ

せっかく買ってあったのに積読状態だったからこれ読もう

Gitでよく使うコマンド・設定 ※随時更新

なんとなく使っていたgitコマンドたちを最近commitやmergeをする前に意図を持って使うようになったのでよく使ってるコマンドを整理しました。
※ ちょくちょく更新していきます。

Commands

remoteのmasterを取ってくる時

作業ブランチからmasterにcheckoutして最新の状態に戻すときに、追跡されてないファイルとかを削除してブランチの状態をきれいにしてからmergeします。

追跡されてないファイルを確認する

git clean -n

追跡されてないファイルを削除する

git clean -f

追跡されてないファイルとディレクトリを削除する

git clean -fd

これをするとvendorディレクトリなどの依存ライブラリを管理しているディレクトリも削除してしまうので、改めて入れ直す必要があります。

pullする

癖でmaster出し git pull をいつも使ってましたが、最近は予め fetch origin master してから merge origin master するようにしてます。

remoteのmasterの状態とlocalのmasterの状態が異なってしまうときにどのファイルでコンフリクトが起きそうなのかを予めlocalにmergeする前にわかっておくと、誰がいつなんで変更したファイルなのかを知ることができます。
resolve conflict というcommitメッセージを極力残さないように注意するようになりました。

remoteにpushするとき

差分を確認する

コードを変更したらまず意図した差分かを確認します。

git diff

これだけでHEADの状態とlocalの作業ブランチの状態を比較します。

ただ、具体的なコードレベルの差分よりも、commit前になったら差分があるファイル一覧だけ欲しい時があります。

git diff --name-status HEAD

これで差分があるファイル一覧を確認します。

新規ファイルを作成したりしたときは

git status

で意図したファイルが作成されているかをcommit前にかならず確認します。

indexに登録する

手癖で git add . を使って一括でHEADに上げることをしていました。
ただ、これだとよくわからないファイルを上げてしまったり、予期してなかった変更を上げてしまうことが増えてしまって、レビュー時に指摘されてしまったりということが増えてきました。

そのため 一括で HEAD に登録する git add . をやめました。

commitするときは diff --name-status HEAD を確認したファイルをindex登録します。 この時できるだけ細かい粒度でaddするようにはしています。 ※ めんどくさいと git add -A でaddすることもあります、

最近知ったんですが、 -p オプションなるものがあるらしく対話形式で厳密にファイルを index に登録していくことができるらしいです。

git add -p .
# diffが表示
Stage this hunk [y,n,q,a,d,e,?]?
# yを選ぶと index に登録される。

a を選ぶと残りを全てindexに登録してくれます。

再度差分を確認する。

add し終えたら再度差分を確認します。

git diff --cached

commitする

commitメッセージ注意するくらいかな。最近はGUIでsquash and mergeすることが増えてきたのでとりあえず適当に書いておいてあとで直せばいいや、くらいのノリでいますが。

add + commitを一度に行う

git commit -A

commit メッセージを書くときにどのファイルがindexに登録されているかもすぐに分かって良さみがある。最近一番良く使う。

既存の変更されたファイルのみ add する。

git add -u

新規で作成されたファイルは含まないので ignore 忘れの vendor などを間違って commit するのを防止できる。

git subtree コマンドで外部リポジトリを取りこむ

ema-hiro.hatenablog.com

author を再設定する

PC を変更した場合に git の user.name や user.email を設定しないまま commit しちゃうと、以下のような「設定してね!」というメッセージが表示される。

You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"
    git config --global user.email you@example.com

このメッセージ表示後に commit した変更は上記の設定で追加したユーザー情報が利用されますが、設定する前の commit までは Unkown ユーザーになってしまう。
こういうケースでは git commit --amend --reset-author を使ってユーザー設定を再設定した後に commit を上書きする。

git コマンドにエイリアスを貼る

毎回 git checkout や git status を叩くのは面倒くさいので alias を貼って短縮化します。
設定は ~/.gitconfig に以下のディレクティブを追加して alias を貼りたいコマンドと正規の git コマンドを追加します。

# ~/.gitconfig

[alias]
    st = status -s
    df = diff
    b  = branch
    co = checkout

エイリアスは僕が普段使ってるものを追加してます。

コミットメッセージを編集する

直前のコミットメッセージを編集する

git commit --amend

2つ以上前のコミットメッセージを編集する

N個前のコミットメッセージを編集したいとします。

git rebase -i HEAD~N # コミットメッセージを編集したいコミットまで遡ります。
pick xxxxx // このコミットメッセージを変えたい時
pick yyyyy
pick zzzzz
edit xxxxx // edit に変更する
pick yyyyy
pick zzzzz

この状態で保存して git commit --amend を選択して該当コミットのコミットメッセージを変更する。その後は git rebase --continue を選択して rebase を完了させます。

goappコマンドを入れ直した話

Overview

GAEを使う場合、localにapp-engineのSDKを入れる必要があります。
少し前までは brew install app-engine-go-64 を叩くと goapp コマンドがlocalにinstallされ、使うことができましたが、ある時から formulla から消えてしまい、brew 経由でDLすることができなくなりました。最新のツールを使ってないと、新しくGCPで使える機能が使えなかったりするので最新の状態に保ちたいと思います。

brewで入れられなくなって以降、goapp コマンドは Google Cloud SDK 経由で入れるようになっています。

Google Cloud SDK経由で入れる

手順は以下の3つ

  1. Google Cloud SDK を入れる。
  2. AppEngineのSDKを入れる。
  3. Google Cloud SDK経由で入れたAppEngineのSDKにpathを通す。

以上です。

Google Cloud SDK を入れる。

※ GoのSDKを使います。

以下からinstallすると gcloud コマンドが使えるようになります。

https://cloud.google.com/appengine/docs/standard/go/download

AppEngineのSDKを入れる。

gcloud component install app-engine-go

※ 上記SE(Standard Environment)のinstall方法に記載してるとおりです。

ちなみにGCP関連の全てのSDKを突っ込む場合は

gcloud  components update

すると全て入ります。

Google Cloud SDK経由で入れたAppEngineのSDKにpathを通す。

Google Cloud SDK で入れたAppEngineのSDKにpathを通します。

Google Cloud SDKで入れたSDK郡が入っているpathは個々人の環境で差があると思います。
僕の場合は /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/platform/google_appengine にあります。

これをshellの設定ファイルにPATHとして登録します。自分はfishを使っているので以下のようになります。

set -x PATH /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/platform/google_appengine $PATH

最後に google_appengine 配下にあるコマンド郡の権限を設定します。

ex) appengineの場合goappコマンドに対して実行権限を付与します。

chmod -x /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/platform/google_appengine/goapp

デプロイする場合は appcfg.py に実行権限付与します。

これで最新のツールを揃えることができます。

goimportsでlocalのパッケージのsort順序を編集する。

-local付きでgoimportsする

goのformatとimportパッケージをよしなにしてくれる goimports コマンドですが、localで独自に定義したpackageをimportするときにこんな風に並んでほしいことが多いです。

import(
  // 標準pkg
  
  // github.comとか有名所pkg
  
  // localの独自pkg
)

goimportsは何も指定しないと https://github.com/golang/tools/blob/165bdd618e6d174c61ee7bd73a28f3e5c6fdced1/imports/fix.go#L44-L67 で示された順序で import の内部をsortします。

ここでは https://github.com/golang/tools/blob/165bdd618e6d174c61ee7bd73a28f3e5c6fdced1/imports/fix.go#L48 にあるようにlocalで定義されているpackageのPrefixを指定してあげます。

以下のようにして goimports を叩きます。

goimports -w -local "localのpackage名" foo.go

-w オプションはgoimportsをかけた出力結果でgoのファイルを上書きするオプションです。

注) importをsortするときは一度importの中から改行を消します。
どういうことかというと以下のような感じです。

import(
  "fmt"
  
  "bar"  
  
  "github.com/foo"

)

みたいに整列されているのを

import(
  "fmt" 
  "bar"  
  "github.com/foo"
)

こうして改行を削除して goimports をかけると

import(
  "fmt"
  
  "github.com/foo"
  
  "bar"  
)

こんな普通に意図した結果で sortされるはずです。
bar はlocalのカスタムpkg

なぜ改行を一度外すかと言うと、goimportsは改行があるとすでにgrouping済みと認識してしまい、意図したsortをしない可能性があるからです。

intellij(jetbrains系IDE)での設定

intellijでは以下のように設定するとうまくいきます。
Preference > Tools > ExternalTools > (+) でカスタムコマンド作成

以下のように設定します。この設定した External ToolsにKeymapでショートカットとか割り当てておけば、コード書き終わったあとにgoimportsをかけてソートします。

f:id:ema_hiro:20180608012237p:plain

Working Directory はこのコマンドが動作するディレクトリの範囲を決めることができます。

引数定義の中身は以下

f:id:ema_hiro:20180608012243p:plain

追記

Intellijでは Plugin から FIle Watchers をDLします。これでFileのSaveをHookして任意のスクリプトなり、actionを指定することができます。
上記の設定と同様の設定をFile Watchersに設定したので Cmd + S でFileを保存したときによしなに imports を聞かせることができるようになりました。

Vueのテンプレート構文のエンコードでハマる

<!DOCTYPE HTML>
<html lang="ja">
<head>
    <meta charset="utf-8"/>
</head>
<body>
<div id="app">
    <p>This is sample Vue app</p>
    <p>count: {{ count }}</p>
</div>
<script src="https://unpkg.com/vue"></script>
</body>
<script>
    new Vue({
        // describe options
        el: '#app',
        data: {
            count:0,
        },
        methods: {
            countUp: function () {
                this.count++
                console.log("count up")
            }
        }
    })
</script>
</html>

Mustache構文を使った時にブラウザで以下のようなエラーにぶち当たりました。

プレーンテキストドキュメントの文字エンコーディングが宣言されていません。ドキュメントに US ASCII 外の文字が含まれている場合、ブラウザーの設定によっては文字化けすることがあります。ファイルの文字エンコーディングは転送プロトコルで宣言されるか、文字エンコーディングを指定するバイトオーダーマークがファイルに使われている必要があります。

encoding文字しているのに指定しているのにブラウザ側で怒られました。(firefox ver60を使用)
XSS対策関連で怒られてるっぽいのでとりあえず、vue内で使うpropertyを指定できればいいので v-html を使って回避しました。

<p>count: <span v-html="count"></span></p>

テンプレート構文 — Vue.js

あたりを参考にするといいっぽい。vue始めたばかりでよくわかってないけど。

初めてハッカソンに参加してきた話

ハッカソンと呼ばれるもの参加してきたので反省をつらつらと。

内容

Event

先週の土日(5/26,27)にこちらのイベントに参加してきました。

connpass.com

Theme

仙台市の抱える課題をRESASやモバイル空間統計を使って、あぶり出して解決する

というものでした。

Output

地域課題に対するソリューションをKaggleみたいなコンペ形式で提出するプラットフォームを立ち上げるためのプラットフォームを作る。

というものを考えました。

反省

準備について

これは事前にチームが組めたわけではなかったので、環境を用意したりとか、エディターの設定等を事前にすり合わせることができず、全くできませんでした。

次回はGAE/Goである程度動く環境を作っておくとかしたいなと思います。
友達に聞いたら https://ngrok.com/ もいいよっていってました。要は手間をかけずにチーム開発できる準備というのは前もってしておかないと行けないなと思います。

また、準備については例えばCRUD的なアプリケーションについては、いくつか雛形作っておきたいなと思いました。というのも、大体何を開発するかと行ったときに、ベタなCRUDアプリケーションがシステムとしてはベースになると思っていて、それを今回準備できてなかったので、当日の作業の足かせになってしました。

Goで書いたroutingのみの簡単なAPIサーバーの雛形はいくつもあるんですが、そこで満足せず、ローカルのDBに接続するための設定ファイルのテンプレだったり、実際に動作するもの(できればbootstrapらへんでUIの雛形もあるもの)を用意しておくと今回みたいな事前準備ができない場合でも、当日すばやく開発にはいれるなーと実感しました。

当日について

当日のアウトラインは以下のとおりですね。

チームビルディングについて

個々人で企画検討、その後全員でそのアウトプットを見ながら自分がどの企画にJOINしたいかを決める、というものでした。

結果として僕の出した企画に4人集まっていただき、最終的に5人チームが発足しました。
ただし、エンジニアが僕一人しかいなかったので、もう一人くらいいると良かったなと思います。
とはいえ、ここについては運営の企画内容によるので仕方無い部分もあり、与えらた環境で最大限アウトプットを出す方向に切り替えました。

企画内容について

Themeに沿う形で、ある程度、実際のneedsに応えることのできるアウトプットになったのではないか?と思っています。

ただ、これにはすごい反省があって、現場のニーズに応えることに意識が行き過ぎてしまい、ハッカソンのゴール設定としてどうあるべきか というところの観点がすっぽり抜けてしまっていました。

課題解決策を考えているのは楽しいし、それが実際の課題とも紐付いていい感じにできそう、という思いはあったものの、ハッカソンとしてのゴールをどこにおくのか?
そこを考えずに企画を作ってしまい、そこはハッカソン勝ちに行く ということを考えたときにどうなのかな、、、とは感じました。

開発(実装)について

単なる掲示板、しかもデザインなしというものだったので正直、ベタなHTMLのページ作ってあとはプレゼンベースでストーリー補足!という方向にしました。 それ自体が悪かったアプローチではないなと思っていますが、ハッカソンらしい、「なにかを作る!」という点で考えるともっとできることあったなと感じました。

こういうときにデザイナーさんの凄さを実感しました。 採用言語については、普段使い慣れているGoを使いましたが、やーやはりこういうときにGoは向かないw 書く量が多くて、それは確かにいいけれど、railsにすればよかったと思いました。

チームにエンジニアが一人しかいなかったのでそもそも一日という時間で作れるものなんかほぼないと思って先に限界を決めてしまったのが敗因でした。

どんなときでも少しでも(見た目含めて)良くしようという気持ちだけはないと行けないなと実感。

とはいえ、プレゼンについてでも述べますが、企画内容をベースにプレゼンで頑張る、あくまで現実のニーズにフォーカスする、という方向で決めていたので、それ自体は今回の企画に対する自分のアプローチとしては間違ってなかったかなと思っています。

(実装は...頑張れ自分....)

プレゼンについて

普段コンサルをしている方がチームにいらっしゃって、すごい助かりました。

ある程度プレゼンのアウトラインを決めてから各自(自分以外)必要なデータ、エビデンスを揃えてアウトラインごとに作成、あとで間引く、というやり方で作りましたが、これは最初に企画の目的や世界観を共有していたために、思ったよりスライドをマージしたときに全体としてブレずにスムーズに進みました。

実際の発表でも時間ちょうどくらい(デモをするために端末切り替えにかかる時間除く)で終わって良いプレゼンになったと思います。
質疑応答にも自分的には割とスムーズに応えることができました。

このあたり、常々自分が疑問に思っていたことに対するソリューションベースで企画を考えていたために、普段から思考実験できてるし、っていうのもあってのことだったと思います。常日頃課題見つけて、考えていることは大事ですね。アウトプットできたらもっと素晴らしいんだろうと思いますがw

結果

審査員賞でした。

まとめ・感想

本企画、ハッカソンというよりはプロトまで作成するアイデアソンに近いと感じました。
ハッカソンっぽくはないなと思っていましたが、それでも最終的にダサい成果物でもちゃんとプレゼンと合わせて一つのものを出せたことは良かったです。

また、今回については自分の企画にチームが集まってくれたこともあり、少しPM的な立ち位置でチームをどう作るか、アイデアをどう具体化していくのか、というところにも少し足を踏み入れることができました。
これは僕の進め方もうまくはなかったですが、集まっていただいた方々がいい人ばかりでとても助かりました。仕事は何をするかでなく、誰とするか、というのを実感しました。

個人としては、こういったハッカソンに参加するのはほとんど初めてだったので、勉強になることが多かったです。
現実の課題意識が先行しすぎて、ハッカソンとしてどうアウトプットを出すべきなのか、ということをもう少し考えることができたら良かったのかなと思います。現実の課題解決方法を考えるのは楽しいけど、やはり限られた中でハッカソンとして、審査員の欲しがるものを出す というのも重要な観点なんだと思います。

総じていい会でした。一日目の夜に東北らしく日本酒まつりがあり、市場では出回らない希少なお酒を飲むことができてそれも良かったです。5年ぶりくらいに仙台に足を運びましたがやっぱ東北に住むのも悪くないなーと少し思いました。

終わり

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にしろ、それらは「何かの目的を達成するために使うもの」でしかないと思っているので、そもそも使ったことでどう変わるんだっけ?ということや、自分たちは何がしたくて、それらのツールを使用するのか?といったことを大本におかないと行けないなーと。

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