コードをよりクリーンにする方法

公開: 2020-06-24

開発者は、ほとんどの時間を既存のコードの読み取りと保守に費やします。 私たちはそれが何をするのか、そしてそれをどのように変更または拡張するのかを理解しようとします。 では、なぜパフォーマンスだけに焦点を合わせるのでしょうか。

読みやすさは、コードを長持ちさせるときにも同様に重要です。

長寿命のソフトウェアを開発するときは、優れたコードの可読性が不可欠です。 古いコードを維持する場合でも、新しい機能を追加する場合でも、古いコードを変更する場合でも、読み取り可能なコードを使用すると、作業がはるかに簡単になります。

もう1つの利点は、新しい開発者をオンボーディングする立場にある場合です。 オンボーディングを成功させるには、既存のコードの可読性が必要です。

現実には、何年にもわたって開発されてきた製品に取り組み始めると、ある時点でレガシーコードを処理する必要があります。 あなたが書かなかった何千行もの読めないコードでいっぱいになると、多くの欲求不満が蓄積します。 それを維持し、それを構築することはそれを悪化させるだけです。

Mediatoolkitでは、製品を長期的に開発しています。 一方では、それは私たちが短期的な修正と危険なビジネス上の決定を避けることを意味します。 一方、エンジニアリングチームは、コードの可読性に少し余分な努力を払う必要があります。

真実は、ほんの2、3年前まで、コードの可読性をそれほど重視していなかったということです。 ご想像のとおり、新しい開発者のオンボーディングと機能のアップグレードに関するいくつかの深刻な問題が発生しました。

うまくいけば、他の人は私たちの過ちを繰り返さず、代わりに時間通りに掃除を始めます。 Mediatoolkitで固執するコードの可読性に関するガイドラインを次に示します。

読みやすさが重要です

既存の製品で作業している場合、開発者はほとんどの時間を既存のコードの読み取りと保守に費やします。 何かが開発するのに何年もかかったとしたら、それが何をするのか、そしてそれをどのように変えるのかを理解するのに1分以上かかるのは当然のことです。

開発者が既存のコードを読むのに多くの時間を費やしているにもかかわらず、新しい、よりパフォーマンスの高いコードを書くことに重点が置かれています。 それを維持するために必要な時間はめったに考慮されません。 では、代わりに何に焦点を当てるべきでしょうか?

基本から始めます。 これらは、コードを改善してクリーンにするために実行できる最初のステップです。

  • 意味のある名前を使用する
  • 機能を改善する
  • 不変性を優先する
  • 命令型よりも宣言型プログラミングを優先する
  • シンプルに愚かにしてください– KISS
  • 繰り返さないでください– DRY
  • あなたはそれを必要としないでしょう– YAGNI

意味のある名前を使用する

すべてをコードで命名するので、うまくやるようにしてください。 意味のある名前は、何が起こっているのかというコンテキストを提供します。 名前は、コードの意図(何かが存在する理由、コードの機能、およびコードの使用方法)を示す必要があります。

時間をかけて良い名前を考えてください。 ランダムなジブリッシュで表現したいことを思い出そうとすると、より多くの時間が費やされます。

意味のある名前のないコード

意味のある名前のコード

可能であれば、名前は問題のあるドメインに由来する必要があります。 ドメインに適切な名前がある場合は、技術名を使用しないでください。

クラスとオブジェクトには、 customeremailSenderhtmlParserなど、名前として名詞または名詞句を含める必要があります。

ただし、その規則に従いながら、 datainfomanagerprocessorcontrollerなどの一般的な名詞を含む名前は避けてください。ほとんどの場合、それらはあまり意味を持たないためです。

一般的な用語は、そのドメインが何であるかを教えてくれません。 可能な限り広い意味で何が含まれているのかを伝えるだけです。

たとえば、 infoという名前のオブジェクトは、 userInfoよりもはるかに読みにくいです。 また、コード全体に複数のinfoscontrollers 、またはmanagersを含めることができるため、これらの名前がドメイン固有である場合は、コードのロジックを簡単にたどることができます。

