かなで技術日誌

プログラミングやエンジニアリング周りについて

主なアウトプットはScrapboxにまとめてます。

SageMaker Studioでexec format errorを解決する

結論

m1 macからのbuiildだったためアーキテクチャの差異が原因。 m1 macでのdocker build時は--platform=amd64を指定する。

詳細

SageMaker Studioのカスタムイメージを使うためにdocker build→docker pushまで実行してSageMaker Studioの立ち上げるも、カスタムイメージをを指定すると正常起動せず最終的にエラーになる。

CloudWatchで該当のappのログを見ても出力されているのはexec /opt/.sagemakerinternal/conda/kgw_variant: exec format error.というエラーのみでパッと見よくわからない。

最終的に辿り着いたのが以下のissueです。

github.com

m1 macでビルドした際にarm64のイメージが優先して取得されます。SageMaker StudioはEFSボリュームが今回だとKernelGatewayにマウントされる際にアーキテクチャが合わずにKernelの起動に失敗したという感じでしょうか。(推測が入っているので正しいかはわかりません)

qiita.com

なのでm1 macであればplatformオプションをamd64に指定することで解決するということです。

qiita.com

運用するときはGitHub ActionsやCircleCIなどを使うと思うのでアーキテクチャの違いに悩まされることは無いと思いますが、調査の時はローカルでの作業がメインになるので気をつけましょう。

余談ですが、調査しているときに同じDockerfileを使っているのにSageMaker Studioで起動するイメージと起動しないイメージがあり、更に謎が深まっていました。理由はローカルからbuildした時とGitHu Codespacesでbuildした時の違いでした。

部分和問題のビット全探索をやっと理解した

アルゴリズム力を鍛えるためにけんちょんさんの本を読んでいて、部分和問題のビット全探索でうまく理解できなかったので自分が理解できるまで調べたという話です。

より詳細な解説を読みたいのであればご本人のブログを読むのが良いかと思います。 drken1215.hatenablog.com

部分和問題でのビット全探索

部分和問題について

「部分和問題 (subset-sum problem)」は、要素が数値の集合 S において、要素の総和が M となる部分集合があるか判定する問題です。

www.nct9.ne.jp

ビット演算について

&(AND)

二つのスイッチを比較してどちらも1なら1、どちらか0なら0を返す

c = a & b

a: 10110101

b: 01000101

c: 00000101

用途

ビットでフラグ管理をしている場合の探索

|(OR)

二つのスイッチを比較してどちらかが1なら1、どちらも0なら0を返す

c = a | b

a: 10110101

b: 01000101

c: 11110101

用途

ビットでフラグ管理をしている場合にフラグを立てる場合

!(NOT)または~

スイッチのON/OFFを全て逆転させる

c = !a

a: 10110101

c: 01001010

XOR

二つのスイッチを比較してどちらか片方だけ1なら1、どちらも1または0なら0を返す

c = a ^ b

a: 10110101

b: 01000101

c: 11110000

用途

二つのスイッチの差分を調べる

>>(右ビットシフト)

スイッチのON/OFFを一つ右にずらす。

空いたビットには0埋めが行われて、溢れたビットは消える。

c = a >> 1

a: 10110101

c: 01011010

用途

ループでビット操作する時

<<(左ビットシフト)

スイッチのON/OFFを一つ左にずらす。

他の操作は右ビットシフトと同様。

c = a << 1

a: 10110101

c: 01101010

用途

右ビットシフトと同様

参考

https://qiita.com/Ingward/items/43acda931c8a62c70d2f

ビット全探索の解説

例題

N個の正の整数a0,a1,...,aN-1と正の整数Wが与えられます.a0,a1,...,aN-1の中から何個かの整数を選んで総和をWとすることができるかどうかを判定してください.

例題解説

N個の整数の集合の2Nある部分集合からどの組み合わせでも良いので総和Wになる組み合わせが存在するかを判定する。

たとえば{1,3,7}という整数の集合の部分集合は{},{1},{3},{7},{1,3},{1,7},{3,7},{1,3,7}の8通りある。(23=8通り) 総和が10の場合、{3,7}が該当する。 実装は以下のようになる。以降でこの実装について解説する。

def main():  
    n, k, a, is_exist = 3, 10, [1, 3, 7], False
    for bit in range(2 ** n):  
        sum = 0  
        for i in range(n):  
            if bit & (1 << i):  
                sum += a[n - 1 - i]  
        if sum == k:  
            is_exist = True  
    print("Yes" if is_exist else "No")  


if __name__ == '__main__':  
    main()

解法

bit全探索

方針としては 1. N個の数列それぞれにビットを当てはめる 2. bit&(1<<i)でそれぞれの数列に当てはめたビットの論理積をとって足し合わせて総和が一致するかを判定 と解いていきます。

