Posts for: #Design

go のジェネリクスと型の集合

0時に寝て何度か起きて7時に起きた。22時頃に素麺を食べたら夜に吐き気がして食べるんじゃなかった。

ストレッチ

今週はいつも通りの普通の1週間を過ごした感じ。休養していたわけでもなく負荷が高かったわけでもない。私の感覚的には右太もも後ろの筋と右腰の張りが強かった。トレーナーさん的には腰は大丈夫そうに言っていて、股関節全体の硬さは常態化しているものだけど、すねの筋もやや張りがあったように話していた。私の感覚とトレーナーさんの感覚がちょっとズレていた。今日の開脚幅は開始前154cmで、ストレッチ後158cmだった。一時期の3-4月の疲弊した状態ではないので一番悪い時期は脱したようにもみえる。

go の学び直し

Gopher塾 #5 - ジェネリクスが書けるようになろう に参加した。

すでにうちのプロダクトはジェネリクスを使った開発を行ってはいるけれど、私自身まだ曖昧なところがあったり、どういった設計がよいのかの手探り状態である。go はオブジェクト指向言語ではない (それ自体は構わない) ところが java のジェネリクスとは異なっていて、なにがその根本的な違いになっているのかを、私の中ではまだ理解できていなかった。その答えがこの勉強会に出てわかった気がする。もう少し独学して理論的に理解する必要はあるが、私に足りなかった知識が参加前よりも明確になったのでこの後の学習は容易に思える。

イベントではワークシートに自分で理解したメモや課題の回答を書き出すよう tenntenn さんが促していた。私はメモを自社の課題管理システムに書いていたのでワークシートには書いていないが、自分の理解を書き出すことの重要性は同意できる。tenntenn さんは次のように説明していた。

概念や理解したことを自分の言葉で表現できるか?を確認するために書くことは大事。

もし書いた内容が間違っていても、間違ったことを認識できることにも意味がある。

つまり、学んだことを書くことは正しくても間違っていても得られるものがある。

この考え方は私が提唱する課題管理にも通じている。なぜ書くかの理由の1つは自分の理解を整理するためでもある。そして、その文章を外部から監視できることで上長が助言できる。私にとっては習慣として身に付いた事柄ではあるけれど、改めてこういうことをチームのメンバーに啓蒙したり、開発ガイドに書いておくとよいように思えた。go の勉強会に参加して課題管理で学ぶことがあるとは思わなかった。よいこと尽くめだ。

閑話休題。本題のジェネリクスについて3割ぐらい知らないことがあった。私が java のジェネリクスと比べて go のジェネリクスを完全に理解できていなかったところの要因は 型の集合 (Type sets) の概念を理解できていなかったところに起因する。go ではジェネリクスを導入するにあたってインターフェースに型の集合という概念を導入した。それまでのインターフェースはメソッドの集合を管理するだけだったが、型の集合も管理できるようになった。また go には Underlying types という概念が当初から存在したが、それを意識してプログラミングすることはなかった。これを日本語にすると「基底型」となるが、オブジェクト指向言語で言うところの基底型とはまったく異なる。なにせ継承できないのだから。インターフェースに型の集合として次の記述ができるようになった。Underlying types はこれまで概念としてしか存在していなかったのがチルダを用いた文法で表現できるようになったため、その理解も強いられるようになった。

Go の “Type Sets” proposal を読む によると、現時点での型の集合とは次の2つを指す。

  • ~T approximation element (近似要素)
  • T | U union element (合併要素)

union 型のようなものは他言語でもある概念なのでイメージしやすいが、Underlying types をチルダを使って指定するのは go 独自?の概念なので新たに学び直す必要がある。

コードを書いていると後から改善点に気づく

1時に寝て7時に起きた。起きてからドラクエタクトをだらだらやってて10時前に起き上がってそれからオフィスへ行って活動してた。

リファクタリングのリファクタリング

