Posts for: #Programming

go の generics に慣れてきた

今日の運動は腹筋ローラー,スクワット,縄跳び(両足跳)をした。統計を 運動の記録 にまとめる。

go の generics の扱い

今日はほぼまる一日コードを書いていた。あるデータ型のリファクタリングをしていて次のような constraint とメソッドの組み合わせで型チェックできることを理解した。generics 使って1年以上開発しているので感覚的にも慣れてきた。User と Group のどちらかを受け取る constraint とそのデータストアの定義は次のようになる。

type UserOrGroup interface {
	User | Group
	GetPrimaryID() string
}

type UserOrGroupStore[E UserOrGroup] interface {
	generic.Store[E]
	FindByPrimaryID(ctx context.Context, primaryID string) (*E, error)
}

この型定義を使う関数では次のようになる。

func find[
	E entry.UserOrGroup,
](
	ctx context.Context, store entry.UserOrGroupStore[E], primaryID string,
) (*E, error) {
	e, err := store.FindByPrimaryID(ctx, primaryID)
	if err != nil {
        ...
    }
	ee := *e
    // ee.PrimaryID はコンパイルが通らない
	_ = ee.GetPrimaryID() // 現時点ではメソッド呼び出しが必要
}

ここで UserOrGroup に GetPrimaryID() というメソッドを追加している。本来は両方の構造体に保持するメンバー属性ではあるものの、現時点の go のコンパイラはメンバー属性を正しくチェックできない。そのため、メソッドにして generics の型チェックが正しく通るようにしないといけない。go の issue にも上がっているのでいずれはメンバー属性を解決できるようになるのだろうと推測する。

税理士さんの選定

1時に寝て3時頃に吐き気で起きて1時間ぐらい苦しんでた。久しぶりにやばかった。その後なんとか寝て7時半に起きた。

税理士さんとの打ち合わせ1

うちの会社のイベントとして毎年ワーケーション (開発合宿) をやろうかと考えている。コワーキングやコミュニティの延長上でワーケーションを行うわけだが、いくらかうちの会社の持ち出しで費用負担してよいと考えている。しかし、そのときの支出はどういった建付けで経費として扱えるのかどうか、私は税理士ではないのでよくわかっていない。そういったことを相談するために税理士さんに顧問になってもらおうと考えている。うちから税理士さんへの要件としては freee のデータを正として扱ってくれればそれでいいかな。

また2021年度は赤字決算になったので2022年度に 法人税の欠損金の繰り戻し還付 を行った。このお金を2022年度に計上していないため、その分の金額が資産のマイナスとして2023年度の決算に残ってしまっている。法人税の支払いは正しいのだが、還付金を2023年度に雑収入として登録するか、2022年度に遡って未計上の金額を登録するかのどちらかで訂正しないといけない。過去の法人決算の訂正自体も行う仕組みはあるので手続きするだけだが、それも手間暇がかかるのでついでに税理士さんにやってもらうと考えている。

会計システムに freee を使っているので freee さんの税理士紹介サービスを使って選定する。3事務所ピックアップしてくれたので順番に打ち合わせしていく。今日はその最初の税理事務所の方と打ち合わせした。話した感覚でうちの会社の考え方や規模にあった税理士さんだったのでこの方でいいんじゃないかとも思っているけれど、せっかく他の事務所もピックアップしてくれたので他の税理士さんの話も来週また聞いてみる。

コードレビュー

まる一日コードレビューをしていた。私もマージリクエストを投げていてレビューしてもらいつつ、メンバーのコードレビューも順番にやっていった。その中で smtp の仕様を把握しておく必要があっていくつかシニアエンジニアの方からもアドバイスをもらって、私もそうだったんだと勉強していた。メールヘッダーのエンコーディング、昔は覚えていたけど、ずっとメールを送るコードを書いてなかったので私も忘れてしまっていた。こういうことをさらっと指摘できるのがシニアエンジニアのすごいところ。

go だと標準ライブラリに mime パッケージがある。mime パッケージを使って件名を utf-8 でエンコーディングされた文字列で指定すると次のようになる。q エンコーディングと b エンコーディングの2種類がある。b エンコーディングの方がデータ量が減ってよさそう。