N個の数列それぞれにビットを当てはめる

仮に$N=4$の場合、全ての数列は{0, 1, 2, 3}の4つになります。このそれぞれにビットを当てはめると0は001、1は010、2は100、3は1000と置くことができます。

N個の数列の組み合わせを復元する

では総和Wが5である組み合わせを復元するにはどうするか。 以下のように数列N個全てに対して調べ上げます。

for i in range(n):  
    if bit & (1 << i):  

$N=4$,$bit=13$の場合にカウンタ変数$i$とif文の条件式の状態は以下のようになります。

i 1<<i bit&(1<<i)
0 00000001 00001101 & 00000001 = 00000001(True)
1 00000010 00001101 & 00000010 = 00000000(False)
2 00000100 00001101 & 00000100 = 00000100(True)
3 00001000 00001101 & 00001000 = 00001000(True)

総和Wが5となる組み合わせは{0,2,3}ですが、それぞれに当てはまるカウンタ変数$i$でTrueとなります。 1<<iは1(00000001)をiの分だけ左にシフトさせます。これがN個ある整数のフラグとなっています。 そしてbitとの論理積を取ると、フラグとしてシフトさせた位置のビットがどちらも1になっていれば1、どちらかが0であれば0となります。これで最初に数列の各要素に当てはめた数字を足し合わせると総和が求まり、これを全探索して終了となります。

終わりに

この方法だと計算量は$O(2N^{2})$となりあまり優秀とは言えません。動的計画法を使うと$O(NW)$に抑えられるので次はDPに挑戦です。

2022年振り返り&2023年目標

2022年振り返り

良かったこと

  • 新しい挑戦ができたこと

  • GoとGraphQL、AWSを業務で使えるようになった

改善すべきこと

  • 他がこれまでのスキルの貯金でやってるところがある

  • 特にこれといったインパクトがある実績がない(かもしれない)

    • 2.5回ほど環境が変わっているのである程度は仕方ないかもしれない(と言い聞かせる)
  • インプットとアウトプットの量と質共に減ってしまった

  • 特にAWSわからんで色々ハマってしまった

2023年目標

スキルアップ

  • 特定のスキルに集中投資する

    • Go、GraphQL、データベース、Next.js、AWSGCP
    • できたらk8sとかRustとかHaskellやりたい
  • アウトプットを増やす

    • 量は質を兼ねるの精神
    • まずは毎週からzennやっていき
    • scrapboxもいいがobsidianも活用したい
  • AWSをもっと知る

    • RSSフィードを購読するようにしたので、まずは毎週気になった内容についてscrapboxにまとめてみる
  • 英語を頑張る

    • youtubeで意図を誤らずに聴けるぐらい
    • 最終的には英語で面接を受けられるようにする
  • 女性とのコミュニケーションについて更に学ぶ

    • 彼女を怒らせる回数を今年よりも減らす
  • 個人開発しているアプリをリリースして運用・改善する

健康

  • もっと運動する

    • 最終的には週4程度で有酸素と筋トレ
    • ジムには行かないでお金をかけずに健康を維持する
  • 歯医者を月1で行く

  • アレルギー(ハウスダスト、ダニ、杉、檜)を克服

お金

ソフトウェアエンジニアになって約4年半の振り返り

彼女に書けと言われたので書きます。

そんなに推敲していないし無駄に長いので本当に暇な人だけ読んだください。

お前誰よ

インターネットではかなでという名前で細々とフリーランスでエンジニアをしています。

twitter

かなで (@py_kanade0404) / Twitter

GitHub

github.com

エンジニアとして職を得た2018年4月から4年と8ヶ月経ちました。同じぐらいの職歴の方の参考になれば幸いです。

ここに書いてある内容はresumeにもありますが、resumeに記載がない内容がたくさんあります。

github.com

結論

色々触ってできることは増えたのは良かったが、プログラミング技術それ自体や一般的な業務の進め方、相変わらずのコミュニケーションには課題感がある。

これからは実装の速度・質を高めながら、仕事の進め方を改善していき、よりその企業のビジネスに関われるようになっていきたい。

これまでの経歴

2016年~2017年

F欄大卒後、このまま就職してもブラック企業しかなさそうだなという感覚と仕事したくないというお気持ち、当時経済学(マクロの成長理論や都市・地域経済学)に興味があり院進したかったのでフリーターでパチ屋でバイトしながら他の時間で勉強をする。パチンコには興味ない。

F欄というのは2ch学歴板の「早稲田はF欄」みたい意味ではなく、真のF欄です。帝京平成大学とかネタにされるだけマシです。

2017年~2018年

院試受験