昨日書いたマージリクエストの変更点についてドキュメントの更新だけしようと作業していたら、その後、一緒に修正した方がよい追加の機能拡張に気付いて3時間ほど追加の実装をしていた。その後、お昼ご飯を食べているときに午前中に書いた実装を改善した方がよいところに気付いて、さらに追加で1時間ほどリファクタリングしていた。コードを書いていて、一旦はできたつもりになってその時点ではよさそうに思うのだけど、時間が経ってから考え直すと考慮漏れやもっとよい実装のアイディアを思い付いたりする。私の頭が悪いだけかもしれないが、最初からよい実装や設計を行うことは多くの人にとって難しいことだと思いたい。何度も考えて作り直したり改善したりしているうちにもっとよい方法に気付く。

多くの開発者はもっとよいアイディアを思い付いたとしても実際にリファクタリングをしようとしない。動いているコードを修正して壊れるリスクや他に優先度の高い作業があるとか、いろいろやらない理由を言う人たちもいる。私はそのやらない理由を議論している合間にリファクタリングしてしまう。というのは、誇張した比喩で実際にはもっと時間がかかることもあるけど、設計も見直す数千行レベルの変更を気軽に行う。もしそれで壊れたらどうすると聞かれてもシンプルに謝るだけ。謝ってから直す、テストを書く、再発防止のための仕組みを考える。やることはそれだけ。問題のあるコードを見て見ぬ振りをする開発者の方が普通という感覚がある。10年以上開発をやってきて思うこととして、そういう価値観を上位の開発者が壊していって模範を示すことがよい開発文化への第一歩となる。しんどいことに対して口だけでは人は動かない。個々の開発者が問題だと思ったらどんどん書き直していく、リファクタリングしていくという文化は一朝一夕ではできない。そういう開発文化を醸成していくと大きな技術的負債が溜まるといったことはなくなるのではないかと考えている。

リファクタリング一段落

1時に寝て7時に起きた。前日も21時頃までオフィスにいて、今日も午後からコードを書いていて22時ぐらいまでやってた。コードを書いていると時間がどんどんなくなる。本当は三宮.dev の勉強会があったんだけど、このリファクタリングは週末にやってしまわないとやばいという野生の勘でキャンセルした。

ストレッチ

今日の開脚幅は開始前156cmで、ストレッチ後160cmだった。だいたいいつも通り。先週から右すねの外側の筋に張りがある。先週よりちょっとよくなった気もするけれど、まだ張りが継続している。あと今週は右腰に張りがあった。今週はリファクタリングしていて座ってきる時間がいつもより長かったためだろうと推測する。どんなに忙しくてもストレッチだけは休まないようにしている。ストレッチに通い始めて2年以上経つが身体的に体調が悪いということは記憶にほぼない。日記にはその週のどこそこに張りがあるとか調子が悪いといったことを書いたりしているが、それは日常生活を送る上で支障が出るようなレベルではない。そうならないように予防している。健康を維持する上でストレッチは大きな影響を与えているため、中長期の展望から忙しくても継続するようにしている。

機能拡張とリファクタリング

今日は休日出勤して go のコードを書いていた。ある機能を作るときに内部的には汎用の api にしてしまって他のコレクションのデータ型でも再利用できるようにしたい。先週ずっと go の generics を使って mongodb 周りのコレクションとそのクライアントのリファクタリングをしていた。go の generics の理解も進んで crud なインターフェースを generics でどのように定義して実装すればいいかわかってきた。その過程で web api のアプリケーション層と mongodb のインフラ層 (データ層) の役割分担も明確になりつつある。どちらも generics を駆使して型チェックされた上でソースコードを共通化し、汎用 api としてリファクタリングしながら設計している。その集大成としてアプリケーション側で汎用的な機能を追加するときに、理想的には1つのコードを追加・変更すれば、別のデータ型でもすべて同じように動くといった機能として実装した。4つのコレクションのデータ型で同じ振る舞い (機能) を共通化する。その実装も丸1日やれば完了できるぐらいに設計の効率化ができてきた。

