パーソルキャリア株式会社 テクノロジー本部 エンジニアリング統括部 サービス開発部 ※本資料は2023年3月時点の情報であり、当該部門における2023年新卒の研修教材です。
良いコードとはパーソルキャリア株式会社 テクノロジー本部 エンジニアリング統括部 サービス開発部※本資料は2023年3月時点の情報であり、2023年新卒の研修教材です。
View Slide
この研修では手を動かす内容はありません。良いコードの初歩的な部分の説明なので気楽に聞いてください。この研修について
目次● 良いコードとは● コードを読みやすくする● おまけ
良いコードとは?● 保守性が高い● 正確に動作する● 無駄な部分がない● 効率的に動作するなどなど縣 俊貴.『良いコードを書く技術── 読みやすく保守しやすいプログラミング作法』. 技術評論社.2021年,24p
将来的な修正や保守作業を容易にするために設計された、読みやすく理解しやすく、変更が容易で堅牢なコードのこと実際は複数人で開発するため、他人が読んでも理解できるようなコードを書く数ヶ月後の自分が読んでも理解できるコードを書こう保守性が高い
”確実に動作し、信頼性が高いことは良いコードの条件です。””良いコードは防御的で、不測のバグを生み出しにくい作りになっています。”正確に動作する防御的プログラミング「正常な値が来るはず」という決め付けをせずに、不正な値が来ても被害を受けないように防御的にプログラミングを行うこと防御的コードが過剰に存在するのも問題で、型による制限など不正な値がそもそも存在し得ないような制約を設けることも検討する。言語やフレームワークの機能も適切に利用する。縣 俊貴.『良いコードを書く技術── 読みやすく保守しやすいプログラミング作法』. 技術評論社.2021年,24p
”無駄がないコードは理解するのも修正するのも簡単で時間がかからないため、良いコードと言えます。”無駄な部分がない● ロジックがシンプル● 無駄な重複コードがない縣 俊貴.『良いコードを書く技術── 読みやすく保守しやすいプログラミング作法』. 技術評論社.2021年,24p
”良いコードは適切なパフォーマンスで動作する。似たような実装がいくつか考えられるとき、あきらかに効率の悪いものを選択する必要はありません。良いコードは適切なパフォーマンスで動作します。”効率的に動作する賢いアルゴリズムが本当に必要なのか実証的に見極めるのが大事です。大概はシンプルさが勝る。必要かどうかはパフォーマンスとの相談。この研修ではここには触れません。縣 俊貴.『良いコードを書く技術── 読みやすく保守しやすいプログラミング作法』. 技術評論社.2021年,24p
他に良いコードと言われて浮かぶもの● 誰でも簡単に理解できるようなコードであること(可読性)● 新しい機能を追加することが容易であること(拡張性)● セキュリティが確保されている○ 潜在的な脆弱性がないこと簡単に言えば、読みやすくて、理解しやすくて、修正しやすいコード● コードスタイルの一貫性を確保する● コードの中に「後でやる」「要修正」などのコメントが存在しない● 変数名やコメントのルールが一貫している
良いコードだと何が良いの?
良いコードの価値継続的かつ迅速にユーザーに価値を届けられる!● 人が入れ替わっても理解しやすい● 機能変更に強い● 修正工数がかからない● バグを生みづらいエンジニアとしては● エンジニア信頼性が上がる● 満足感・達成感がある
悪いコードだと(開発現場でよくあること)● コードを読み解くのに時間がかかる○ 簡単だと思っていた仕様変更やバグ修正に何日も費やす● バグを埋め込みやすくなる○ どこかのコードを変更したら別の箇所でバグが発生● 変更の影響がありそうな箇所を探し回る
なぜ良いコードを書くべきか● 現場ではチーム開発することが基本○ コードを読まれることの方が圧倒的に多い● リリースが遅れて機会を逃す● バグが多いサービスはユーザーが離れる
コードを読みやすくする
意味不明なネーミング● 意図が全く読み取れない● 読み解くのに時間がかかって、中途半端に変更してバグに繋がる連番命名意図がわかる名前を使う
意図がわかる名前を使う縣 俊貴.『良いコードを書く技術』. 技術評論社.2021年,58p
良い名前の条件短すぎず、長すぎず、説明的で意味・意図を表現している変数名、メソッド名、クラス名は、名前がその中身を正しく表現していて、名前を見るだけでその役割を理解できる。良い名前はコードの理解がしやすいが、悪い名前は読む人を混乱させて、勘違いを生み、バグの発生につながる。
意図がわかる名前を使う何の計算なのかわからない
コメントで対応するのは不適切コメントやドキュメントを追加するのも改善方法の一つだが、かなり乱雑なコードになるので良くない。
名前をわかりやすくする変数の意味がコードだけで分かるのでコメントも不要
コメントは適切に使う書きすぎないこと。基本は書かない方が良いです。● ロジックの内容を説明するだけのコメントはしない● メソッド名をわかりやすくするなど、ロジックを理解しやすいようにした方が良いコード理解の助けになる場合に書くと良いです。これは良くないパターン(見ればわかるロジックをただ説明しているだけ)
必要なコメントは書こうコードだけでは意図がわからない場合はコメントしておくと良いです。● なぜこの分岐を作らないのか、なぜこういう計算をしているのか● ライブラリのバグなどで特殊な対応をしている場合● 難しい前提知識が必要な場合@t_wada, https://twitter.com/t_wada/status/904916106153828352, 2017年9月5日
ドキュメントコメントTypeScriptでは型情報を記載できるので、わざわざJSDocコメントに型情報を記述する必要はないです。(jsでは有用)
名前は基本的に省略しない昔は省略することが多かった(諸々の制約があり、そもそも言語仕様で長い変数名が許容されなかった)が、最近はエディタの入力補完などもちゃんとしてるので、省略しない方が良いです。for文のi, j, kや例外のeなど、慣習的でプログラマなら理解できる場合、むしろ省略することもある。
名前に一貫性があるとよい● 対称性を保つ○ begin/end、write/read、on/offなど● 単語の組み合わせ方を一貫させる○ scoreAvg、scoreAverage、avgScoreなどを同時に使用しないなど
英語で命名されていること● 和製英語を使わない● スペルミスに注意● 誤訳に注意VS CodeならCode Spell Checkerのようにタイポを発見してくれるツールもある昔見たことあるのは、記事が保存されるテーブルで、名称はkijis
メソッド名の名前について良いメソッド名は、名前から機能が想像できる。逆に名前から想像できないことはしない。getterであれば、副作用はあってはいけない。メソッドは処理を行うので、メソッド名は「動詞」または「動詞」+「目的語」になっていることが多い。
変数の使い回しをしないコードの途中で変数の用途が変わってしまい、読み手が混乱してバグを埋め込んでしまう可能性がある
変数の使い回しをしないそれぞれの用途にあった、変数を都度定義する≒変数のスコープを可能な限り狭くする
関数化する計算ロジックをダラダラと書くと、どこまでが何の処理なのか分からなくなってくるため、小さな関数を組み合わせることによって、表現がわかりやすくなる。
種類の異なる処理をそれぞれ関数として分離したことで、違う処理が紛れ込みにくくなり、複雑な処理も理解しやすくなりました。関数化の目安は画面に収まりきる程度、30行程度が目安になるのではないかと思います。(処理の内容によるが・・・)関数化する
スコープって何?プログラミングにおけるスコープ(英:scope,可視範囲)とは、変数や関数などを参照できる範囲のこと。通常、変数や関数が定義されたスコープの外側からは、それらの名前を用いるだけでは参照できない。このときこれらの変数や関数は「スコープ外」である、あるいは「見えない」といわれる。(Wikipedia)スコープ=見える範囲=使える範囲=依存する範囲=保守性に影響を与える範囲= スコープ狭い方が良いスコープ_(プログラミング) . Wikipedia. https://ja.wikipedia.org/wiki/スコープ_(プログラミング)
スコープが広い例(NG)グローバルスコープの例グローバルスコープにxを定義して、foo関数内でxを参照して、bar関数内でxを再定義しています。foo関数はその関数自身のスコープでxを定義していないため、スコープチェーンを使用してグローバルスコープからxを参照するので、bar関数の実行結果は10になる
スコープが狭い例(OK)このコードでは、foo関数は引数xを受け取り、bar関数内で定義された変数xをfoo関数に渡しています。foo関数はbar関数で定義された20を出力します。ローカルスコープに変数を限定することで、予期しない結果を避けることができます。関数の中だけ、ループ処理の中だけといったように、できる限り変数の利用範囲は狭くしましょう。
コードの行数にこだわらない一般的にコードの行数は少ないほど良いと言えます。ただし、分かりやすさ、誤解されづらさも大事なことなので、簡潔だが理解できないコードは避ける。
コーディングルールに従うそれぞれのプロジェクトでコーディング標準や命名規約を定めてチームメンバー全員が合わせていくことが重要。各プログラミング言語のコーディング標準も公開されています。https://qiita.com/moaible/items/134329123074337913fb
ネストの深いコードは避けるif文, for文などの制御構文で入れ子構造になっているとき、ネストしていると呼ぶ。何重もの入れ子構造になっていることをネストが深いと言ったりします。
コードの見通しが悪くなる● どこからどこまでがif文の処理ブロック({}中括弧でくくられた処理範囲)なのか、読み解くのが難しくなる。仕様変更が辛い。深くネストしたコードは読みにくい
ガード節(早期return)メインフローとは独立した事前条件を満たしていない場合、すぐにreturnで抜けることで、メインフローの独立性を高めてシンプルな記述にできる。ネストが解消されて、ロジックの見通しも良くなる。ネストが深い場合多くの処理をやり過ぎていることも多いので、関数に分割したりする
自前で処理を作成配列にtokyoが含まれているか判定するコード以下のコードは配列にtokyoが含まれているか判定するコード標準ライブラリで同様の処理を行う関数があるにも関わらず、自前で処理を書いてしまっている
自分が使う言語の標準ライブラリ、フレームワークは把握しておきましょう。自前で処理を作成someを使えば、ワンラインで実装できる
関数の呼び出しを読みやすくする関数に適切な名前がつけられていれば、何の関数なのか分かりやすいですが、引数の目的・機能が明確でないと理解するのが大変になります。● 引数は不変にする● フラグ引数は使わない● 引数はできるだけ少なくする
引数は不変にする引数を変更すると値の意味が変わり、どんな意味なのか推測が困難になります。また、どこで変更されたのかわかりにくくなるので、引数は不変にする。
フラグ引数は避ける メソッド内部の機能を切り替えるために渡すBoolean型の引数のこと呼び出し側からは何をしているのかわからないので、メソッドを分割した方が良い。
引数はできるだけ少なくする引数は可能な限り少なくなるよう設計するのが良いです。多くの引数を使いたいメソッドは処理内容が増大するのでロジックが複雑化する。引数の管理も重くなる。引数が多くなりそうな場合は、メソッドの分割、オブジェクト引数にする、別クラスへの分割する、などを検討します。オブジェクト引数への変更
デッドコードどんな条件でも到達しないコードのこと● 可読性低下● なぜ残ってるのか分からず勝手に削除するのが怖い● 仕様変更で到達可能になってバグになるかもしれない
必要になった時だけ実装する● 今現在必要性がないのに、将来必要になるかもしれない、などといった見込みや思い込みで機能を追加することはやめておきましょう。● 予想や見込みで追加された機能は使われないまま 放 置 されることが 多く、そもそも正しい機 能なのかも分からない。
マジックナンバーロジック内に直接書き込まれる意図がわからない数値。重複するなら定数化しましょう。意図が明確な場所では、そのまま入れても問題はないです。app.listen(3000)など
例外の握り潰しはしない安易にtry, catchを使わない。例外を握り潰すことになってしまうので、使う場合は再スローなどする。NG OK
リファクタリングメンテナンスしやすくなるように、ソースコードを書き換えていく作業のことリファクタリングをする時は● リファクタリングと機能改変を同時には行わない。リファクタリングをしてから新しい機能を追加する。● テストの追加をしない(テストケース漏れの追加, インターフェース変更への対象は例外)● リファクタリングを始める前と後にはユニットテストを実行しコードの機能が変更ないかを確認する。● パフォーマンスよりもメンテナンス性を重視する。● 小さなリファクタリングとテストの組み合わせを繰り返す。一度に大きなリファクタリングをしない。
Eslint, Prettierを使うESlintを導入することで、単純な構文エラーやプロジェクト固有のコーディングルールを定義することで、複数人で開発する場合でもシステム全体のコードの一貫性を維持することができる。コードフォーマッター(ソースコードを整形してくれるツール)のPrettierも併用することでより一貫性を保てるので積極的に使って良いと思います。Eslint導入する一択で良い
テストコードは書こうテストコードを書くことで、仕様変更の影響が把握しやすくなったり、テストコード自体が仕様として機能したり、メリットは多いので、書くようにしましょう。安心してリファクタリングもできるようになります。詳しくはテストコード研修で実施されます。
参考書籍● リーダブルコード○ 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