fmt.Println("Subject: " + mime.QEncoding.Encode("utf-8", "テスト"))
fmt.Println("Subject: " + mime.BEncoding.Encode("utf-8", "テスト"))
Subject: =?utf-8?q?=E3=83=86=E3=82=B9=E3=83=88?=
Subject: =?UTF-8?b?44OG44K544OI?=

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 独自?の概念なので新たに学び直す必要がある。

ポインタの学び直し、参照とは違う

2時に寝て7時に起きた。深夜に葬送のフリーレン10巻を読んでからなんとなく眠れなくて夜更かししてた。木曜日は会議がなくて自分のために時間を使える。機能開発に集中して実装していた。

go の学び直し

Gopher塾 #4 - 私も解説できるポインタ - DAY1 に参加した。

今日のテーマはポインタ。tenntenn さんが話すのだから深い内部実装の話しなどもあるのかな?と期待していたけれど、これは基本的な go のポインタの扱いを学ぶ講義だった。私にとっては9割は知っていることだった。それでも1割は知らないことがあったので参加して勉強にはなった。この歳になると本やイベントから1-2割学べたら十分だと思う。go は内部的にすべて値渡しで何でもコピーするするといった振る舞いをする。ポインタを渡すと、ポインタの値であるアドレスをコピーすることでプログラムが動く。コピーなので大きな構造体をそのまま渡すとその分のメモリのオーバーヘッドがあって遅くなったりする。ポインタならアドレスだけのコピーで済む。

go には参照の概念はないという説明があって、ポインタと参照は別の概念なんだと今更ながらに気付いた。gpt-4 にポインタと参照の違いを尋ねたりしていた。参照は初期化後に変更できなかったり、null を参照できなかったり、ポインタ演算のようなことができなかったりすることで安全にプログラミングするための言語機能と言える。一般的には参照はポインタを使って実装される。ポインタの方が低レイヤで制約が少ないと言える。参照はポインタの一部の機能を安全にプログラマーに提供していると言える。

次に go のポインタの特徴をまとめる。

  • 型付け
    • ポインタは型付けされていて、特定の型の変数のアドレスだけがその型のポインタに割り当てられる
  • アドレス演算子とデリファレンス演算子
    • これらを単項演算子と呼ぶ
    • アドレス演算子 (&) で変数のアドレスを取得してポインタを作成する
    • デリファレンス演算子 (*) でポインタが指すアドレスに格納されている値にアクセスする
  • ポインタ演算制限
  • ポインタ演算は許可されていない、メモリアクセスの誤りやセキュリティ上の問題が軽減される
  • new と make 関数
    • new 関数を使うと指定された型の新しい変数を作成してそのアドレスを返す
    • make 関数は、スライス、マップ、チャネルなどの複合データ構造を作成および初期化して、それらへのポインタを返す
  • ポインタの nil 値
    • ポインタは、無効なアドレスを表す特別な値である nil をもてる
    • nil ポインタにアクセスしようとすると、実行時に panic が発生する
  • メソッドレシーバとしてのポインタ
    • メソッドレシーバとしてポインタを使うとメソッド内でレシーバオブジェクトの変更ができる
      • 値レシーバは意図せぬ不具合を招く可能性があるから基本的にはポインタレシーバを使う方がよいのではないかといった話しもあった

休日のオンライン学習

0時に寝て夜中に吐き気がして2回ほど起きて3時と5時に起きて8時に起きた。なかなか苦しい寝方をした。

ヤフートラベルと一休.comのシステム統合

アーカイブ公開されたらみようと思いつつ忘れてたので見返した。

