Posts for: #2024/08

その後の台風の影響

台風の影響で昨日も今日も終日、新幹線は取りやめになっていた。木曜日に帰ってこれた ことには大きな意味があった。本当に助かった。

ストレッチ

今日の開脚幅も開始前149cmで、ストレッチ後156cmと普段通りの数値だった。運動できていないので筋肉痛もなく、デスクワークの疲労ぐらいしかない。いつも通りトレーナーさんと雑談して硬くなったカラダをほぐしてもらう感じだった。今週は出張していたのと、出張中の業務時間も普段より少なかったのでとくに疲労がたまっているわけでもなかった。運動せず筋肉痛もなくストレッチを受けるともったいないような気分にもなってきた。いまの開発フェーズが終わったらまた運動を再開できるかなぁ。

成就しない結末への期待

今期のアニメで 逃げ上手の若君 を見始めた。最初は「ながら」でみていたせいか、あまりぱっとしなかったものの、改めてちゃんと数話を見返したらおもしろい作品だと思えた。もともと私は歴史漫画が好きなので歴史ジャンルというだけでもみてしまう。著者の 松井優征 さんの作品は過去に「暗殺教室」を読んだこともあって好きな漫画家の1人でもある。したがって、私はもともとこの作品を知っていたし、関心をもっていた。いままで読んでいなかっただけ。主人公は 北条時行 という、室町幕府が成立する時代の、鎌倉幕府最後の北条家の跡継ぎになる。足利尊氏 は歴史の授業で習うが、北条時行を私は覚えていないから習わなかったのかもしれない。歴史の影というのか、この作品は敗者を描く作品になる。

余談だが、神戸駅のすぐ近くに 湊川神社 がある。逃げ上手の若君の作品内でも出てくる 湊川の戦い の、あの「湊川」であり、神戸という地元応援の文脈で 楠木正成 も応援している。楠木正成は没後から江戸時代まで知名度は低かったが、なぜか徳川光圀公に評価され、その後、幕末の維新志士から崇敬の対象となり、歴史上の時間が経ってから知名度があがった稀有な武将でもある。そういう背景もあってなのか、逃げ上手の若君の作品内でも特異な武将として描かれていて、史実から湊川の戦いで足利尊氏に負けてしまうのだけれども、それでも格好よく戦って、その智謀を発揮している。この作品を読んでさらに楠木正成への関心が出てきた。

歴史漫画は結果がわかっているから予定調和で読み進める。主人公が勝者であれば安心して読めるが、この作品は敗者なので結末は悲劇となる。ある意味、敗者だからあまり史実の資料が残っていなくて創造性を発揮できるところもあるだろう。そこが漫画家の腕の見せ所だと思う。北条時行による「中先代の乱」があったから南北朝が生まれ、その後の室町幕府への影響も大きかったように、この作品内では描かれている。敗者も歴史を作っていく上での重要な役割を担っているという表現になっていて歴史の背景を想像して楽しみながら読める作品になっていると思う。

まる一日コードレビュー

昨日は2時頃に帰ってきて、朝も昼も食べてなくて空港でおにぎりを食べただけだったので家に戻ってきてお腹が空いて軽食を食べてから寝た。お手伝い先の都合で朝から請求書を送る必要があったため、8時過ぎにはオフィスへ行って請求書を作成して送付した。9時からはらさんと隔週の雑談もあったのでスケジュール的にも早起きする理由があってちょうどよかった。

出張帰りの気分転換に nginx で X-Forwarded-For を設定する方法を remote_addrとかx-forwarded-forとかx-real-ipとか をみたりしながら調査していた。リバースプロキシがある前提であれば、api サーバーがそのヘッダーを参照するのではなく、nginx がそのヘッダーを remote_addr に設定するようにしてしまおうと思う。

今回の開発フェーズでは若いメンバーにサーバーサイドの大きな機能を開発してもらう。サーバーサイド開発の経験を積んでもらう機会にもする。レビューに私の時間が取られることを折り込んで工数を確保している。ある機能の初期実装ができたというのでそのレビューをしていた。そのコードレビューをしていてサーバーサイドの開発は難しいなと実感した。経験がないメンバーだと動けばいいコードしか書けない。効率やリソースの消費を考えながらコードを書いていないし、ライブラリやフレームワークのコードも読んでいないからサーバーサイドの運用に耐えるコードは書けない。あちこち指摘して直してもらう必要があった。なんやらかんやらでまる一日コードレビューしていて、自分の作業はまったくできなかった。

