Slide 1

Slide 1 text

良いコードとは パーソルキャリア株式会社 テクノロジー本部 エンジニアリング統括部 サービス開発部 ※本資料は2023年3月時点の情報であり、2023年新卒の研修教材です。

Slide 2

Slide 2 text

この研修では手を動かす内容はありません。 良いコードの初歩的な部分の説明なので気楽に聞いてください。 この研修について

Slide 3

Slide 3 text

目次 ● 良いコードとは ● コードを読みやすくする ● おまけ

Slide 4

Slide 4 text

良いコードとは? ● 保守性が高い ● 正確に動作する ● 無駄な部分がない ● 効率的に動作する などなど 縣 俊貴.『良いコードを書く技術── 読みやすく保守しやすいプログラミング作法』. 技術評論社.2021年,24p

Slide 5

Slide 5 text

将来的な修正や保守作業を容易にするために設計された、読みやすく理解しやすく、 変更が容易で堅牢なコードのこと 実際は複数人で開発するため、他人が読んでも理解できるようなコードを書く 数ヶ月後の自分が読んでも理解できるコードを書こう 保守性が高い

Slide 6

Slide 6 text

”確実に動作し、信頼性が高いことは良いコードの条件です。” ”良いコードは防御的で、不測のバグを生み出しにくい作りになっています。” 正確に動作する 防御的プログラミング 「正常な値が来るはず」という決め付けをせずに、不正な値が来ても被害を受けないように防御 的にプログラミングを行うこと 防御的コードが過剰に存在するのも問題で、型による制限など不正な値がそもそも存在し得ないような制約 を設けることも検討する。言語やフレームワークの機能も適切に利用する。 縣 俊貴.『良いコードを書く技術── 読みやすく保守しやすいプログラミング作法』. 技術評論社.2021年,24p

Slide 7

Slide 7 text

”無駄がないコードは理解するのも修正するのも簡単で時間がかからないため、 良いコードと言えます。” 無駄な部分がない ● ロジックがシンプル ● 無駄な重複コードがない 縣 俊貴.『良いコードを書く技術── 読みやすく保守しやすいプログラミング作法』. 技術評論社.2021年,24p

Slide 8

Slide 8 text

”良いコードは適切なパフォーマンスで動作する。 似たような実装がいくつか考えられるとき、あきらかに効率の悪いものを選択する 必要はありません。良いコードは適切なパフォーマンスで動作します。” 効率的に動作する 賢いアルゴリズムが本当に必要なのか実証的に見極めるのが大事です。大概はシンプルさが勝る。 必要かどうかはパフォーマンスとの相談。 この研修ではここには触れません。 縣 俊貴.『良いコードを書く技術── 読みやすく保守しやすいプログラミング作法』. 技術評論社.2021年,24p

Slide 9

Slide 9 text

他に良いコードと言われて浮かぶもの ● 誰でも簡単に理解できるようなコードであること(可読性) ● 新しい機能を追加することが容易であること(拡張性) ● セキュリティが確保されている ○ 潜在的な脆弱性がないこと 簡単に言えば、 読みやすくて、理解しやすくて、修正しやすいコード ● コードスタイルの一貫性を確保する ● コードの中に「後でやる」「要修正」などの コメントが存在しない ● 変数名やコメントのルールが一貫している

Slide 10

Slide 10 text

良いコードだと何が良いの?

Slide 11

Slide 11 text

良いコードの価値 継続的かつ迅速にユーザーに価値を届けられる! ● 人が入れ替わっても理解しやすい ● 機能変更に強い ● 修正工数がかからない ● バグを生みづらい エンジニアとしては ● エンジニア信頼性が上がる ● 満足感・達成感がある

Slide 12

Slide 12 text

悪いコードだと(開発現場でよくあること) ● コードを読み解くのに時間がかかる ○ 簡単だと思っていた仕様変更やバグ修正に何日も費やす ● バグを埋め込みやすくなる ○ どこかのコードを変更したら別の箇所でバグが発生 ● 変更の影響がありそうな箇所を探し回る

