
すべての良い一日。 少し前に、「良いコードに何を期待するのか」というトピックについて学生と話し、それをここで複製することにしました。 翻訳の過程で、テキストは多少変更されましたが、本質は同じままでした。 この記事はシンプルであることが判明しました(もちろん完全ではありません)が、ここには合理的な粒子があります。
コードは動作するはずです

コードに期待することについて話しましょう。 まあ、初心者にとってはうまくいくはずです。
当たり前のように聞こえますが、私たち一人一人が一度も試みなかったか、うまく行かなかったコードをうまく起動したので、笑わないでください。 2番目のポイント-コードは正しくない状況でも正しく動作するはずです。 それはエラーをキャッチすることです。 しかし、最初のポイントに戻って少し話しましょう。
定期的に、どうすればいいかわからないタスクがあります。 つまり、一般的に(私は周りを見回して、常に新しいことを試みます)。 そして、私はすぐに、実際の作業の瞬間を遅らせるために、いくつかの抽象化、何らかのインフラストラクチャを書くように引き付けられました。 だから、これは間違っています。 コードは動作するはずです。 繰り返しますが、これは重要なポイントです。 問題の解決方法がわからない場合は、急いでインターフェースやモジュールを作成しないでください。それだけです。 これは悪い考えであり、あなたの時間の終わりに終わり、あなたはどこにも行かないでしょう。 動作が不十分なコードは、動作するコードではなく、動作するコードよりも何倍も優れていることを忘れないでください。
同じ製品を作った2つのソフトウェア会社についての古いたとえ話があります。 とにかく最初のものが市場に参入しましたが、最初のものは市場に参入し、2番目のものはすべてを完璧に行い、遅れました。 その結果、最初のキャンペーンはなんとか市場を征服し、2番目の企業を買収しました。 それは別のものについて少しですが、主なアイデアはまだ同じです。 最初に問題を解決し、次にコードを美しくします。
一般に、最初に実用的なプロトタイプを作成します。 不自由で曲がった不幸なものにしましょうが、尋ねられたとき、解決策はすでにそこにあると言えます。 必要に応じて書き直してください。 あなたはそのような格言でこれを表現しようとすることができます-あなたがタスクを行う方法を知っていれば-それをうまくやる。 わからない場合は、まず何とか解決してください。
そして重要なポイントがあります。 理解してほしい。 これは、悪いコードを書くための呼び出しではありません。 コードは良いはずです。 これはFirst Thing Firstの呼び出しです。最初にコードが機能し、次にリファクタリングされます。
それでは、Shit Happensについて話しましょう。 だから、私たちはコードを持っています、それも動作します。 むしろ、「機能する」。 簡単な例を見てみましょう:
public string Do(int x) { using (WebClient xx = new WebClient()) { return xx.DownloadString("https://some.super.url"); } }
これは「動作する」コードのすばらしい例です。 なんで? 遅かれ早かれ考慮されないため、エンドポイントは落ちます。 この例では、いわゆるエッジケース(境界線、「不良ケース」)を考慮していません。 コードを書き始めたら、何が間違っているのか考えてください。 実際、私は単にリモートコールだけでなく、ユーザー入力、ファイル、ネットワーク接続、データベースなど、制御できないすべてのリソースについても話します。 壊れる可能性のあるものはすべて、最も不適切な瞬間に壊れます。あなたがそれでできる唯一のことは、可能な限りそれを準備することです。
残念ながら、すべての問題がそれほど明白ではありません。 バグを生成することがほぼ保証されている多くの問題領域があります。 たとえば、タイムゾーンを使用してロケールを操作します。 それは痛みと叫び声です。「すべてが私の車で機能します。」 彼らは彼らを注意深く知り、彼らと一緒に働く必要があるだけです。
ユーザー入力については。 非常に良い原則があります。それは、他の方法で証明されるまで、ユーザー入力はすべて間違っていると考えられるということです。 つまり、ユーザーが入力した内容を常に検証します。 はい、サーバーでも。
合計:
- 最初にコードを機能させ、
- それから彼を良くする
- エッジケースとエラー処理を忘れないでください。
それでは、コードのサポートについて話しましょう
サポートは複雑な概念ですが、ここでは3つのコンポーネントを含めます。コードは読みやすく、変更しやすく、一貫性がなければなりません。
誰がロシア語でコメントを書いていますか? 誰も書いていない? いいね 一般的に、問題の1つは英語以外のコードです。 しないでください。 ノルウェー語のクラスを含むコードがあり、その名前を発音できませんでした。 悲しかった。 明らかに、そのようなコードをサポートすること(ノルウェー人以外)は簡単な作業ではありません。 しかし、これはまれです。
一般的に、読みやすさは命名と構造に関するものです。 エンティティの名前-クラス、メソッド、変数は、シンプルで読みやすく、意味を持たなければなりません。 前の例をご覧ください。
public string Do(int x) { using (WebClient xx = new WebClient()) { return xx.DownloadString("https://some.super.url"); } }
実装にもかかわらずDoメソッドが何をするのか理解できますか? ほとんどない。 変数名も同様です。 xxオブジェクトの種類を理解するには、その宣言を探す必要があります。 これには時間がかかり、一般的にはコードで何が起こるかを理解できません。 したがって、名前にはアクションまたは意味の本質を反映する必要があります。 たとえば、Doメソッドの名前をGetUserNameに変更すると、コードが少し明確になり、場合によっては実装を確認する必要がなくなります。 同様に、xおよびxx形式の変数名を使用します。 確かに、エラーの場合はe、i、サイクルカウンターの場合はk、ディメンションの場合はn、その他の形式の例外が一般に受け入れられています。
繰り返しますが、たとえば、1か月前に書いたコードを流takeに読んでみてください。 そこで何が起こっているのか理解できますか? もしそうなら、私はあなたを祝福します。 そうでない場合は、コードの可読性に問題があります。
一般的に、このような興味深い引用があります:
「コンピューターサイエンスには、キャッシュの無効化と命名の2つの困難なものしかありません。」©Phil Karlton
コンピューターサイエンスには、キャッシュの無効化と命名という2つの複雑なことがあります。
エンティティに名前を付けるときは彼女を覚えておいてください。
読み取り可能なコードの2番目のコンポーネントは、その複雑さまたは構造です。 私は、ネストされた6つのifasを作成したい人、またはコールバック内のコールバックコールバックにコールバックを作成したい人について話している。 JavaScriptにはCallback Hellという用語もあります。