東京出張を新幹線に依存するリスク

新幹線から飛行機への変更

いつも出張帰りは18時19分 (品川発) 〜 20時53分 (新神戸着) の新幹線を使っている。朝の時点では台風が九州にいたので大丈夫そうと考えていた。しかし、16時頃に 東海道・山陽新幹線運行状況 をチェックしたら東京 - 静岡間が止まっていることに気付いた。火曜日の夕方も大雨で2時間半ほど遅れたとお手伝い先の社員さんから聞いていて、静岡県の一部の地域だけ局所的に雨が降ることは事前に知っていた。台風は遠かったから待てば遅れて動き出すかな?と静岡県の天気予報を眺めていた。17-19時に雨足は少し弱まる予報なものの、19時以降はまた強い雨になっていたので18時頃に動かない状況だったから新幹線は無理だなと諦めた。実際 18:50 に新幹線の終日運転取り止めの案内が発表された。

諦めつつ、なんとなくお手伝い先の cto に声をかけてみたら飛行機に変更したら?と教えてもらった。その場で検索してもらって関空行きならまだ予約を取れるという。私は普段、飛行機を使わないから航空券の手配の方法をよくわかっていない。航空券を取るためのアカウントすらあるかも怪しい。そこで cto に航空券を予約していただいた。それから慌てて羽田空港へ向かうことに。しかし、飛行機も約1時間出発が遅れたりして22時前に出発して23時過ぎに関空へ着いた。私は関空へ行くのも初めてだった。関空からの帰りのルートもよくわからない。三宮まで帰るときの電車の最終は 22:48 で、高速バスは 23:00 となる。残念ながら三宮までは帰れないものの、23:45 の梅田行き (最終) の高速バスには乗れた。

0時半頃に梅田に着いた。そのときはどこか適当に泊まる場所を探そうと考えていた。バスを降りて移動していたら、同じバスから降りた2人組がタクシー乗り場を探しながら相乗りする人を探そうと話していた。声をかけてみたら神戸までタクシーで行くというから、一緒に乗せてもらって3人でタクシーで帰ってきた。梅田から神戸までのタクシー料金 (深夜割増) は高速道路を使わずに1万5千円弱だった。時間は1時間半ぐらいかな。1人5千円程度なのでサウナや漫画喫茶に泊まってから電車で帰るのとそれほど変わらない金額に思える。三ノ宮駅で私は降りて2時前には自宅に着いたと思う。

もし私1人だったら18時の時点で帰れないと諦めていた。台風が接近するから金曜日も土曜日も新幹線は止まることが容易に推測できた。周りに尋ねて、他者の助けを得て東京から自宅に帰ることができた。たまにこういうことがあって世の中は助け合いであることを実感する。一方で私の準備不足で右往左往したり、余分にコストがかかったりしたのをふりかえりしておく。

  • 16時の時点で飛行機へ変更をしていたらもっと早く (安く) 帰れた可能性が高い
  • 航空券の予約方法がわからないのを改める必要がある
    • 飛行機予約のためのアカウントを作る
    • 航空券の予約手続きに慣れておく
  • 新幹線が止まっても飛行機は飛んでいる場合がある
  • 慣れておくために飛行機で東京出張する機会をたまに設ける

集中開発の1ヶ月間

プロジェクトの進捗報告

出張したときの月例報告の19回目。前回の進捗報告はこちら 。この開発フェーズは私が経営陣へ進捗報告するものの、引き継いだマネージャーにも同席してもらって、こんな打ち合わせをしているというのを知ってもらう機会にしている。この1ヶ月間の進捗やこの開発フェーズでやろうとしていることを一通り説明して、あとはざっくばらんに経営陣と雑談するといった機会にもなった。最低限、開発のボトルネックになりそうなところは私が集中開発して解消したので見た目上はよいペースで進捗している。

