👮
わいの考えたさいきょうのコーディングルール
はじめに
プログラミングやソフトウェア開発における学びは、日々の挑戦や試行錯誤の中で獲得されるものです。私自身もまだまだ学び始めの段階で、多くの先輩方や専門家たちには遠く及ばないと感じることも多く、時には絶望する日々を送っています(´∀`=)
しかし、そのような日々の中で一つ明確に感じていることは、コーディングの品質や一貫性の重要性です。チームでの開発においては、全員が共通のルールや規約に従うことで、品質を担保することが可能となります。一方、個人としても、自らのスキルを向上させ、一貫性のあるコードを書くためには、明確な指針が必要です。このような背景から、初心者の方々も参考にしていただけるようなコーディングルールを作成したので、新しい知識や技術を効果的に取り入れる指針にしていただけたらと思います。
※ 不足事項があればどんどん追記していきますので、どしどしコメントください!
コーディングルールの観点
フォーマットと構造
-
インデント
- すべてのインデントは統一されていますか?(例: 1 タブまたは 4 スペースで統一していますか?)
-
行の長さ
- どの行も指定された最大文字数を超えていませんか?(例: すべての行は 80 文字以内ですか?)
-
空白行
- 関連するコードブロックの間に適切な空白行が挿入されていて、コードの可読性が向上していますか?
-
ブレースのスタイル
- 使用しているブレースのスタイルは統一されていますか?(例: K&R スタイルか Allman スタイルのどちらを使用していますか?)
-
ファイル構造
- 各ファイルは特定の目的や機能に関連するコードのみを含んでいますか?(例: ユーティリティー関数をまとめているファイルは、その関数のみを含んでいますか?)
-
クラスの行数目安
- 各クラスは適切な行数以内に収まっていますか?(例: 1 クラスは 200 行以内とするなど)
-
関数の行数目安
- 各関数は適切な行数以内に収まっていますか?(例: 1 関数は 50 行以内とするなど)
-
関数名・変数名の最大長
- 任意の関数名や変数名は指定された最大文字数を超えていませんか?例: 関数名や変数名は 30 文字以内とするなど)
命名規則
-
明確さ
- 名前は、変数、関数、クラスの目的や機能を正確に表していますか?
- 名前を見ただけで、その目的や使い方を他の開発者が理解できますか?
-
短縮形や略語の使用
- 名前に略語や短縮形を使用している場合、それは一般的に理解されるものですか?
-
一貫性
- 同じ概念や目的の変数や関数に対して、プロジェクト全体で一貫した名前付けをしていますか?
-
複数形と単数形
- 配列やリストを示す変数の名前は、適切に複数形を使用していますか?
- 単一のアイテムを示す変数の名前は、適切に単数形を使用していますか?
-
前置・後置の接頭辞/接尾辞の使用
- Boolean 型の変数は、
is
,has
,should
,can
などの接頭辞で始められていますか?-
状態の確認
is
-
用途: 何かの状態や条件が成立しているかを確認する。
-
例:
isActive
,isFinished
,isValid
-
用途: 何かの状態や条件が成立しているかを確認する。
-
所有関係の確認
has
- 用途: 何かが特定の属性や要素を持っているかを確認する。
-
例:
hasItems
,hasErrors
,hasAccess
-
行動の推奨
should
- 用途: 何かのアクションや動作を行うべきかを示す。
-
例:
shouldUpdate
,shouldRetry
,shouldAlert
-
可能性の確認
can
- 用途: 何かのアクションや動作が可能かどうかを確認する。
-
例:
canSubmit
,canEdit
,canAdvance
-
状態の確認
- Boolean 型の変数は、
アーキテクチャとデザインパターン
-
デザインパターンの採用
- 適切なデザインパターン(例:
Factory
、Strategy
など)を採用して、コードの再利用性、拡張性、および保守性を向上させていますか?
- 適切なデザインパターン(例:
-
モジュール性と組織化
- システムを構成する部品を明確に識別し、それぞれを独立したモジュールとして設計しましたか?
- モジュール間の依存関係は明確ですか?また、その設計は疎結合・高凝集の原則に従っていますか?
SOLID原則
-
単一責任の原則 (SRP)
- 各クラスやモジュールは 1 つの明確な責務や役割のみを担っていますか?
- 変更が必要になった場合、その影響範囲は該当のクラスやモジュールのみに限定されていますか?
-
オープン/クローズド原則 (OCP)
- 新しい要件や機能を追加する際に、既存のコードを変更せずに拡張できるように設計されていますか?
- 既存のコードの安定性は新しい変更によって損なわれていませんか?
-
リスコフの置換原則 (LSP)
- 派生クラスは、基底クラスと置換可能な形で設計されていますか?
- 基底クラスの代わりに派生クラスを使用した場合も、期待する動作が保証されていますか?
-
インターフェース分離の原則 (ISP)
- クラスは不必要なインターフェースを持っていませんか?
- 与えられたインターフェースは、その使用するクライアントの要件に特化して設計されていますか?
-
依存性逆転の原則 (DIP)
- 高水準のモジュールは低水準のモジュールに直接依存していませんか?
- モジュール間の依存関係は抽象(インターフェースや抽象クラスなど)を介していますか?
コードのクリーンさ
-
アーリーリターン
- 関数やメソッド内で、条件が満たされないケースやエラーケースを最初にチェックして適切にリターンしていますか?
- ネストが深くなっている場所はないですか?
-
マジックナンバーを避ける
- ハードコードされた数字や文字列は使用していませんか?
- そのような値に代わり、意味を持たせた定数や設定値を使用していますか?
-
デッドコードの削除
- 使用されていない変数、関数、クラスは存在していませんか?
-
DRY原則
- 同じコードが複数の場所で繰り返されていませんか?
- 重複を削減するための共通の関数やモジュールを活用できる箇所はありませんか?
-
KISS原則
- コードはシンプルかつ明確に問題を解決していますか?
- 必要以上の複雑な設計や実装は避けられていますか?
-
YAGNI原則
- 現時点で必要とされていない機能やコードをあらかじめ追加していませんか?
- 必要となる前に追加したコードが存在する場合、それは本当に必要ですか?
-
ボーイスカウトの法則
- あなたがコードを触れた場所は、触る前よりも少しでも良い状態にしていますか?
セキュリティ
-
データの検証
- 外部から取り込むデータ全てに対して、適切な入力検査やバリデーションが実施されていますか?
- 不正な形式や攻撃コードが含まれる入力は適切に拒否またはサニタイズされていますか?
-
センシティブデータの取り扱い
- API キー、パスワード、セッショントークンなどのセンシティブデータはコード内にハードコードされていませんか?
- センシティブデータは環境変数や専用の秘密管理ツールを利用し、安全に保管していますか?
-
データの暗号化
- パスワードや他の個人情報は適切な手段で暗号化され、安全にデータベースに保存されていますか?
-
インジェクション攻撃の防止
- ユーザー入力をクエリやコマンドに組み込む際、安全なパラメータ化方法やエスケープメカニズムが使用されていますか?
- SQL インジェクションや OS コマンドインジェクションのリスクを十分に認識し、これらの攻撃を防ぐための対策が施されていますか?
- ユーザー入力をクエリやコマンドに組み込む際、安全なパラメータ化方法やエスケープメカニズムが使用されていますか?
-
XSS(クロスサイトスクリプティング)の対策
- XSS 攻撃に対する脆弱性はなく、外部データの表示には適切なエスケープやサニタイズが適用されていますか?
-
クロスサイトリクエストフォージェリ(CSRF)の対策
- CSRF 攻撃に対する脆弱性はなく、トークンベースの対策は適切にされて居ますか?
パフォーマンス
-
効率的な計算
- 不要な計算や再計算を排除していますか?
- 無限ループのリスクは回避されていますか?
-
効率的なデータベースクエリ
- N+1 問題のリスクは考慮し、避けられていますか?
- JOIN を使用する際、必要なテーブル、カラムのみを選択していますか?
- フルテーブルスキャンの回避や、サブクエリの過度な使用を控えていますか?
-
データキャッシングの適用
- 頻繁にアクセスされるデータはキャッシュ化されていますか?
- キャッシュの有効期限や更新策略は適切に設定されていますか?
-
外部サービスとの連携の最適化
- 外部 API やサービスのレスポンスタイムや制限を適切に考慮し、設計していますか?
- 同じリクエストの冗長な発行を避けるための戦略は取り入れていますか?
-
フロントエンドの最適化
- 画像やリソースは最適なフォーマット、圧縮、サイズで提供されていますか?
- 必要に応じてオフスクリーンのコンテンツや画像は遅延ローディングされていますか?
- クライアントサイドのレンダリングでは、不要な再レンダリングや計算を回避していますか?
-
非同期処理の最適化
- 非同期処理は適切に行われており、相互に依存しないタスクはまとめて処理されていますか?
- 一方で、計算が重いタスクは適切に同期処理されており、メインスレッドのブロックを回避していますか?
テスト
-
テストの範囲
- 想定されるあらゆる主要ケース、エッジケースが適切にテストされていますか?
- 例外処理やエラーケースも適切にテストされていますか?
-
テストの明確さ
- テスト名は意味があり、何をテストしているのか明確に示されていますか?
- テストの目的や対象がコメントやドキュメントに明記されていますか?
-
テストの信頼性
- テスト結果は一貫しており、環境やランダム性に依存していませんか?
- テストが失敗した場合のデバッグがしやすいよう、失敗原因や詳細を明確に出力していますか?
-
テストの独立性
- 各テストは他のテストから独立して実行可能ですか?
- テスト間での依存関係や順序が必要な場合、その理由や条件は明確に文書化されていますか?
-
ユニットテスト
- 個々の関数やメソッドは独立してテストされていますか?
- テストは明確な期待値と実際の結果を比較していますか?
-
統合テスト
- システムの異なる部分が互いに適切に機能するかを確認するテストは行われていますか?
- 依存関係や外部サービスとの連携が正しく動作することを確認していますか?
エラーハンドリング
-
明確なエラーメッセージ
- エラーメッセージは具体的で、そのエラーの原因や解決策についての情報を提供していますか?
-
エラーのカテゴリー分け
- エラーコードやエラータイプは適切に定義されており、それぞれのエラーが正確に分類されていますか?
-
外部のエラーハンドリング
- 外部サービスやライブラリのエラーは適切にキャッチされており、その後の処理が適切に行われていますか?
- 予期しないエラー(例:タイムアウトや通信エラー)に対する適切な処理が行われていますか?
-
リトライ戦略の適用
- 一時的なエラーや通信の障害に対して、再試行のロジックが明確に実装されていますか?
- リトライの間隔や上限回数は適切に設定されていますか?
-
リソースのクリーンアップ
- 例外やエラーが発生した際、未完了のトランザクションやオープンリソース(ファイル、ネットワーク接続など)は適切に終了・解放されていますか?
-
エラーロギング
- 発生したエラーや例外は、適切なログレベルで記録されていますか?
- ログには、エラーの発生箇所、エラーコード、エラーメッセージなど、デバッグに必要な情報が含まれていますか?
コメント
-
明確性
- コードの目的や動作、特に非直観的な部分はコメントで十分に明確に説明されていますか?
-
詳細性
- 複雑なロジックやアルゴリズム、特定の判断背景などは詳細なコメントを通じて後のレビューやメンテナンスが容易に理解できるようになっていますか?
-
更新の追従
- コードが変更された場合、関連するコメントも適切に更新され、情報の不整合が生じていないですか?
-
変更理由の記載
- 大きな変更や重要な修正をコードに加える際、その背景や理由はコメントとして十分に記述されていますか?
-
過度なコメントを避ける
- コード自体が自己説明的である場合、不要な冗長なコメントは避けられていますか?コメントは実際に追加の文脈や説明が必要な場面でのみ適切に使用されていますか?
-
TODOやFIXMEの使用
- 未完成の部分には
TODO:
、後で修正が必要な箇所にはFIXME:
のようなキーワードを使って明確に示されていますか?
- 未完成の部分には
インラインドキュメンテーション
-
関数/メソッドのドキュメンテーション
- 各関数やメソッドの直前に、その機能、引数のタイプ、戻り値のタイプ、例外などの情報を明確に記載しましたか?
-
クラスとプロパティの説明
- クラスとそのプロパティに、それぞれの目的と使用法を示す説明を付けましたか?
-
タグの使用
- jsDoc やその他のドキュメンテーションツールでサポートされているタグ(例:
@param
,@returns
,@throws
)を適切に使用して、ドキュメンテーションの構造を整理しましたか?
- jsDoc やその他のドキュメンテーションツールでサポートされているタグ(例:
おわりに
今回、私の未熟な経験を元に考えたコーディングルールを共有させていただきました。
完璧であるとは言い難いかもしれませんが、これが皆さんのコーディングの一助となれば幸いです。
プログラミングは常に変わりゆくもので、私たちもそれに伴い成長していくことが求められます。この記事をきっかけに、新たな視点やアプローチを取り入れて、より良いコードを書くための旅を共にしていきましょう。
参考文献
Discussion