雑なめも。また機をみて見返すこともあるかも。

  • バックエンドは完全に一休側に寄せるという大きな意志決定を2016年に行った
    • この意志決定はフロントエンド統合にも大きな影響を与えた
    • ふじもんさんの意志決定がよかった?
  • 今日の話しはマルチブランドデザインシステム統合がメイン
    • 開発者が50-60人程度で半年ぐらいで launch できた
    • nuxt/vuejs で開発している
    • スタイルは tailwindcss を使っている
    • 実は launch した後にこのシステムが必要だとわかった
      • 開発者とデザイナー間の細かい意思疎通が困難
      • 外部からデザインシステムに詳しい人にも来てもらっていろんな議論をした
      • ガイドラインを言語化するところから始め、最終的にソースコードの共有ができるようになった
    • 終わってからデザインシステムそのものは重要ではないと気付いた
      • この過程で開発者とデザイナー間のどのように共通化するか、あるいはしないかと議論を繰り返し行ったことが重要だったと当事者がインタビューで語っていた
      • デザインシステムの開発を通じてデザインの共通認識をもてたことがよかった
  • 波及効果
    • 同じソースコードから少し異なる体験の開発のノウハウができた
    • ふるさと納税に特化した宿泊予約サイトを作った
  • 統合は終わりではない、lauch したところが始まり
    • 統合後にいろいろな施策をすることで課題がみえてくることがある
  • 全国旅行支援は1つの開発で2つの体験をつくることができた
  • Q. デザイナーと開発者はわりと仲が悪いのでは?価値観や考え方が異なるのですり合わせるのは難しいのでは?
    • 過去の一休でも起きていた
    • 一休のチームはデザイナーと PM と開発者で構成されている
      • このチームが一緒に働いていてチームでなるべく意志決定している
      • 普段から一緒に働いていると仲が悪いということはなかった
      • とはいえ、仕事のプロセスが異なるので課題はあった
        • 地道に丁寧にすり合わせを行った
        • 外部から講師を読んで中立的な立場でワークショップを何度も行った
    • デザイナーと開発者を別の組織にしているとコミュニケーションの壁ができてしまうかもしれない

go の学び直し

テストの学び直し に引き続き、Gopher塾 #2 - Goらしいコードの書き方 - DAY 1 に参加した。

テストの次のプログラミングの話しだったので内容そのものは難しくはなかったけど、改めて重要な項目を選抜しているのだと考えると学びはあったと思う。参考になったことをいくつか覚えている範囲でまとめる。名前の付け方について感覚的に理解していたし、実際に私はそうしているけど、コードレビューしていて自然になっていないコードを指摘する機会も多いので一定の習熟を要するのかもしれない。いま毎週勉強会をやっていて私が講師として話している。ネタがなくなってきたり大変になったきたら準備の少ないコードリーディング会もやってみたいと思った。

  • google Go Style
  • derrors.Wrap
  • 名前に文脈を与えるという概念
    • 相対的な名前をつける
  • 準備の少ないコードリーディング会
    • お題(読むパッケージ)を決める
    • 選んだお題に期待することを当日話す
    • 時間を決めてみんなでそれぞれ読む(20分とか)
    • 読みながらSlackのスレッドにメモをしていく
    • 残りの時間で気になったところを議論する
    • 自分が気づけなかった点を知ることができる

技術選定の根拠

0時に寝て5時に起きた。夜中に目覚めたかどうかはわからないぐらいにはたぶん寝てたと思う。

go の http フレームワークの選定

net/http で実装していた web api サーバーにフレームワーク導入しようかと考えている。いままでは認証・認可を外部で行う想定だったが、やっぱり api サーバーに実装した方がよいだろうと要件を再確認したので routing と middleware を再利用できるフレームワークを使うメリットが出てくる。net/http 上で直接 routing, middleware を実装するのは別に難しくないから自分で実装すればよいという考え方がある。一方で誰が実装しても大して変わらないものを車輪の再発明する必要があるのかというところに私は懸念に感じる。また context があとから標準ライブラリに追加されたため、net/http の HandlerFunc は context をシグネチャにもっていない。リクエストコンテキストをもっていないのが net/http の欠点だと私は考えていた。しかし、調べてたら NewRequestWithContext が追加されていてハンドラーではなくリクエストからリクエストコンテキストを扱えるようになっていた。これは私の勘違いだった。

フレームワークを使おうと決めて難しいのはなにを選ぶか。最近の流行り廃りや動向を私は知らないので基準がない。たまたましぶかわさんの記事をみつけて読んでいた。

この中で紹介されている chiecho のどちらかにしようと直観で決めた。echo は以前 go の勉強会をしたときにいけうちさんが採用していたのでよく覚えている。そのときの話しを聞いていてもよさそうにみえた。たまたま echo のサイトをみたら Shiguredo さんのロゴがあって驚いた。スポンサーをされているらしい。chi はまったく知らない。どちらも十分によく使われていて middleware も揃っているフレームワークにみえる。本質的にはどちらを選んでも構わない。一方でマネージャーとしてどういう調査をして、どういう根拠で、どの技術を選定するのか。メンバーに対して説明責任を果たすためにこの2つのフレームワークの調査をすることに決めた。私自身がどちらもフレームワークも使ったことがないので軽くコードも書いてみてどんな雰囲気なのか感触を掴みつつ、フレームワークのソースコードも読んでみようと思う。