フリーターを辞めて試験勉強に集中する。TOEFLがゴミみたいな点数しか取れず、泣く泣くいくつかの研究科を諦めることに。 秋に旧帝大の研究科を3つ受験した。2つは1次試験落ち、K大は1次試験は通過したものの2次試験で落ちる。 ちなみに後日2次試験の成績を申請すれば郵送してくれるんですが、順位が定員+1で本当にギリギリで落ちてた。悔しい。

実はプランBがあったのでそちらの移行することになった。それがエンジニアへの転職だった。

エンジニア転職に向けて

勉強の息抜きに「Rによるやさしい統計学」を読んでRstudioを起動して遊んでいた。Rはもうほとんど忘れた。

www.amazon.co.jp

そこからプログラミング自体にも興味を持ち、数値計算や行列計算、機械学習関連のライブラリが充実しているという情報からPythonを触ることに。 その体験から、もし試験落ちたらエンジニアも面白そうだなと漠然と考えていた。この中にエンジニアが今ホットだとか給料が上がってるとかフリーランスとかは一切考慮になく、ただ面白そうという好奇心が根底にあったのが今に繋がっているんだと思う。

不合格が確定してからはprogateで勉強していた。当時は全部無料だった気がするのでとてもありがたかった。

prog-8.com

試験に落ちてからは就活をするために株式会社UZUZのウズウズカレッジに行くことになった。お金は結構消えてしまったので有料のプログラミングスクールに行くつもりはなかったし、プログラミング自体というよりはとにかく職を得ないといけないのでこういう選択になった。 uzuz-college.jp

最初の面談で初台に行き、カウンセラーの話を聞くことになった。プログラミングコースではJavaをやると聞いたので、帰路の途中で池袋ジュンク堂に行って「スッキリわかるJava入門」を実践編とあわせて購入してすぐ読んだ。

www.amazon.co.jp

www.amazon.co.jp

ここでJavaSQLとざっくりだけどHTML/CSSを学んで自分でWebアプリケーションをapacheで動かすことをやる。自分は2chみたいな掲示板を作ってみた。mavenとかgradleとか一切使ってないし、サーブレットなので今となってはレガシーだとは思うけど、よくわからないが動くからとRails使うよりは良いと思う。

その実装はGitHubにある。色々ツッコミどころはあるけど供養。

github.com

自分が受講した講義は多分これだと思う。多分、というのは当時は全部オンサイトでやっていたので動画を見ていない。動画を見るよりもやっぱりオンサイトの方が楽しいとは思うものの、講師としては拘束時間がきついし動画の方がスケールするので悩ましい。

www.udemy.com

ここまでを1ヶ月半でやって、移行は就活対策をひたすらやる。模擬面接をずっとやってたり志望動機を精査したりとプログラミングはそんなにやってなかったけど、自分はVagrant+VirtualBoxUbuntu環境作ってそこでPythonを入れてDjangoを動かしてHerokuにデプロイするとかをしてた。

就活は自分の場合は結構難航していた。自分は自慢ではないが当時の同期や他のメンバーと比較すると割と実力はあったとは思うが、初心者に技術とか求められないので他の側面で落ちたっぽい。なんとか1月だったと思うけど内定をもらって、移行はウズウズカレッジでチューター兼内部の仕事を手伝うので業務委託で2ヶ月ほど仕事をしていた。

3ヶ月で退職

2018年4月になり晴れてエンジニアとして入社することとなる。

会社はSESと受託のハイブリットという感じでかなり小さい。入って早々に実際の開発案件の実装をほぼ自分一人ですることになった。要件自体は難しくないけど1ヶ月後に納品する必要があり、知らないことだらけでまあまあ大変だった。

技術スタックとしてはC#PostgreSQL?とHTML/CSSでMyBatisを初めて驚いた記憶がある。Djangoは触ったことがあるがなんかXMLSQLが書いてあって何が何だかという状態だった。 全然うまく実装できなくて業務委託の中国人の先輩にめっちゃ聞いて1/4か1/3ぐらい実装してもらったかもしれない。色々とひどい実装だった気がするけど、なんとか必要な実装は終えてIIS上で動くようにできた。IISで動かすのはメンターの社員に「これ見てやってみて」とデプロイの説明書をもらったはいいが、日本語のはずなのに何を言っているのか全くわからず、これもほぼ中国人の先輩にやってもらった。

そんなこんなで最初の一ヶ月で体調は悪くなるし契約書周りで(非は向こうにあると言える)トラブルがあり、入社一ヶ月過ぎたところで転職エージェントに声をかけて転職準備をするようになった。

当然、ほぼ未経験なので転職はきついというのは共通認識としてあったが、実際は特に苦労することはなく最初に面接した会社にそのまま合格してそのまま6月を持ってスピード退職することとなった。