go はオブジェクト指向言語ではないので generics を駆使しても、java でいうところの抽象既定クラスを用いたテンプレートパターンの実装ができない。それぞれの構造体で基本的にはコピペとなる構造体のメソッドを定義しないといけない。もちろん別のヘルパーに移譲するといったことはできるけど、状態をもっていないコードの再利用はたしかに安全ではあるけれど、状態を参照できないからそのために値をコピーするといった整合性の懸念やボイラープレート的なコードを書く必要がある。これは設計におけるトレードオフになるので go の処理系の設計に不満があるわけではない。但し、generics でできることにはまだ機能不足がある。とくに直和型の扱い。できないのかな?とググると proposal の issue がみつかるので今後の機能拡張に期待したい。

正直マネージャーが開発に工数使っていて何やってるんだとみられているかもしれない。1-2週間集中してリファクタリングしてみて、いまのアプリケーションの設計の勘所が以前よりも理解が進んだ。コードレビューだけではわからないフィードバックがある。結合テストもいくつか追加したので今後の開発で役に立つはず。これで私の (リファクタリング) 開発は終了しようと思う。

今日作ったマージリクエストの diff が次になる。

51 files +1314 -648

diff の行数だけ数えると今週だけで1万行近くは変更したと思う。

zeromq の多言語対応がすごい

1時に寝て7時に起きた。昨晩は食べ過ぎて気分が悪かった。

エレベーター点検の間違い

朝オフィスの入っているビルへ着くと、エレベーターに張り紙があって使えないことが書いてある。問題があれば、エレベーターの保守会社へ連絡してくださいとある。その張り紙をみて、エレベーターが故障したのかな?と勘違いした。その横でオフィスの利用者が10人ほど復旧を待っていた。仕方ないから一旦、家に戻って午前中は家からお仕事することにした。これはこれで docker で開発環境を作っていると、普段使っていないマシンでもすぐに開発環境を構築できることのメリットを実感する機会となった。11時頃に再訪したら普通にエレベーターが動いていて、あれ!?と思って、そのときに初めてビルの掲示板を見に行ったら、7:30 - 8:30 の時間帯でエレベーター点検だと書いてあった。私は8時前後に出社するのでこの時間帯は厳しい。エレベーターが動いていなかったらまず点検を疑うことにするのを学んだ。

zeromq の調査

昨日から zeromq の調査をしていた。ネットワークの通信におけるプラクティスとも言える、ØMQ - The Guide というごっついガイドもあって学びが多い。少し古いバージョンなら翻訳版も ØMQガイドブック(日本語版) にある。英語が苦手な方はまずこれを読んで概要を掴むのもよいかもしれない。ちなみにこの翻訳者の方といま一緒に働いていて設計のレビューをお願いして教えていただいている。感謝。

zeromq を使うときの注意点の1つとして、バックグラウンドで i/o スレッドが動いていて zmq_send() は実際に通信しているのではなく、バックグラウンドの i/o スレッドにメッセージを渡すだけになる。そのため、i/o スレッドが実際にノード間の通信を非同期で行う。これは接続先の相手がダウンしていても送信バッファにメッセージを溜めておいて再送してくれるので都合がよい。ちなみに送信バッファのサイズは zmq_setsockopt()ZMQ_SNDHWM を指定して調整できる。ソケットが常時接続されていれば、メッセージの順序は維持されるらしいが、ソケットを接続/切断するような使い方をすると zmq_send() が呼ばれたメッセージの順序は保証されない。一般の queue をイメージしてメッセージの順序が保証されることを前提に開発すると落とし穴があるので注意しておく必要がある。そういう so や issue も登録されているのを確認した。

近況報告の雑談

約1年ぶりにやすだ先生と大阪でオフライン飲み会をした。毎年2-3月頃に近況報告して経営のアドバイスなどをいただいたりしている。今回で3回目。今年は私がいま実家のいろいろとリファクタリングなどでいっぱいっぱいなのでとくに近況報告の資料を作る余裕がなくて、普通に飲み会しながらその場での近況報告となった。昨今の web 開発の当たり前として ci/cd や k8s のことを共有しながら、大学のシステムはどうこうみたいな話しもした。やすだ先生も副業が好調らしく、東京に出張する機会も多いとご活躍されているそうだ。