Slide 13

Slide 13 text

なぜ良いコードを書くべきか ● 現場ではチーム開発することが基本 ○ コードを読まれることの方が圧倒的に多い ● リリースが遅れて機会を逃す ● バグが多いサービスはユーザーが離れる

Slide 14

Slide 14 text

コードを読みやすくする

Slide 15

Slide 15 text

意味不明なネーミング ● 意図が全く読み取れない ● 読み解くのに時間がかかっ て、中途半端に変更してバ グに繋がる 連番命名 意図がわかる名前を使う

Slide 16

Slide 16 text

意図がわかる名前を使う 縣 俊貴.『良いコードを書く技術』. 技術評論社.2021年,58p

Slide 17

Slide 17 text

良い名前の条件 短すぎず、長すぎず、説明的で意味・意図を表現している変数名、メソッド名、 クラス名は、名前がその中身を正しく表現していて、名前を見るだけでその役割 を理解できる。 良い名前はコードの理解がしやすいが、悪い名前は読む人を混乱させて、勘違い を生み、バグの発生につながる。

Slide 18

Slide 18 text

意図がわかる名前を使う 何の計算なのかわからない

Slide 19

Slide 19 text

コメントで対応するのは不適切 コメントやドキュメントを追加するのも改善方法の一つだが、かなり乱雑な コードになるので良くない。

Slide 20

Slide 20 text

名前をわかりやすくする 変数の意味がコードだけで分かるのでコメントも不要

Slide 21

Slide 21 text

コメントは適切に使う 書きすぎないこと。基本は書かない方が良いです。 ● ロジックの内容を説明するだけのコメントはしない ● メソッド名をわかりやすくするなど、ロジックを理解しやすいようにした方が良い コード理解の助けになる場合に書くと良いです。 これは良くないパターン (見ればわかるロジックをただ説 明しているだけ)

Slide 22

Slide 22 text

必要なコメントは書こう コードだけでは意図がわからない場合はコメントしておくと良いです。 ● なぜこの分岐を作らないのか、なぜこういう計算をしているのか ● ライブラリのバグなどで特殊な対応をしている場合 ● 難しい前提知識が必要な場合 @t_wada, https://twitter.com/t_wada/status/904916106153828352, 2017年9月5日

Slide 23

Slide 23 text

ドキュメントコメント TypeScriptでは型情報を記載できるので、わざわざJSDocコメントに型情 報を記述する必要はないです。(jsでは有用)

Slide 24

Slide 24 text

名前は基本的に省略しない 昔は省略することが多かった(諸々の制約があり、そもそも言語仕様で長い変数 名が許容されなかった)が、最近はエディタの入力補完などもちゃんとしてるの で、省略しない方が良いです。 for文のi, j, kや例外のeなど、慣習的でプログラマなら理解できる場合、むしろ省 略することもある。

Slide 25

Slide 25 text

名前に一貫性があるとよい ● 対称性を保つ ○ begin/end、write/read、on/offなど ● 単語の組み合わせ方を一貫させる ○ scoreAvg、scoreAverage、avgScoreなどを同時に使用しないなど

Slide 26

Slide 26 text

英語で命名されていること ● 和製英語を使わない ● スペルミスに注意 ● 誤訳に注意 VS CodeならCode Spell Checkerのようにタイポを発見してくれるツールもある 昔見たことあるのは、記事が保存さ れるテーブルで、名称はkijis

Slide 27

Slide 27 text

メソッド名の名前について 良いメソッド名は、名前から機能が想像できる。 逆に名前から想像できないことはしない。getterであれば、副作用はあってはい けない。 メソッドは処理を行うので、メソッド名は「動詞」または「動詞」+「目的語」 になっていることが多い。

Slide 28

Slide 28 text

変数の使い回しをしない コードの途中で変数の用途が変わってしまい、読み手が混乱してバグを埋め込ん でしまう可能性がある

Slide 29

Slide 29 text