この退職はモダンな環境がーとかやっていることのレベルが低いだの自分が生意気だったところもあったので、自分としても反省する点が多々あった。まあそれでも辞めるが。

下積み?時代

中小SIer時代

こうしてSESをやっている企業の中ではかなり大きなIT(人売り?)企業に入ることになる。 最初の現場は登戸まで行かないといけずまあまあしんどかった。ちなみに面談でDocker使ってますか?って聞いたら「Dockerってなんですか?」と聞かれたのでこれが日本の中小SIerの現状なんだと思った。

ここでは製薬企業の試薬検査の管理パッケージの開発をしていた。 最初は帳票出力でVBAを初めて触った。なんだかよくわからなかったけど普通に実装できたので言語としては簡単なのだと思う。PythonとかJavaとかC#を使った後だとあまりにも言語として機能が貧弱すぎるて1ヶ月だけ触ったけどもう2度と触りたくないと思う。

結論から言うとここも3ヶ月で離任することとなった。最終的にはストレスによる腹痛が酷すぎてベッドから起き上がれなかったり、電車には乗れるけど手前の駅でギブアップしてそれ以上先にいけなくなるようになった。理由としては色々あるんですが

  • 要望が一切反映されていない

当時はWebをやりたいと営業には言っており、面談した時もかなり微妙そうな直感があったのでここじゃないとこにしたいですと言ったが、基本的には面談なので自分に決定権というか選択肢が無かった。もしかしたらこの業界だと当たり前なのかもしれないが、それすらも知らなかったし事前に説明は無かった。

離任時の話になるが体調が酷すぎて現場を離れたいしこのままここで仕事することはできないという話をしてもじゃあ体調が良くなったら出勤しましょう(意訳)みたいなことしか言わなかったので営業の人の頭が悪かったと思う。

自分が半分キレてやっと離任の話になり、なんとか離任する運びになった。

  • 開発環境

データベースはOracleでしたが、複数のテーブルのカラム名が特に意味を持たないID名でnullableなvarcharで統一されていた。これは複数の会社の要望に柔軟に合わせるために全てnullableにして、それぞれのカラムの意味はエクセルで管理して都度そのエクセルを参照するというものだった。SIerがよく言うの「お客様に寄り添う(笑)」の結果の賜物であり、ただ要望を横流ししてそのまま実装しているだけでプロダクトマネジメントのかけらもない。 これ以上詳細は書けないですが、今となっても本当に色々終わっていた現場だったなと思います。

ただ良かった点としては実装前にテストケースを自分で考えてレビューしてもらう工程があり、そこでソフトウェアテストについて色々調べたのが今に繋がっている気がする。

日立系列会社時代

そして営業が変わり、次の現場は日立のとある孫会社になった。この時の実質の上司の人はなんだかんだいい人だったなと思う。実際9ヶ月はいたのでエクセルスクショテスト以外はそこまで悪くはないと思う。ゆるゆるやりたい人ならあの現場はいいと思います。製作所の人もいましたが皆さん優秀でした。

ここではJava8とAngularJS1.x、HTML/CSSPostgreSQLで社内Webアプリケーションを開発していた。具体的な年齢は聞いてなかったけど齢70を超えているであろう協力会社のおじいちゃんエンジニアがいて、めっちゃシステムに詳しくてプロパーの偉い人が挨拶に来てた。そのおじいちゃんに言われて画面描画完了まで10秒かかるところを3秒以内に改善したりテストでかなりやばいバグを発見したりと一応進捗はしていた。

ゆるゆるやるならこれでもいいとは思うが、ここにいてもプログラミングはできるだろうが自分でできる範囲が狭かったりPublic Cloudを触ることは難しいと思うので転職をすることとなる。

ちなみに個人ではDjango触ったりフロントエンドでAngularやVueを触るなどしていた。この頃はほぼ外に遊びに行くことはなく、ひたすらプログラミングするかちょっとハースストーンするぐらいだった。この頃のようなハングリーさが欲しい。

これが異世界転生ですか?

転職先となる前職は5月ごろにGreenで連絡が来ていた。当時はディレクター is 何だったりWeb制作ってなんぞと言う感じだったが、技術ブログを読んで面白そうだったので何度か面接を受けて6月に内定をもらった。

最初に内部の細々としてことをやって10月から実案件に入ることになる。

実践Webアプリケーション開発

某外コンの案件で新規でWebアプリケーション開発をする。技術スタックはLaravel+MySQL+Vue+Azureといった感じ。Azure以外は普通。

新規実装でCRUDはもちろんのこと、Laravelの認証middlewareを要件に合わせてカスタマイズしたりBackendのリファクタリングテスト駆動開発の導入、FrontendのSP対応とSPデザインをFigmaで作ったりとなんでもやっていました。