メソッドには、動詞またはpostPaymentdeletePageinsertなどの動詞句を使用して名前を付ける必要があります。 省略名は、初期開発時にのみ混乱して直感的になることが多いため、使用しないことをお勧めします。

代わりに、発音可能な名前を使用してください。 これらは、コードを読んで理解している間、理解しやすく、覚えやすいものです。

コメントのない悪い名前は意味がありません:

より良い自明の名前:

コンセプトごとに1つの用語を選び、それを守ります

異なるクラスの同等のメソッドとしてfetchretrievegetを使用するのは混乱を招きます。

同じまたは類似したものに異なる名前を使用すると、読者が混乱し、名前が異なるため、これらの名前がどのように異なるかなどの質問が開かれます。

機能を改善する

関数を改善するために最初にできることは、関数を小さくすることです。 私が小さいと言うとき、私は50行未満、できれば10〜15行未満を意味します。 関数を小さく保つことで、読むときに考えなければならないコンテキストを減らすことができます。

関数のインデントもコンテキスト保持を向上させます。 関数に2つ(またはそれ以上)のインデントがある理由をよく説明する必要があります。

可能であれば、ネストされたインデントブロックを関数呼び出しに置き換えます

上からの`calculateEmployeeSalary`のインデントの少ないバージョン:

読みやすさを向上させるために、関数は1つのことだけを実行する必要があります

長い関数は多くの場合、複数のことを実行するため、長くなります。 コードを読みやすくしながら、複数のことを行うには、長い関数を複数の小さな関数に分割する必要があります。

他の関数を呼び出す関数は、それでも1つのことだけを実行する必要があり、もう少し抽象的です。

複数レベルの抽象化を導入する

より高いレベルの抽象化で動作を記述できる場合は、コードのスニペットを関数に抽出します。

多くのより高い抽象化レベルの関数は、いくつかの低レベルの関数と比較して理解しやすいです。 抽象化は、ドメインの動作に基づく必要があります。

コードの再利用を目的として導入された任意の抽象化は、ほとんどの場合、事態を悪化させます。 関数の関数呼び出しを同じ抽象化レベルに保つようにしてください。 これには、抽象化を平準化するためだけに1行の関数が必要になる場合がありますが、これは問題ありません(現代の言語ではインライン化によって最適化されるため、パフォーマンスは問題になりません)。

関数をレベルごとに階層的に編成すると、コードは段階的なレシピではなく、行動のストーリーを伝えることができます。

関数の引数はできるだけ少なくする必要があります。 2つ以上はめったに使用しないでください。

多くの引数は、特に引数を出力として使用する場合(関数の完了後に変更される引数)、コードを理解しにくくします

多くの場合、出力引数は予期せず不自然なので、避けてください。

前の例では、3つの引数を使用して、関連する例と可能な限り類似した状態を維持していますが、避ける必要があります。

関数は、アクション(副作用)を実行するコマンド、または呼び出し元にデータを返すクエリのいずれかである必要がありますが、両方ではありません。

彼らの「役割」はその名前で強調されるべきです。 関数がコマンドであるか、その名前によるクエリであるかを誤解することはありません。

引数の状態を変更するコマンドの名前の例:

引数の状態を変更せずに値を抽出するクエリの名前の例:

副作用は常に明示的でなければなりません。 彼らは決して予想外であってはなりません。 不要な場合は避けてください。 機能を「純粋」、つまりステートレスに保つようにしてください。

不変性を優先する

プログラミングにおいて「不変性」とは実際にはどういう意味ですか?

これは、オブジェクト/変数が完全に作成された後は変更できないことを示すプロパティです。 オブジェクトの状態を変化させる代わりに不変のコードを使用すると、状態が変更されたコピーが作成されます。

可変コード:

不変コードでの同じ動作:

不変性により、コードがより単純になり、追跡しやすくなります

オブジェクトが不変であることを知っているので、オブジェクトを渡す関数がオブジェクトを変更するかどうかを心配する必要はありません。 並行プログラミングもより簡単でクリーンになります。

不変オブジェクトは本質的にスレッドセーフです。つまり、常に変更不可能な一貫性のある状態で作業しているため、同期ブロックは必要ありません。