よい go コードを書くためのガイド

2時に寝て6時に起きて2度寝したら8時だった。生活リズムがおかしい。

Go Code Review Comments の学び直し

私の周りでは Go Code Review Comments というドキュメントが引用されているのをよくみかける。google 社での go のコードレビューのときによくある指摘をまとめたものである。pr/mr を送る前にこれぐらいは自分でチェックしようといったガイドになる。私自身、過去に何度か読んでいるとは思うが、久しぶりに go 開発をするので学び直しも兼ねて読み直すことにした。うちのチームは java 開発者が多いせいか、go のコードで go っぽくないところがいくつか散見されていた。チームメンバーにも共有する意図も含めて2回にわけて勉強会をしてみんなで読み合わせをする。その下調べとして既存のコードでこのガイドに準拠していないコードがあればそれはわかりやすい事例になるので探したりしていた。

キャリアは知識と経験の差分でわかる

23時に寝て2時に起きてその後どうしていたかあまり覚えていないが気付いたら8時だった。

ストレッチ

今日の開脚幅は開始前160cmで、ストレッチ後163cmだった。今週も全然ストレッチできなかったのになぜか数値はよくなっていた。ストレッチを受けていて調子の悪さも感じなかったので気候が過ごしやすくなってきて体調がよくなった結果として普段の生活における活動量や新陳代謝などにも影響を与えているのかもしれない。トレーナーさんからは涼しくなったのだから運動をしてくださいと言われた。ほんとその通り。

知識と経験

たまたま目を通した medium のおすすめ記事に出ていて、タイトルにひかれて斜め読みしたらおもしろかったので後で deepl を使って精読した。最近は英語の記事を deepl で訳して読んでいる。まず deepl で全訳した後に文脈から訳文の意味をとれなかったり、明らかにおかしいところだけを手直しする。著作権的に機械翻訳を公開はできないため、その翻訳内容は課題管理システムのイシューで管理している。この記事だと手直し数回ぐらいで大意を読める。普段、英語の記事を日本語アカウントで紹介することはないんだけど、これは素晴らしい内容だったのでそのまま共有することにした。軽く所感も書いてあるが、課題管理システムのイシューにはさらに詳細な分析やコメントも残している。

多くの若いチームでは課題管理の重要性を理解していない。その無理解の原因の1つとして、ものごとを検討したり判断したりした時点では正しかったことが未来のある時点で誤りになってしまう可能性を想像できないからだと私は考えている。記憶と忘却の仕組みから前日のことですら半分以上忘れてしまうので数ヶ月前の詳細など、ほとんどの人は覚えていない。にも関わらず、日々の小さい判断の積み重ねや意思決定の履歴を記録として残さないのはなぜだろうか?それはその詳細があとで重要になるかどうか、多くのケースでその発生時点ではわからないからだ。例えば、システムのアーキテクチャに関して言えば Architectural Decision Records (ADRs) というドキュメントが提唱されている。アーキテクチャのような大きなものでさえ、明示的に残さないと経緯がわからなくなるのに、もっと小さい粒度である日々の開発や運用の誤りを、一般の (普通の) 開発者がその発生時点から数ヶ月や数年経ってふりかえって見直すことができるだろうか?いやできないというのが、多くのチームやメンバーをみてきた私の所感だ。多くのメンバーは過去のある時点の見逃しや判断ミスをなかったことにしようとする。それは無意識にしろ意識的にしろ起きやすい。客観的に詳細を確認できればなかったことになってしまうのは仕方のないことでもある。

私は課題管理システムのコメントに、こういう状況からこう判断したとか、誰それと相談してこういう事情でそうしたとか、自身の感覚からとくに意味もなく決めたとか、常々なぜに相当する内容を残している。そして、あるとき過去の経緯を見返して、そのときの判断は適切だったか、過去のある時点で気付けたはずのことを見逃してなかったか、見逃していたとすればどうすればその時に気付きを得られたか、というふりかえりを日常的なチケット整理の一環として実践している。件の medium の記事にはなぜそれが重要なのかの概念を書いてあるように私には受け取れた。課題管理 + 情報共有の需要な概念の1つだと認識して寝かせておこうと思う。