今回 クラフトビアハウスモルト 梅田店 というお店に初めて行った。私のような普段着の人間でも気軽に入ってよいようなお店であることもわかった。また接待で使おうと思う。食べものはちょっと上等なおつまみがある程度なのでビールを飲むのをメインとする相手がよいだろう。飲み放題コースにしたので、食べものの選択やビールの値段を気にせず注文できたのも接待としては考えることが減ってよかったと思う。阪急グランドビルの31Fという最上階にあって、あまり広いお店ではないが、気軽に夜景をみながらクラフトビールを飲める。早めに予約したおかげだと推測するが、カウンター席の一番端だったので座席もよかった。その横におそらく VIP ルームがあって、個室かどうかよりも店内が広くないので広いスペースを使う意図で VIP ルームもよさそうにみえた。追加料金なく借りれるのかな?2人で借りるのは難しいかもしれないが、4人ほどいれば借りてみたいと思う。

余裕がなさ過ぎる

1時に寝て7時に起きた。タスクが溜まり過ぎてそろそろ辛くなってきているところ。この余裕の無さはよくないことなので、自分のダメさ加減というか、大いに反省しないといけない。

隔週の雑談

顧問のはらさんと隔週の打ち合わせ。いつもは打ち合わせの議題を2-3日前には共有するようにしている。だいたい水曜日前後に議題のリファレンスをはらさんに共有して金曜日の朝に話している。しかし、今週はリファクタリングに集中し過ぎていて前日の寝る前になって議題を共有していないことに気付いた。そして朝起きてから急ぎで議題を考えて共有していた。これはとてもよくない。準備ができていないので今日の議題は主に近況の話しをしていた。

ハドルの雑談

先日から 午前中はハドルに滞在 するようにしている。今週は木曜日にチーム外から勉強会についての相談が、今日はメンバーから気分転換に雑談にやってきてくれた。おそらく私がハドルにいなかったらゼロだったコミュニケーションの機会が、1週間に1-2回でもあることに私は嬉しく思ってしまう。フルリモートワークにおける、オフラインのような気軽な雑談の機会を提供する施策の1つとして意味なくハドルに入るのは悪くない気がしている。そのときにコミュニケーションを強制させるような押し付けが発生しないよう、運用ルールを徹底することが大事に思える。いまは相手がハドルに入ってくると 1on1 のような雰囲気になってしまうのでその次の挑戦としてはハドルに入っていても話さなくてよいといった運用ルールを設ければよいのではないかと思う。例えば、午前中はとりあえずハドルに入って気分が向いたときだけ話しかけるみたいな、ゆるいコミュニケーションの場になればいいなと思う。

ハドル雑談の運用ルールのアイディア

  • ハドルに入らなくても業務上の支障は一切おきない
  • ハドルにいる人には、用事があってもなくても、話しかけてよい
  • ハドルに入っていても話さず聞いているだけでもよい
  • 業務に集中していて忙しいときは話しかけられても後回しにしてもよい (ハドルから退出した方がわかりやすいかもしれない)

go の generics 勉強会

ちょうど先週からあちこち直したり、mongodb のクライアント周りをリファクタリングしたりしている。その過程で generics を使ってコードの共通化もしたりしている。私自身 generics で意図した通りにコンパイルできなくてはまってしまった事例もあるのでそういった失敗コードも共有した。go の generics はコードに対して静的な領域しか適用されず、コード中における動的な値の型は generics とは直行した概念だというところに初学者ははまるのではないかと思う。私がはまった。参加者におそらく1度はまるからはまったときに私が話していたことを思い出してとコードの解説をしていた。

余裕があったらスライドにまとめて後で資料として再利用できるようにしたかったものの、私の作業に余裕がなさ過ぎて次のリファレンスから引用しながら解説するといった勉強会になった。ただ私が読んでよいと思った他者のスライドやブログの記事のみを紹介している。それはそれで参考にはなるので勉強会の意図としては問題なかったんじゃないかとは思う。

