Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
エンジニア達の_完全に理解した_-コードでの契約ってなんだ_.pdf
Search
ツノ
June 25, 2024
210
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
エンジニア達の_完全に理解した_-コードでの契約ってなんだ_.pdf
ツノ
June 25, 2024
More Decks by ツノ
See All by ツノ
Vite完全に理解した その1
2nofa11
2
310
年末年始に「chibivue」で Vueヂカラをつけた
2nofa11
0
290
「世界一流のエンジニアの思考法」 を完全に理解した
2nofa11
1
340
書籍「プログラマー脳」を完全に理解した
2nofa11
0
89
VuexからPinia移行に向けて
2nofa11
0
460
一か月半かけて、TypeScript本を写経した話
2nofa11
0
880
VueTestUtilbrのキホンの『キ』
2nofa11
0
180
Featured
See All Featured
How to Think Like a Performance Engineer
csswizardry
28
2.7k
Designing for Timeless Needs
cassininazir
1
440
VelocityConf: Rendering Performance Case Studies
addyosmani
332
25k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.9k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
Speed Design
sergeychernyshev
33
2k
Side Projects
sachag
455
43k
The agentic SEO stack - context over prompts
schlessera
0
860
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.7k
Paper Plane
katiecoart
PRO
2
53k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.4k
Transcript
コードでの契約ってなんだ? ツノ
自己紹介 ツノ BtoB Saasのフロントエンドエンジニア 銭湯とサウナを愛する20代 「完全に理解した」Talkは4回目 過去のIT 書籍「プログラマー脳」を完全に理解した 「世界一流のエンジニアの思考法」を完全に 理解した
Vite完全に理解した Xの最近の投稿 ツノ @2nofa11·Follow やっぱり風呂だよ、風呂。あとサウナ。 10:55 PM · May 11, 2024 2 Reply Copy link Read more on X
LTの内容 読んだ本のアウトプット Good Code,Bad Code ~持続可能な開発のための ソフトウェアエンジニア的思考 本の概要 コーディングプラクティスの紹介本 メンタルモデル
具体的なHow 1年間近く積読していた LT駆動読書で読みました!
本題 📕
👦全人類「Goodコード書きたい 🔥」 Goodコード=高品質なコード
👦全人類「どうやって書けばいい? 🤯」
👨Tom Long「6つの柱を実践すればいい 👼」 Tom Long=著者。Googleでテックリード。
コード品質の柱 高品質なコードを書くための戦略として挙げられている6つの柱 1. 📖 : コードを読みやすくする 2. ❗️ : 想定外の事態をなくす
3. 👌 : 誤用しにくいコードを書く 4. 🤖 : コードをモジュール化 5. ♻️ : コードを再利用、汎用化しやすくする 6. ✏️ : テストしやすいコードを書く
柱の詳細(今回は2つのみ) ❗️ : 想定外の事態をなくす あるタスクをこなそうとした時に、想定外が起きることは悪いこと 例:レストランの注文で「マルゲリータ 🍕」と「マルガリータ 🍸」の注文は間違えやすい 👌 :
誤用しにくいコードを書く これをしないと作成者が想定していない利用方法で使われる 例:テレビの電源ケーブル 📺とHDMIケーブル 🖥は形が違うので誤用しようがない この2の柱を実現するために「コードでの契約」が必要!
ようやく本題「 『コードでの契約』だ 🧗♀️」
コードでの契約とは コードで他のエンジニアに、関数の使い方やどう言う挙動が期待できるかを伝えるメンタルモデル コード間で契約を結んでいるような世界観 呼び出し元は特定の義務を果たし、対価として呼び出したコードで値の取得や状態を変更できる
コードの契約:契約の中の細則 コードでの契約というメンタルモデルを頭に入れると、 「契約の中の細則」もコードの世界に落とし込める # 例:レンタサイクルのアプリ - 明確な契約 - レンタサイクルを借りられる -
レンタル費用は150円/時 - 契約の中の細則 - 時速30kmを超えた場合は罰金5000円が発生する※ ※利用者が意識して監視する必要がある (速度を抑制する機能がついていない) # 例:実際のコード - 明確な契約 - 関数とクラスの名前 - パラメーターの型 - 戻り値の型 - 契約の中の細則 - コメント - ドキュメント 言いたいこと 「契約の中の細則」は落とし穴のようなものになりがち → できる限りコードでの契約に寄せるべき
それでは、実際のコードを見てみよう 🤺 TypeScriptで記載しています
まずは、 「 ❗️想定外の事態をなくす」について
その1
マジックバリュー(固定値)を戻り値に使わない 例:ユーザーに関する情報を保存するクラスがあった場合 🙅 BadCode 🙆 GoodCode コードの作成者とレビュアーはこの動作を確認してい るはずだが 新規開発者が平均年齢を出す処理を getAge()
を使っ て実装を行う場合バグる 呼び出し元でnullが来ることが検知でき、 新規開発者が落とし穴があることが把握できる class User { private age = null getAge():number{ if(this.age === null){ return -1 // 入力がない場合は-1を返す } return this.age } } class User { private age = null getAge():number | null{ if(this.age === null){ return null } return this.age } }
その2
呼び出し元を意識したnullオブジェクト利用を心がける 例:HTMLの class を見て強調しているか確認しているコード 🙅 BadCode 🙆 GoodCode getClassNames でnullが帰ってくる
→呼び出しもとでnullチェックを 呼び出し元のコードがスッキリした function getClassNames(element: HTMLElement): Set<string> | const attribute = element.getAttribute("class"); if (attribute === null) { return null; } return new Set(attribute.split(" ")); } function isElementHighlighted(element: HTMLElement): boolea const classNames = getClassNames(element); if (classNames === null) { // 使用まえにnullチェック return false; } return classNames.has("highlighted"); } function getClassNames(element: HTMLElement): Set<string> { const attribute = element.getAttribute("class"); if (attribute === null) { return new Set(); } return new Set(attribute.split(" ")); } function isElementHighlighted(element: HTMLElement): boolea // null値チェックの必要がない return getClassNames(element).has("highlighted"); }
その3
将来的にも有効に使えるように列挙型処理を利用する 例:列挙型の条件分岐(下のコードに新しい列挙 Top が追加された場合) 🙅 BadCode 🙆 GoodCode コンパイルエラーを検知できない コンパイルエラーを検知できる
実装時にエラーに気づくことができる const Position = { Right: 0, Left: 1, } as const; type Position = (typeof Position)[keyof typeof Position]; // 上は type Position = 0 | 1 と同じ意味になります function toJapanese(position: Position) { if (position === Position.Right) { return "右"; } return "左"; } const Position = { Right: 0, Left: 1, } as const; type Position = (typeof Position)[keyof typeof Position]; // 上は type Position = 0 | 1 と同じ意味になります function toJapanese(position: Position) { switch (position) { case Position.Right: return "右"; case Position.Left: return "左"; } }
次に、 「 👌 : 誤用しにくいコードを書く」について
その1
全てを不変にする(ことを検討する) 例:フォント情報を保存するクラス 🙅 BadCode 🙆 GoodCode fontFamily が呼び出し元で書き換えられる fontFamily が
ReadonlyArray なので不変 安心して使えるね class TextOptions { constructor( private fontFamily: Font[], private fontSize: number ){} getFontFamily(): Font[] { return this.fontFamily; } getFontSize(): number { return this.fontSize; } } class TextOptions { constructor( fontFamily: ReadonlyArray<Font>, private fontSize: number ) {} getFontFamily(): ReadonlyArray<Font> { return this.fontFamily; } getFontSize(): number { return this.fontSize; } }
その2 ⭐️最後 ⭐️
汎用的なデータ型は避ける 例:地図上に指定位置をマークするメソッド 🙅 BadCode 🙆 GoodCode class LocationDisplay { private
readonly map: DrawableMap; /** * 与えられたすべての座標の位置を地図上にマークする * * リストのリストを受け入れる。内部のリストには正確に2つの値が含ま * 1番目の値は緯度、2番目の値は経度 (両方とも度) */ markLocationsOnMap(locations: Array<[number, number]>): for (const location of locations) { this.map.markLocation(location[0], location[1]) } } } /** 緯度と経度を度数で表す */ class LatLong { constructor( private readonly latitude: number, private readonly longitude: number) {} getLatitude = () => this.latitude; getLongitude =() => this.longitude; } } class LocationDisplay { private readonly map: DrawableMap; markLocationsOnMap(locations: LatLong[]): void { for (const location of locations) { this.map.markLocation(location.getLatitude,loca } } } 契約の中の細則(コメント)でカバーしようとしている 何を表しているかが明確なため誤用を避けられる
まとめ 高品質なコード(GoodCode)を書くには 6つの柱を満たす必要がある 今回は「 ❗️ : 想定外の事態をなくす」 、 「 👌
: 誤用しにくいコードを書く」を特集した コードでの契約 上記2つを達成する戦略として、コード上で縛りを入れる 具体例 マジックバリュー(固定値)を戻り値に使わない 呼び出し元を意識したnullオブジェクト利用を心がける 将来的にも有効に使えるように列挙型処理を利用する 全てを不変にする(ことを検討する) 汎用的なデータ型は避ける
None