進捗報告して雑談しているうちに、もうこれ以上は私がお手伝い先へ提供できる新たな価値はなさそうに思えてきた。ここからは課題管理できている issue を優先度順にひたすら fix していく、よくないところはリファクタリングする、開発の負債やボトルネックを解消していくといった、より実践的な実務が求められる。課題管理を含むプロジェクトマネジメントやチームの情報共有を改善することで開発をうまくまわしていくフェーズは十分にメンバーが実践できるようになったと思える。自身の引き出しの中身を払い出してしまって、なにも残っていないような寂しさを感じるようになった。

いまマルチブラウザ/デバイスのテストの自動化のために BrowserStack というプラットフォームを評価している。まだ評価中なので採用の可否はこれから判断するところだが、採用したらコストがかかるのでその話題も経営陣に伝えてその場で議論したりしていた。おそらくこのサービスは Selenium Grid を使っているのではないか?と推測される。うちのプロジェクトだけでなく、社内インフラとして全社共通のテスト基盤を作るという施策もあるかもしれないと話しが発散したりもした。開発においてプラットフォーム的な投資も大事だと考えられている。うちのプロダクトで作る課題管理のメトリクスに、プラットフォーム投資のための見える化ができる機能もあるとよいのかもしれないと思ったりしていた。

実際に動くようになってからわかること

東京出張しての、隔週の定例会議にて、ある仕様について話しをした。これまでもずっとそういう仕様ではあったが、実際の本番運用が近づいてきて、実運用を考えているうちにある要件が出てきた。しかし、現状のシステムの構成上、その要件は満たせないことがわかった。1年半にわたって開発してきて初めてこの要件は現状のシステムの制約でできないと発言した。出来ないものは出来ないで仕方ない。それでも今更そんな要件が出てくるところに課題管理として出来ていなかった反省もあるし、気付きが足りなかった。私は20年も開発してきたからたいていの要件への対応は出来るだろうと、自身の経験から過信してしまっているところもあったなと思えた。やはりお仕事になるエンタープライズの要件はなかなか難しい。難しいからお客さんはお金を払って si 的なお仕事になるとも言える。自分への情けなさとそれでもできる範囲でやっていかないといけないという現実とを実感したひとときだった。

親からの依頼

前泊移動

親からの依頼 16時半移動の19時半から友だちと東京で飲み会予定になっていた。昨日リリース作業があったそうでお仕事の影響で行けないという話しになったので新幹線の移動時間も19時52分〜に変更しての前泊になった。スマートEX は新幹線の予約変更を直前までできる。こういう予定が曖昧なときに便利なのを実感した。朝にスーツケースを準備してオフィスに持ち込んで16時から移動できるような段取りは組んでいたものの、なんか16時から移動というのも違和感があったのでキャンセルになっていつも通りのスケジュールで1日を過ごせたことはよかったと思う。

城崎温泉のアテンド

親が親戚と一緒に城崎温泉へ行きたいというので11月の下旬に旅館の予約をとった。サイトで条件を入れて検索したら、きのいえ のすぐ前にあった 緑風閣 がヒットしたので (前を通って) 知っている旅館なのでここでいいなと4人一部屋で予約した。私が車で運転して連れていって案内したりすることになりそう。うちはもともと旅行したりする家族ではなかったし、親がどこかへ行きたいということもあまりないのでこういった機会はなるべく要望に応えるようにはしている。過去2回うちの会社の合宿として城崎温泉へ行った話しを親にしているうちに関心をもったようだ。別に狙った意図ではなかったが、親が楽しむ機会になるならそれはそれでよかったなと思える。

multipart/form-data リクエストの扱い

9時に起きて2度寝して10時頃に起きたものの、お昼までだらだらしていた。それからオフィスへ行って溜まっていた日記をまとめて書いて、逃げ上手の若君 をみながら作業をしていた。来週は出張の週だから事前にやっておくことがいくつかある。

ストレッチ

先週は実家へ帰っていた ために2週間ぶりのストレッチになる。とはいっても、いまは運動をしているので筋肉痛もない。しかし、机に向かってデスクワークする時間が増えている分の負荷がかかっている。トレーナーさんからも腰から背中にかけて硬いと指摘された。今日は硬くなっているカラダ全体をほぐしてもらった感じだった。おかげで今後も体調よく机に向かえる。今日の開脚幅は開始前149cmで、ストレッチ後155cmと普段通りの数値だった。