変数の使い回しをしない それぞれの用途にあった、変数を都度定義する ≒変数のスコープを可能な限り狭くする

Slide 30

Slide 30 text

関数化する 計算ロジックをダラダラと書くと、どこまでが何の処理なのか分からなくなってくるため、 小さな関数を組み合わせることによって、表現がわかりやすくなる。

Slide 31

Slide 31 text

種類の異なる処理をそれぞれ関数として分離したことで、違う処理が紛れ込みにくくなり、 複雑な処理も理解しやすくなりました。 関数化の目安は画面に収まりきる程度、30行程度が目安になるのではないかと思います。 (処理の内容によるが・・・) 関数化する

Slide 32

Slide 32 text

スコープって何? プログラミングにおけるスコープ(英:scope,可視範囲)とは、変数や関数などを参照できる 範囲のこと。通常、変数や関数が定義されたスコープの外側からは、それらの名前を用いる だけでは参照できない。このときこれらの変数や関数は「スコープ外」である、あるいは 「見えない」といわれる。(Wikipedia) スコープ=見える範囲=使える範囲=依存する範囲=保守性に影響を与える範囲 = スコープ狭い方が良い スコープ_(プログラミング) . Wikipedia. https://ja.wikipedia.org/wiki/スコープ_(プログラミング)

Slide 33

Slide 33 text

スコープが広い例(NG) グローバルスコープの例 グローバルスコープにxを定義して、foo関数内でxを参照 して、bar関数内でxを再定義しています。 foo関数はその関数自身のスコープでxを定義していない ため、スコープチェーンを使用してグローバルスコープ からxを参照するので、bar関数の実行結果は10になる

Slide 34

Slide 34 text

スコープが狭い例(OK) このコードでは、foo関数は引数xを受け取り、bar関数内 で定義された変数xをfoo関数に渡しています。foo関数は bar関数で定義された20を出力します。 ローカルスコープに変数を限定することで、予期しない 結果を避けることができます。 関数の中だけ、ループ処理の中だけといったように、 できる限り変数の利用範囲は狭くしましょう。

Slide 35

Slide 35 text

コードの行数にこだわらない 一般的にコードの行数は少ないほど良いと言えます。 ただし、分かりやすさ、誤解されづらさも大事なことなので、簡潔だが理解でき ないコードは避ける。

Slide 36

Slide 36 text

コーディングルールに従う それぞれのプロジェクトでコーディング標準や命名規約を定めてチームメンバー 全員が合わせていくことが重要。 各プログラミング言語のコーディング標準も公開されています。 https://qiita.com/moaible/items/134329123074337913fb

Slide 37

Slide 37 text

ネストの深いコードは避ける if文, for文などの制御構文で入れ子構造になっているとき、ネストしていると呼ぶ。 何重もの入れ子構造になっていることをネストが深いと言ったりします。

Slide 38

Slide 38 text

コードの見通しが悪くなる ● どこからどこまでがif文の処理ブロック({}中 括弧でくくられた処理範囲)なのか、読み解 くのが難しくなる。仕様変更が辛い。 深くネストしたコードは読みにくい

Slide 39

Slide 39 text

ガード節(早期return) メインフローとは独立した事前条件を満たしていない場合、すぐにreturnで抜けるこ とで、メインフローの独立性を高めてシンプルな記述にできる。 ネストが解消されて、ロジックの見通しも良くなる。 ネストが深い場合多くの処理をやり過ぎていることも多いので、関数に分割したりす る

Slide 40

Slide 40 text

自前で処理を作成 配列にtokyoが含まれているか判定するコード 以下のコードは配列にtokyoが含まれているか判定するコード 標準ライブラリで同様の処理を行う関数があるにも関わらず、自前で処理を書いてしまって いる

Slide 41

Slide 41 text

自分が使う言語の標準ライブラリ、フレームワークは把握しておきましょう。 自前で処理を作成 someを使えば、ワンラインで実装できる

Slide 42

Slide 42 text