ちょっとプロジェクトの雲行きが怪しくなってきたと言うことでアサインされました。結果としてはPoCは通過して自分が離任後に正式にリリースされました。

本件を通じてテスト駆動開発とソフトウェア設計は重要だよねと言うことを再確認できたと思います。 特にFrontendはBackendと違ってFrontend独自の複雑性があり、そこはうまく対応できずかなりお粗末な設計・実装になってしまったなと反省しています。Vuexをどこで使うか、副作用の取り扱い、コンポーネントの責務の切り分けなど今でも難しいなと思っています。一般的なWebアプリケーションのBackendの複雑さの関心は主にビジネスロジックにあると思いますが、Frondendはそれ自体の複雑さが主となっているように思えるのでBackendのようにはいかないのが難しい。

炎上の火消し

2019年初めに上記の案件から一瞬離れて絶賛炎上しているフロントの案件に入ることとなりました。nunjucksを使ってましたがもう一生使うことはなさそうです。

Nunjucks+JavaScriptでFrontendのみリニューアルをすると言うものでした。Frontendだけリニューアルなので、BackendのAPIがHTMLを返すのでそれを描画すると言う謎仕様そのままでした。

ひたすらJavaScriptで検索周りの画面のロジックを実装していました。一応既存実装はあったのですが、チェックボックスの全選択を実行するとチェックボックス全てで都度イベントが発火するので、チェックボックスの数の分だけAPIが叩かれると言うやばい実装になっており、これの作り直しでした。

よく終電近くまでやっていましたが、ある種お祭り感もありそこまでしんどさは無かった気がします。同じことをしたいかで言えばしたくはないですが。。。

みんなで頑張って実装していき、なんとか形になりました。ここでJavaScriptに少し詳しくなりました。

久々の常駐と新規DMP開発

2021年になり、とある美容系広告代理店のエンジニアとして久々に常駐して業務することとなりました。

技術スタックはTypeScript+MySQL+Next+Express+GCPといった感じで既存メンバー二人がFrontendあがりなのでTypeScriptに統一しています。

主に新規DMP開発と先方の新卒社員の育成を行いました。

当初は社内の広告のコスト監視ツールの開発でしたが、ITP対応やiOS14対応と合わせてFacebook Conversion APIを使った広告サーバ件DMPの新規開発を任されることとなりました。現在では主力事業に成長しています。

ビジネス的には開発して離任するまでに10社のお客様に導入していただきました。 導入に関してもコンサルの方と連携して導入サポートをしていきました。

技術的には初めてGCPをフルに使ってのインフラ構築とTerraformでのIaCを実現しました。一部terraform化できなかったリソースがありますが、主要な部分はまあまあ管理できていると思います。

テストコードも合わせれ実装するようにして、テストを書くと言うことを当たり前にしていきました。結果として、顧客影響のある障害は0を達成しました。(唯一、core web vitalsのメトリクス取得でミスってタグ内でエラーで計測に一部失敗していました)

また新卒教育ですが、JavaScriptをベースにWebの基本的なところを抑えてもらって、実際に社内アプリケーションの開発をしてもらって実案件に入ってもらう流れで進めました。 最初はPCの電源の付け方もわからなかったですが、最終的には自力でpuppeteerを使ってFacebookの広告管理画面の2段階認証を突破して業務の自動化をいい感じにやってくれるようになり、離任時はプロジェクトを任せられるほど成長して良かったです。彼ら・彼女らの努力はもちろん、スタンスが素晴らしかったと思います。

前職で最も成長できた期間だったなと思います。

そして退職

その後、会社の方針と自分のキャリア方針、ビジネスとの協調などに課題感を感じて退職しました。

退職はしていますが、筋の良いジュニアのエンジニアがこれからスキルをもっと伸ばしていくという観点でオススメできると思っています。

事実として入社前では無理であろうさまざまな経験を積むことができました。そういった点で、まさにこの転職は異世界転生だったということでした。

技術的には言わずもがなですが、勉強会を個人的に開催したり採用系の業務を行うようになり自律性の向上を感じます。

フリーランス

退職後は次を見据えて業務委託として各社でお手伝いさせていただいています。あまり触ることが無かったAWSに触れたり実業務で使いたかったGolangを使う、これ以上ないほど酷いReactコードをリファクタリングしてTypeScript化をするなど様々なことをしています。

業務をしながら、最終的には「ここしかあり得ない」と言える企業に入るために準備をしています。

次のステップへ向けて

結局何ができて何ができない(改善しないといけない)のかを考えました。

できること

Backend

GolangとTypeScriptとPHPPythonは特に不自由しないと思います。他の言語だとちょっとキャッチアップが必要かもです。