mongodb を触ってみる

0時に寝て7時半に起きた。今日は1日中リファクタリングしてコードを書いていた。

リファクタリング

mongodb 周りのインフラ層のリファクタリングしている。過去に mongodb を触ったことがなかったので mongodb そのものの振る舞いや仕様なども理解しながらリファクタリングしている。その第一弾として差分が1500行以上のマージリクエストを作った。私の中ではまだ 1/3 ぐらいの進捗。動くレベルになったのでコードレビューを通じてメンバーと設計の考え方を共有していく。差分は多いけど、重要なところは一部だけ。やり過ぎだなと思えるのは、設計を見直すとテストコードを書き換える必要があって、その書き換えをやっていると時間が削られる。設計の部分だけ変更して、その後の作業をメンバーに引き継いでもらうといったやり方ならもっと早くできるかもしれないけど、テストコードを書き換える過程で私もユーザーの立場になって設計の良し悪しを検証するきっかけになるのでこの作業は自分でやることにも価値があると考えている。

設計がよくないところをどうやってメンバーに指導していくかはなかなか難しい。良し悪しは複数の設計を比較することで初めて気づくことも多い。私はその引き出しが多いので比較対象がたくさんあるだけでメンバーはその引き出しが少ないから悪い設計と認識できないでいる。その比較対象を私が提示してメンバーが考える機会にしてあげたい。理屈上はこれだけなんだけど、現実のコードと納期とのバランスを取るのが難しい。

いい加減マネージャーがリファクタリングに工数を使い過ぎだろうと私自身でも思うようになってきたので週末に残りのコードを書いて区切りのよいところでひと段落つけようと思う。

クリーンアーキテクチャを勉強し直したい

0時に寝て5時前に起きたらサッカーやってて最後の10分ほどみた。まさかスペインに勝つと思ってなかったから驚いた。

アーキテクチャと設計

退職したメンバー がドメイン駆動開発 (DDD) とクリーンアーキテクチャから既存のアーキテクチャを構成したというドキュメントを残してくれた。そのドキュメントを読みながら、説明の粗いところや足りないところを私が補って加筆し、既存のコードを読みながら誤っているところなどをリファクタリングしたりしていた。あとアーキテクチャや設計のドキュメントを書く上で図がないのはよくない。現代の開発は分割統治の概念で設計されていて、そこで扱う本質的複雑さは依存関係になる。誤解を恐れずに言えば、現代の開発のアーキテクチャは依存関係をどう管理するかの基本的な考え方に過ぎない。依存関係の向きが分かるので図があった方が圧倒的にわかりやすい。一方で私自身もクリーンアーキテクチャにそう明るくない。もう少し勉強し直す必要があることは感じた。クリーンアーキテクチャ勉強会もやっていいようにも思う。

課題管理 + イテレーション開発とスクラム開発の勉強会

今週ずっと朝起きたら2-3時間かけて資料を作り続けてきた。前回は時間が余ったので今回は余らないよう、最終的には43枚のスライドになった。

  • スクラム事前知識
  • スクラムガイド
  • 課題管理+イテレーション開発とスクラム開発との比較
  • スクラムマスター
  • 会議体とツール
  • 分析・計測
  • スクラムの是非
  • まとめ

話してみたら1時間を10分ほどオーバーした。勉強会で1時間話すネタを調整をするのは難しい。毎月出張でオフィスへ行くときは課題管理に関する勉強会を行う。課題管理や開発方法論の話しを聞いてくれる人たちがいるというだけでありがたい。5日前から準備を始めて資料作りの時間が少なかったので細部の調査はあまりできていないし、構成も荒くて練れていない。もう2-3ヶ月かけて細部の調査や理論武装をしたらよいコンテンツになるかもしれない。イテレーション開発とスクラム開発を比較するときの叩き台として寝かしておく。

オフィスの引越しの荷造り