あなたの同僚とあなた自身に同情してください。 1週間後、このコードを修正または追加するには、文字通りこのコードを歩いていく必要があります。 これを避けることはそれほど難しくありません:
- 短い関数を書く、
- 多くの分岐や入れ子を避け、
- コードの論理ブロックを、再利用するつもりがない場合でも、別々の機能に分けます。
- ifではなくポリモーフィズムを使用する
次に、もう1つの複雑なことについて話しましょう。良いコードは簡単に変更できます。 泥のビッグボールという用語を知っているのは誰ですか? 誰かが慣れていない場合-写真を見てください。

各モジュールは各モジュールに依存しており、1箇所での契約の変更は、極地のの出現、または少なくとも非常に長いデバッグにつながる可能性があります。 理論的には、これに対処するのは非常に簡単です-自分のコードへのコードの依存を減らします。 コードが実装の詳細について知らないほど、それはより良いものになります。 しかし実際には、それははるかに複雑であり、コードの再複雑化につながります。
ヒントの形で、私はそれをこのように言います:
- コードをできるだけ深く非表示にします。 明日、プロジェクトから手動で削除する必要があると想像してください。 修正する必要がある場所はいくつありますか? この量を最小化してください。
- 循環依存を避けます。 コードをレイヤー(ロジック、インターフェイス、データアクセス)に分け、「下位」レベルのレイヤーが「上位」レベルのレイヤーに依存しないことを確認します。 たとえば、データへのアクセスはユーザーインターフェイスに依存しないようにします。
- 機能をモジュール(プロジェクト、フォルダー)にグループ化し、その中のクラスを非表示にし、ファサードとインターフェースのみを残します。
そして描く。 アプリケーションでデータがどのように処理され、どのクラスがこれに使用されるかを紙に書きます。 これは、これがすべて修復不可能になる前に、複雑すぎる場所を理解するのに役立ちます。
そして最後に、均一性について。 たとえあなたにとって間違っているように思われる場合でも、チームが採用した統一スタイルを常に守ってください。 これはフォーマットに適用され、問題を解決するためのアプローチです。 より高速であっても、~~を使用して丸めないでください。 チームは感謝しません。 そして、新しいコードを書き始めるときは、常にプロジェクトを見てください。おそらく必要なものがすでに実装されており、それを再利用できます。
合計:
コードは非常に生産的でなければなりません
少し風邪を引きましょう。 次に考慮すべき要件は、コードの生産性を高めることです。
「十分」という言葉はどういう意味ですか? おそらく誰もが時期尚早な最適化は悪であり、読みやすさを損ない、コードを複雑にすることを聞いたことがあるでしょう。 これは本当です。 ただし、WebメールクライアントがCore I7を60%読み込むように、ツールを知って書かないでください。 パフォーマンスの問題につながる典型的な問題を把握し、コードを記述する場合でも回避する必要があります。
例に戻りましょう。
public string GetUserName(int userId) { using (WebClient http = new WebClient()) { return http.DownloadString("https://some.super.url"); } }
このコードには1つの問題があります-ネットワークを介した同期ダウンロード。 これは、実行されるまでフローをフリーズするI / O操作です。 デスクトップアプリケーションでは、これはぶら下がりインターフェイスになり、サーバーアプリケーションでは、無駄なメモリ予約とサーバーへの要求数の枯渇につながります。 そのような問題を知っているだけで、あなたはすでにより最適化されたコードを書くことができます。 ほとんどの場合、これで十分です。
しかし、時々、いいえ。 そのため、コードを記述する前に、パフォーマンスに関してどのような要件が設定されているかを事前に知る必要があります。
それでは、テストについて話しましょう。
これは、以前のトピックと同じくらい大事なトピックであり、おそらくそれ以上です。 テストではすべてが複雑です。 ステートメントから始めましょう-コードは妥当な数のテストでカバーされるべきだと思います。
コードカバレッジとテストさえ必要なのはなぜですか? 理想的な世界では、それらは必要ありません。 理想的な世界では、コードはバグなしで記述され、要件は変更されません。 しかし、私たちは理想的な世界からはほど遠いので、コードが正しく機能する(バグがない)か、何かを変更した後にコードが正しく機能することを確認するためのテストが必要です。 これは、テストがもたらすメリットです。 一方、テストでカバーされる100%(メトリックスの計算の詳細のため)でさえ、すべてを完全にカバーすることを保証しません。 さらに、機能を変更した後はテストも更新する必要があるため、テストを追加するたびに開発が遅くなります。 したがって、テストの数は合理的である必要があり、主な困難は、コードの量とシステムの安定性の間の妥協点を見つけることです。 このファセットを見つけることは非常に困難であり、これを行うための普遍的なレシピはありません。 ただし、これを行うのに役立つヒントがいくつかあります。
- ビジネスアプリケーションロジックをカバーします。 ビジネスロジックは、アプリケーションが作成されるすべてのものであり、可能な限り安定している必要があります。
- 複雑で計算されたものをカバーします。 計算、変換、複雑なデータのマージ。 間違いを犯しやすい場所。
- バグをカバーします。 バグは、コードがここで脆弱であったことを示すフラグです。 そして、ここはテストを書くのに適した場所です。
- 頻繁に再利用されるコードをカバーします。 頻繁に更新される可能性が高いため、あるものを追加することで、他のものを壊さないようにする必要があります。
多くの必要なしにカバーしないでください
- 外部ライブラリ-コードが既にテストでカバーされているライブラリを探します。
- インフラストラクチャ-DI、自動マッピング(複雑なマッピングがない場合)など。 これにはe2eまたは統合テストがあります。
- 些細なこと-フィールドへのデータの割り当て、通話の転送など。 ほとんどの場合、テストでそれらをカバーするためのはるかに便利な場所を見つけるでしょう。
まあ、それは基本的にそれです。
まとめると。 良いコードは
- 作業コード
- 読みやすい
- 変更が簡単
- 十分に速い
- そして、適切な量のテストでカバーされています。
この難しい方法で頑張ってください。 そしておそらく、あなたはこれを嫌うでしょう。 まだそうでない場合は、ようこそ。