テストコードを当たり前と思って実装します。

設計はちゃんと検討したいと思っており、それなりにはレイヤードアーキテクチャの話が通じます。(ただ最近はレイヤードアーキテクチャ的なアプローチが果たして有効なのかに疑問を持っており、詳しい方に見解を聞きたいです。)

GraphQLもわかります。

Frontend

最近はずっとReactあるいはNextですが、本職のFrontend Engineerよりは劣ると思いますがコンポーネント作成とかstate管理、Storybookやテストはそれなりにはできるつもりです。E2Eもplaywrightで実装した経験あり。

Infrastructure

インフラはGCPでそこそこのWebアプリケーションとデータ基盤の構築はできると思います。

具体的にはCloud RunにLoad Balancer立ててVPC内にCloud SQL用意して、Pub/SubとかDataflowを使ってBigQueryにデータを流し込むパイプラインを作れます。

terraformも1サービスの過半数のサービスを管理していたので、GCPなら不自由しない印象です。

業務一般

組織の課題を吸い上げて自分で解決に向けて実行します。

コミュニケーションは得意ではないですが、前職のマネージャーからは入社時と比べてかなり改善されたと言われたので問題があるという認識もないです。

またいつも同じようなテンションなので、あまり自分の上機嫌・不機嫌が表に出ない

その他

また採用とエンジニア育成に携わってきたので、それらでも貢献できそうです。

多少ですが広告の知識はあります。(用語を言われたら理解はできる)

できないこと

Backend

マルチスレッド処理は得意ではないです。goroutineやchannelは使えますが、シュッと実装できるほどではないです。