神戸に戻ってきて一旦家に帰って晩ご飯を食べて一息ついて、23時過ぎから引越しのための荷造りを始めた。大きい家電や電子機器は購入時の箱を置いておくと引越しのときの荷造りが楽になる。言うても一部屋の荷物なんで本気出せばすぐ終わる程度の量。3時間ほど荷造りやって8割ぐらいできたところで今日の作業は終えた。出張と移動で疲労は積み重なってきた。

http フレームワークの選び方

昨夜いろいろあって帰ってくるのが0時過ぎになった。23時過ぎから雨降りで雨の中、自転車で帰ってきた。2時に寝て5時に起きて7時半に起きた。危うく寝坊するところだった。

母の入院

昨夜のいろいろのすべて。最悪の事態を想定してお手伝い先にも今日休むかも?と昨日の夜時点で一報を入れていた。結論としては休む必要はなかった。「ろれつが回らない」という連絡を受けて姉が救急車で病院へいくことを指示して即検査で即入院した。母は過去に目がみえなくなって脳梗塞だったことがある。幸い一通り検査して問題はなかったものの、念のために2日間入院して明日退院する予定。姉に病院の付き添いとかいろいろやってもらったので、私も週末に帰って様子をみてくる。お仕事が立て込んでてんやわんやだけど、そのために神戸で自分の会社をやっているのもあるので仕方ない。母は車を運転しない方がよいだろうという見立てで週末にレンタカーも借りた。久しぶりに高速バスではなく、高速道路をドライブしながら実家へ帰る。

echo と chi でサンプルコードを書いてみた

go の http フレームワークの選定 の続き。明日、定例があるのでメンバーにソースコードを共有しつつ、http フレームワークの採用を決めようと考えている。特定のルーティングとミドルウェアの適用をする簡単なサンプル。

net/http のレイヤーであれこれカスタマイズしたいなら chi でよい気もするけど、web api のアプリケーションのレイヤーにのみ注力したいなら echo を使った方が楽そうという私の第一印象。web api サーバーを書いてて request のパラメーターを扱うことはあっても response writer を扱う必要性をあまり感じたことがない。json しか返さないのだし、構造体を返したら勝手に json に変換してくれたらそれでいいんじゃないかと私は考えている。

設計談義

0時に寝て6時に起きた。2時と3時ぐらいに起きたけど、まぁまぁ眠れた。

go の interface の考え方

メンバーと設計の議論をしていて interface の考え方の概念を誤解しているように感じたので Go Code Review Comments の interfaces で書いてあることの意図や背景などを解説した。メンバー全員を集めて30分ほどで説明した。既存のコードは過剰に interface を設計していて、特定のメソッドを呼び出すラッパー関数を設けて、そのシグネチャに interface を受け取って構造体のメソッドを呼び出すコードを書いている。こんな感じのコード。

type myBehavior interface {
  doSome(data string) error
}

type myObject struct {
  myBehavior
}

func (o *myObject) doSome(data string) {
  ...
}

func handleSome(o myBehavior, data string) error
	return o.doSome(data)
}

handleSome のようなラッパー関数は不要だし、myObject の構造体に interface を埋め込む必要はないし、Go Code Review Comments では構造体を定義しているところで interface を提供しない方が保守コストが下がってよいよと提案している。これは java のような nominal subtyping と go の structural subtyping の違いで go らしい interface は構造体の提供側ではなく、呼び出し側で勝手に定義して任意の振る舞いを強制できるといった内容を java と go のコードを比較しながら説明した。そして、この話しが重要になるのはサードパーティのライブラリを利用するときに interface が変わると、それを使っている開発者に大きな影響を与えるので interface を提供するなら慎重に練ったものを公開しないといけないという java 開発から得られた知見などが影響しているのではないかという私見も話した。さらに自分たちが管理しているコードなら interface が変わろうが struct のメソッドが変わろうが、すべて自分たちが変更できる権限をもっているから設計時に厳密に interface やメソッドの振る舞いを詰めきれなかったとしても、後から必要ならいつでもいくらでも変えればいいだけと一緒に話した。開発のバランス感覚は経験からでないと身に付かないものだと思う。