multipart/form-data リクエストを扱う結合テスト

昨日の夜に汎用のファイル操作の api を実装した。今日はその結合テストを追加してマージリクエストを作成した。multipart/form-data のリクエストを作るのはちょっと面倒くさい。go のライブラリのテストコードや stackoverflow のサンプルコードなどを調べながら自分で実装した。次のような multipart/form-data リクエストを扱う writer や buffer を生成するためのユーティリティを作る。一通りの結合テストを実装するのに3時間ほどかかった。

func createMultiPartFormData(
	fileBody []byte, formField map[string]string,
) (*multipart.Writer, *bytes.Buffer, error) {
	b := new(bytes.Buffer)
	mw := multipart.NewWriter(b)
	for k, v := range formField {
		fw, err := mw.CreateFormField(k)
		if err != nil {
			return nil, b, err
		}
		if _, err := fw.Write([]byte(v)); err != nil {
			return nil, b, err
		}
	}
	fw, err := mw.CreateFormFile("file", "path/to/file")
	if err != nil {
		return nil, b, err
	}
	if _, err := fw.Write(fileBody); err != nil {
		return nil, b, err
	}
	if err := mw.Close(); err != nil {
		return nil, b, err
	}
	return mw, b, nil
}

このユーティリティを使って http リクエストのテストデータを生成するのは次のようなコードになる。

u := &url.URL{
	Scheme: "http",
	Host:   "localhost",
	Path:   path,
}
mw, body, err := createMultiPartFormData(fileBody, formField)
if err != nil {
	return nil, fmt.Errorf("failed to create multipart form data: %s", err)
}
req, err := http.NewRequest(http.MethodPost, u.String(), body)
if err != nil {
	return nil, fmt.Errorf("http create new request error. err: %s", err)
}
req.Header.Set("Content-Type", mw.FormDataContentType())

あと結合テストでファイルをアップロードすると実際にファイルシステム上に保存されてしまうのでそれらを削除するには Cleanup を使うと簡単に後始末できた。

func TestFileUpload(t *testing.T) {
    ...
	t.Cleanup(func() {
		if err := os.RemoveAll(file.FilesDir); err != nil {
			t.Errorf("failed to remove files directory: %s", err)
			return
		}
	})
    ...
}

生活のリズムづくりの1ヶ月

歯科検診

17時から歯科検診へ行ってきた。スタッフに「痩せてませんか?」と尋ねられて3ヶ月ぶりならそれほど変わらないんじゃないかと返したが、そのスタッフが私の担当をするのは2月以来だったらしく、それならかなり変わりましたと話していた。たまにしか行かないのに、首まわりが全然違うと言われて、半年前の体型を覚えているんやなと思ってこっちが驚いた。たまに会う人向けのお断りとして「癌ではありません」と説明しといた。

生活のリズムづくり

ここ1ヶ月ほど開発者へ戻るための取り組みをしてきた。昼間にお仕事でコードを書いて、晩ごはんを食べてから、夜にコードを書くのが習慣的になってきた。概ね1日の作業時間が10-12時間になってきている。夜に開発できている日はだいたい20-21時頃から24時頃までコードを書いている。夜は割り込みが入らないので集中できる。今日も晩ごはんを食べて22時前から翌2時半ぐらいまでコーディングしていた。ファイルのアップロード/ダウンロードを扱う汎用 api を実装した。

いまの開発フェーズでは 過去の残課題 が多い。それはこれまでの私のマネジメント不備でもあるし、知見を得たことでアーキテクチャの不備や再設計のリファクタリングができるようになった課題も多い。技術的負債が溜まっているとみなせる。いずれにしても、実運用を間近に控えて直せるところをできるだけ直しておきたい。当初は私が改善する issue が仕様変更になるためにプロジェクト全体のボトルネックになってしまっていた。なるべく初期の開発で ボトルネックを解消 してからもペースを落とすことなく、集中して開発作業を継続できている。スケジュールの前倒しとまではいかないが、後手にまわっている印象はなく迅速に対応できている。個人的にもよいリズムと集中力が出てきたと感じている。その視点からみると、いま開発に向いている集中力をこれまでは体脂肪コントロールや運動に費やしてきたこともわかる。だから短期間に大きな成果が出た。人の可処分時間は決まっている。継続的になにかに取り組むと1ヶ月も経てば実感できるぐらいの成果がでる。もしかしたら私がフルタイムの開発者として作業できるのはあと3ヶ月になるかもしれない。悔いの残らないよう、できるだけ集中して取り組もうと思う。