関数の呼び出しを読みやすくする 関数に適切な名前がつけられていれば、何の関数なのか分かりやすいですが、 引数の目的・機能が明確でないと理解するのが大変になります。 ● 引数は不変にする ● フラグ引数は使わない ● 引数はできるだけ少なくする

Slide 43

Slide 43 text

引数は不変にする 引数を変更すると値の意味が変わり、どんな意味なのか推測が困難になります。 また、どこで変更されたのかわかりにくくなるので、引数は不変にする。

Slide 44

Slide 44 text

フラグ引数は避ける  メソッド内部の機能を切り替えるために渡すBoolean型の引数のこと 呼び出し側からは何をしているのかわからないので、メソッドを分割した方が良 い。

Slide 45

Slide 45 text

引数はできるだけ少なくする 引数は可能な限り少なくなるよう設計するのが良いです。 多くの引数を使いたいメソッドは処理内容が増大するのでロジックが複雑化す る。引数の管理も重くなる。 引数が多くなりそうな場合は、メソッドの分割、オブジェクト引数にする、別ク ラスへの分割する、などを検討します。 オブジェクト引数への変更

Slide 46

Slide 46 text

デッドコード どんな条件でも到達しないコードのこと ● 可読性低下 ● なぜ残ってるのか分からず勝手に削 除するのが怖い ● 仕様変更で到達可能になってバグに なるかもしれない

Slide 47

Slide 47 text

必要になった時だけ実装する ● 今現在必要性がないのに、将来必要 になるかもしれない、などといった 見込みや思い込みで機能を追加する ことはやめておきましょう。 ● 予想や見込みで追加された機能は使 われないまま 放 置 されることが 多 く、そもそも正しい機 能なのかも分 からない。

Slide 48

Slide 48 text

マジックナンバー ロジック内に直接書き込まれる意図がわ からない数値。重複するなら定数化しま しょう。 意図が明確な場所では、そのまま入れて も問題はないです。 app.listen(3000)など

Slide 49

Slide 49 text

例外の握り潰しはしない 安易にtry, catchを使わない。 例外を握り潰すことになってしまうので、使う場合は再スローなどする。 NG OK

Slide 50

Slide 50 text

リファクタリング メンテナンスしやすくなるように、ソースコードを書き換えていく作業のこと リファクタリングをする時は ● リファクタリングと機能改変を同時には行わない。リファクタリングをしてから新しい機能を追加 する。 ● テストの追加をしない(テストケース漏れの追加, インターフェース変更への対象は例外) ● リファクタリングを始める前と後にはユニットテストを実行しコードの機能が変更ないかを確認す る。 ● パフォーマンスよりもメンテナンス性を重視する。 ● 小さなリファクタリングとテストの組み合わせを繰り返す。一度に大きなリファクタリングをしな い。

Slide 51

Slide 51 text

Eslint, Prettierを使う ESlintを導入することで、単純な構文エラーやプロジェクト固有のコーディング ルールを定義することで、複数人で開発する場合でもシステム全体のコードの一 貫性を維持することができる。 コードフォーマッター(ソースコードを整形してくれるツール)のPrettierも併用 することでより一貫性を保てるので積極的に使って良いと思います。 Eslint導入する一択で良い

Slide 52

Slide 52 text

テストコードは書こう テストコードを書くことで、仕様変更の影響が把握しやすくなったり、テスト コード自体が仕様として機能したり、メリットは多いので、書くようにしましょ う。 安心してリファクタリングもできるようになります。 詳しくはテストコード研修で実施されます。

Slide 53

Slide 53 text

参考書籍 ● リーダブルコード ○ www.amazon.co.jp/dp/4873115655 ● リファクタリング ○ www.amazon.co.jp/dp/4274224546 ● Clean Architecture ○ www.amazon.co.jp/dp/B07FSBHS2V ● 良いコード/悪いコードで学ぶ設計入門 ○ www.amazon.co.jp/dp/4297127830 ● 良いコードを書く技術 ○ www.amazon.co.jp/dp/4297120488 ● Good Code, Bad Code ○ www.amazon.co.jp/dp/4798068160