もちろん、ロジックが不自然、複雑、またはパフォーマンスが低い場合もありますが、それでも不変として表現されます。 その場合でも、可変性を使用できますが、その範囲を可能な限り縮小するようにしてください。

命令型よりも宣言型プログラミングを優先する

相続人が簡単に読めるコードを書く上で重要なのは、命令型プログラミングではなく宣言型プログラミングを選択することです。 命令型プログラミングとは何ですか?宣言型プログラミングとは何ですか?

命令型プログラミングは、物事を行う方法を示しています。 その焦点は、条件文、ループ、突然変異などの段階的なメカニズムにあります。

一方、宣言型プログラミングは、それを行う方法ではなく、何をすべきかを示します。 その焦点は、何をしなければならないか、つまり、段階的な説明ではなく、アクション全体を意味することにあります。 宣言型プログラミングは、命令型プログラミングのステップバイステップスタイルの上に構築されています。

命令型コードを宣言型に抽象化してみてください。

宣言型のスタイルでは、ビジネスロジック/意図がはるかに明白になります。 コードの意図を一目で確認すると、コードの保守と修正がはるかに簡単になります。 これにより、コード全体を最初に読み取ってその意図を解読するのではなく、問題のある部分を特定してから詳細に飛び込むことができます。

以下に示すように、動作は宣言型スタイルでより明白になります。

シンプルに愚かにしてください– KISS

開発者は、特定の問題に対して「賢い」解決策を思いつくことがよくあります。

それらの解決策は、与えられた瞬間に神が送るように見えますが、エゴブーストが私たちに与えるかもしれないにもかかわらず、好まれるべきではありません。 ほとんどの場合、彼らは理解して従うのが難しく、それによって、維持またはアップグレードするのがさらに難しくなります。

シンプルさは、設計の重要な目標である必要があります。 不必要な複雑さを避けてください。

繰り返さないでください– DRY

重複、特に知識の重複は悪いです。 システムに知識の単一の表現を持たせることを目指す必要があります。 知識が変わった場合は、複製された場所ごとに知識を変更する必要があります。

複製を見逃すと、バグになる可能性が高くなります。

メンテナンスは、重複が多いと簡単に悪夢になります。

複雑な問題に取り組むときは、プロトタイピング中にコピーアンドペーストするのが通常の習慣です。 それは私たちが適切な知識の抽象化を見つけるのに役立ち、それが意図をよりよく表現することにつながるので、それは何も悪いことではありません。

しかし、私たちが子供の頃に教えられたように、遊びの時間の後、それは片付けの時間です。 それらの複製はその目的を果たしました。 次に、それらを削除します。

あなたはそれを必要としないでしょう– YAGNI

将来必要になる可能性のあるものを実装するのではなく、必要なものだけを実装してください。 私たちが「必要とする」ことが非常に多いのは、後で実際に必要になるものではありません。

私たちが「必要とする」ものの時期尚早な実装は、私たちの設計が進む可能性のある多くの道を閉じます。 それは私たちの製品の実際のニーズに最適化されていない設計を私たちに強制し、それは次に私たちを維持するのが難しい貧弱で複雑な全体的な設計につながります。

次のステップ

改善するために実行できる次のステップは、 SOLIDの原則です。

これらは、ソフトウェア設計をさらに理解しやすく、柔軟性があり、保守しやすいものにすることを目的とした5つの設計原則です。

  1. 単一責任の原則– SRP
  2. オープンクローズ原則– OCP
  3. リスコフの置換原則– LSP
  4. インターフェイス分離の原則– ISP
  5. 依存性逆転の原則– DIP

これらの(他のいくつかの)原則に従うことで、コードとドメインの設計のほとんどを読みやすく、保守が容易で、アップグレード可能に保つことができました。

私たちがそれを行った理由は、主にオンボーディングプロセスをより効率的かつ快適にすることによって、チームの新しいメンバーを歓迎する準備をするためです。

新しいメンバーと言えば、キャリアページでシニアJava開発者またはその他の欠員の募集職種を確認してください。