ファイルアップロードのインターフェース

今日も昼間は普通にお仕事で開発して、お仕事を終えて晩ごはんを買い出しへ行ってきて、オフィスで晩ごはんを食べてから夜のコーディングに戻るといった一日になった。昼間は会議や問い合わせ対応、他のメンバーの進捗をチェックしたりなど、ちょくちょく割り込みが入る。夜はそれらがないことがわかっているので3-4時間集中してコーディングできる。

echo のファイルアップロードのサンプル

メンバーがファイルを受け渡しする web api のインターフェースがよくわからないということで私がサンプルを作ってみることにした。echo には File Upload のサンプルも紹介されているからすぐにできる。歴史的にブラウザからのファイルアップロードを前提にすると、ファイルを扱うときは次の Content-Type を使う。

Content-Type: multipart/form-data

これを echo のコードで書くと次のようなインターフェースとなる。

type MyRequest struct {
	Type      string    `form:"type" validate:"required"`
	Operation string    `form:"operation" validate:"required"`
}

func handle(c echo.Context) error {
	req := MyRequest{}
	if err := c.Bind(&req); err != nil {
		return err
	}
	if err := c.Validate(&req); err != nil {
		return err
	}
	file, err := c.FormFile("file")
	if err != nil {
		if errors.Is(err, http.ErrMissingFile) {
			return echo.NewHTTPError(http.StatusBadRequest, "file is required")
		}
		return err
	}
    ...

ファイル情報を MyRequest で管理できるとリクエストパラメーターを一元管理できて望ましいが、次の issue によると現時点ではそれはできないらしい。

curl コマンドでリクエストするには次のような cli になる。

$ curl -i -X POST -F type=misc -F operation=add -F file="@myfile.data" ...

寝ている間に再設計

昨日のもやもやは寝ている間に整理され、今日は標準的な開発者としての過ごし方になった感じがする。

マネージャーとの 1on1

これまでは私がマネージャーとして 1on1 をしてきたが、今後は交代したメンバーがマネージャーを務める。この開発フェーズでは私は開発者 (メンバー) として 1on1 をしてもらうといった感じかな。自分が開発者側だと思うと、いま私が取り組んでいることの話しをしやすかったりした。立場によって 1on1 のやり方は変わることを実感した。マネージャーはメンバーの話しを聞く方に注力したり、プロジェクト全体の話しをしがちになる。開発者として臨むと、自分の抱えている issue に集中して話せるといった違いがあった。

CPAP の中断

夜に睡眠外来へ行ってきた。以前に CPAP 装置 を借りて3ヶ月ぐらいやっていたものの、ここ2ヶ月ほどやらなくなってしまっていた。もともとは体脂肪コントロールの疲労回復のために始めたものだった。体脂肪コントロールがうまくいって目標達成したことで睡眠改善を行う目的もなくなってしまって関心を失ってしまった。借りているだけで毎月5千円ほどかかるので中断して機器を返却することにした。旅行のときなど、一時的に借りられないかを聞いてみたら、それは不可とのこと。また再開したくなったらいつでも言えばよいとのこと。

ツールの再設計

昨日の続き 。睡眠外来から帰ってきて、晩ごはん食べて、軽く飲みながら24時過ぎまでコードを書いていた。今日もまる一日ツールの再設計をしていた。昨日のノーアイディアな状況から少しずつ好転していって、ある処理で歯車が噛み合ってからはいつも通り着実に進捗していく様がみられた。意図的にやっていることではあるけど、課題について考えながら一晩寝ると、寝ている間に無意識に刷り込まれて脳が考えてくれる。それで徐々によい設計が現れてくるようになって明確な実装に落ち着いたのではないかと推測する。今日はよい感じに集中できた。