アルゴリズムに苦手意識があります。某企業のコーディング面接でダイクストラ法をソラで実装する問題がありほぼ手も足も出なかったという苦い経験があります。(そう指示された訳ではないが問題の解放として一番スマートなのがダイクストラ

DDDとか読み込んでいるわけでもなく、アーキテクト的な業務をやったことがあるわけでもないので要件定義・基本設計のレイヤーはまだ得意じゃなさそうです。

パフォーマンス改善もあまりメトリクスをしっかり測定して何かを改善するという経験が無いです。

Observabilityについても基本新規開発ばかりであまり知見がないです。DataDogとかOpenTelemetryとか知ってるけど使ったことない状態。

Frontend

CSSとかHTMLも全体的に理解が浅いです。マークアップ周りは今後頑張りたいかと言われたら直近ではそうでもないですが。

もうあまりやらないかもですがwebpackの設定とかは全然わからないです。

あとReactのuseMemoとかuseCallbackあたりはあまり使いこなせてないです。

SEOはわからない。

パフォーマンス改善も経験ないです。

Infrastructure

k8sはほぼ触ったことないです。

クラウドネイティブ周りも名前聞いたことあるとかちょっと知ってるけどあまりわかってないものが多いです。

AWSもそんなに詳しくないですが現在は少しずつ業務で触っていて目下勉強中です。Azureもちょっと業務で使ったぐらいです。

業務一般

助けを求めるのが苦手です。

あとは相手が話している言葉の含意を汲み取るとか期待されている言動が何かを理解して動くことが苦手です。(twitterでイーロンマスクに噛み付いた某androidエンジニアとかはこの点で自分に近いものを感じました)

英語は4技能全て苦手です。

これからやるべきこと・やりたいこと

業務

一般

直近で言えば業務知識をつけることです。直近では広告業界にいるのでWeb広告やマーケティングについてもっと勉強する必要があります。 他では気になる領域としては採用・人事評価や決済周りは気になります。

将来的にはマネジメント系をやることがあるかないかは分かりませんが、相互理解のためにも組織マネジメントについて勉強したいですね。

この手の書籍はたくさんありますが、EMについてなら「エンジニアリングマネージャーのしごと」とか

組織論であれば「TEAM OF TEAMS」とかになるのかなと思っています。

Backend

現状メインはGolangですがそこまでこだわりはないです。ただTypeScriptでもKotlinでもいいですが、LL言語はもういいかなと思います。(型によるある程度の動作保証のありがたさはその辺の単体テストよりも重要だと考えているので) 大規模開発の経験をすることが直近の課題です。ここで言う大規模開発とは、あるサービス・プロダクトの利用者数やトラフィックが膨大であることを指します。(何を持って膨大とするかは諸説ありますが。。。)

マイクロサービスについてはそこまでこだわりはないです。マイクロサービスが重要ではなく、正しく理由があって且つ適切なサービス境界で分割できていることが重要なので。

Frontend

こちらはそんなに力を入れているわけではないので特にはないですが、メインはNext.jsを触れるといいのとCDN周りはもう少し勉強したいですね。(最近だとcloudflare、特にD1が熱かったりする)

www.cloudflare.com

Infrastructure

どうせGCPはそこそこ(めっちゃではない)わかるのでAWSをちゃんとやっていきます。GCP好きなんですがやはりマジョリティーAWSなので、AWSも現状のGCPの知識ぐらいあるなら多分クラウドボトルネックになることはないだろうという判断です。

そして前職までの課題であった監視・運用もしっかり携わっていきたいですね。自分で理由づけをして監視戦略・運用戦略を立てられるぐらいを2年のうちに目指したいです。

Others

細かいですがエンジニアの定量的な評価しづらさに課題感があり、four keysを計測したりインフラコストの可視化などは取り組んでいきたいです。

トランクベースの開発もどのぐらい効果があるか試してみたい気持ちがあります。

個人

アルゴリズムを勉強します。LeetCodeで言うとeasyの50%未満の問題もサクッと解けるぐらいをまずは目指したいです。

並行処理・並列処理をもっとこなれるようにしていきます。

アプリケーション設計について「ソフトウェアアーキテクチャの基礎」「ソフトウェアアーキテクチャ・ハードパーツ」を読みます。

個人で密かに開発しているWebアプリケーションをまずはリリースします。できたらFlutterでネイティブアプリを作るのもよいかもしれないです。

英語を勉強し直して、2年後には英語でのコミュニケーションを業務でできるようになります。色々なところで英語の需要が年々高まっていると言うことを聞いているので、流石にそろそろ英語に本腰入れる時期かなと思いました。

あと運動の習慣と早起きを習慣づけます。

終わりに

個人的には4年以上経った割にはあまり大したことができてないなと言う印象を受けました。。。

キャリアが安定したことで昔のようなハングリー精神が削がれてしまっているかもしれません。(一概に悪いとは言えませんが)

先の2・3年を見たらやらないといけないことはたくさんあるので、またやるべきことと優先順位を整理した上で次の振り返りで満足できるように結果を出していきたいですね。

monorepoでのhusky+lint-stagedとlefthookと比較

monorepo環境でのgit hooksの管理でどう設定するのがいいのか、まとまった資料はなさそうなので書き記します。

以降はhuskyとlint-staged、lefthookについては知っている前提です。 知らない場合はざっくり説明すると

husky → git hooksを管理するライブラリ

lint-staged → gitのstagedなファイルに対して任意のコマンドを実行できるライブラリ

lefthook → go製のgit hooks管理ライブラリ

github.com

github.com

github.com

個人的には後述する理由からlefthook推奨です。

前提

バージョンは以下のとおりです。

husky: 8.0.1
lint-staged: 13.0.3
lefthook: 1.1.1

また、今回はgoとnext.jsのアプリケーションが横並びである状態を想定しています。

$ tree -L 1
.
├── go
└── next

目標は、commit時に各アプリケーションのファイルごとに特定のコマンドを実行するようにします。 jsやts、tsxファイルなどに対してはeslintやprettier、goファイルに対してはgo fmtやgolangcil-intを実行します。

husky+lint-stagedでの設定

まずroot directoryで以下コマンドを実行します。

# package.jsonを作成
yarn init
# 依存ライブラリをinstall
yarn add -D husky lint-staged
# package.jsonにhuskyの初期化コマンド追加
npm set-script prepare "husky install"
# huskyの初期化
yarn prepare
# git hooksにpre-commit時のコマンド
yarn husky add .husky/pre-commit "yarn lint-staged"

これでcommit時にlint-stagedが実行されます。

ではアプリケーションごとに実行アプリケーションごとに実行させるには各アプリケーションのディレクトリごとに.lintstagedrcを追加します。

# root/next/.lintstagedrc.js
const path = require('path')

module.exports = {
  '*.{js,ts,tsx}': (absolutePaths) => {
    const cwd = process.cwd()
    const relativePaths = absolutePaths.map((file) => path.relative(`${cwd}/next`, file)).join(' ')
    return [`eslint ${relativePaths}`, `prettier --write ${relativePaths}`]
  },
}
# root/go/.lintstagedrc.js
module.exports = {
    "*.go": "go fmt"
}

これで各アプリケーションごとにcommit時に指定したコマンドが実行されます。 pushとコマンドを分けたい場合は別名でconfigファイルを作成して-cオプションで指定すれば良いです。

lefthookでの設定

lefthookはnpmのpackageはdeprecatedになっているため、macであればhomebrew経由やgoバイナリをdownloadするのが良いです。

www.npmjs.com

lefthookをdownloadしたら以下コマンドを実行してlefthook.ymlを作成します。

lefthook install

そしてpre-commitに実行したいコマンドを追加します。

rootにアプリケーションのディレクトリを指定することで、そのディレクトリからコマンド実行とファイルパスの解決をしてくれます。 {staged_files}でstagedなファイルの全件を半角スペース区切りで渡してくれます。

pre-commit:
  parallel: true
  commands:
    eslint:
      root: 'next/'
      glob: '**/*.{js,ts,jsx,tsx}'
      run: yarn eslint {staged_files}
    gofmt:
      root: 'go/'
      glob: '**/*.go'
      run: go fmt {staged_files}

そしてpre-commit設定を追加します。 lefthook add pre-commit

これでcommit時に各ファイルに対して任意のコマンドを実行してくれます。

どちらが良いか

lefthookのwikiにも記載がありますが、以下の理由から自分はlefthookを推奨します。

  • huskyはNodejsランタイムが必要だがlefthookはシングルバイナリのみで動く
  • huskyは並列実行できないがlefthookは並列実行可能
  • lefthookは一つの設定に集約可能
  • lefthookはgit hooks管理ライブラリではなくタスクランナーの側面もあるので適用範囲が広い

github.com

4番目は私見ですが、commitを契機とするタスク実行をしてくれるライブラリなのでhusky+lint-stagedよりも適用範囲は広いと思います。 任意のscriptを実行でき、dockerにも対応しているのでそもそもできることの幅がhusky+lint-stagedとはだいぶ違うという認識です。

終わりに

どちらでも基本的なmonorepoでのpre-commitの設定はできることがわかりました。

husky+lint-stagedがデファクトスタンダードですが、まだ使ったことが無い方はlefthookの導入も検討してみてください。

新規プロジェクトでとりあえず入れるライブラリ・サービス

自分が新たにリポジトリを作るときにある程度デフォルトでいれているライブラリやサービスを書き残します。

Docker

説明は不要。ライブラリ開発なら要らないかも。

www.docker.com

GitHub Actions

基本GitHubを使っているので、特段の理由が無ければGitHub Actionsを使用。

今日のソフトウェア開発においてCI/CDは当たり前であり、プロジェクト初期から入れる方がレバレッジが効く。GitHub以外なら他のサービスをよしなに使います。(CircleCI、Gitlab CI、etc...)

github.co.jp

lefthook

git hookを管理するツールです。 github.com

一般的にはhuskyが有名だと思いますが、

The fastest polyglot Git hooks manager out there とあるように、最速を謳っています。

他にもhuskyとの差別化について書いてます。

github.com

個人的な見解としては速度もそうですが

  • huskyはdockerとの相性が悪い
  • nodejsとhuskyを入れる場合はlint-stagedと原則セットになるのが煩雑

secretlint

secretlintはcommitしてはいけない秘匿情報を含んだファイルのチェックを行うライブラリです。 github.com

JavaScript Primerのauthorだったりtextlintの開発者であるazuさんが開発しています。ご本人による解説はこちら。 efcl.info

秘密鍵やPublic Cloudのsecret keyなど、誤commitされるケースは少なく無く、そのままpushされて最悪は悪用されることがよくあります。悪用されれば金銭的な被害のみならず、事後対応やレピュテーションリスクに晒されることになる可能性があります。

secretlintは割と他に代用できるツールが無いのにあまり広まってない感覚があるので、特にアプリケーション開発ではlefthookとセットで入れるのをおすすめします。

actionlint

GitHub前提になってしまいますが、GitHub Actionsのyamlを静的解析してくれるライブラリです。

github.com

ご本人の解説はこちら rhysd.hatenablog.com

GitHub Actionsの構文解析をpushして怒られてからではなく、手元で確認できます。 説明にも書いてあるように本体側でのチェックが緩いこともあり、かなり細かく見てくれるのでありがたいです。

これで後はCircleCIみたいにローカルで確認できれば...

renovate

renovateは自動でライブラリや他依存関係のアップデートの修正チケットを作成してくれるライブラリ及びWebサービスです。

github.com

GitHubであればGitHub Marketplace経由で無料で有効化でき、以降は自動でPRを作成してくれます。

またself hostingもできるのでオンプレ運用できたり、ライブラリとしても提供されているので他の定期実行できるツールと合わせて利用することができます。

ライブラリのアップデートは全て手動で行うのはそれなりの時間を取られてしまうので、renovateでCIがpassしたら自動mergeするようにすることで運用コストを大幅に削減できる可能性があります。

設定も非常に細かく適用できますが、まずはデフォルトの設定から入れるのが良いかと思います。

3/24

本来は有給のはずなのに仕事している。どうして...

今日はずっとHTMLとCSS(SCSS)の修正で一日が終わった。恥ずかしながらdialog要素を初めて知りました。マークアップは初心者なので。

プライベートはpuppeteer辛みを感じるのでchromedpを試している。

github.com