あなたはこれを嫌うか、どのように良いコードが見えるべきかの物語を嫌います

完全になコードを検索するるに破損しているコピーの数。







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







コードは動作するはずです



明らかなことは、それらが明白であるという事実からそれほど問題をもたらさない。多くのプロジェクトが崩壊するのは、開発が実際のユーザーの問題の解決から完全に離れたためです







コードに期待することについて話しましょう。 まあ、初心者にとってはうまくいくはずです。







当たり前のように聞こえますが、私たち一人一人が一度も試みなかったか、うまく行かなかったコードをうまく起動したので、笑わないでください。 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週間後、このコードを修正または追加するには、文字通りこのコードを歩いていく必要があります。 これを避けることはそれほど難しくありません:









次に、もう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%(メトリックスの計算の詳細のため)でさえ、すべてを完全にカバーすることを保証しません。 さらに、機能を変更した後はテストも更新する必要があるため、テストを追加するたびに開発が遅くなります。 したがって、テストの数は合理的である必要があり、主な困難は、コードの量とシステムの安定性の間の妥協点を見つけることです。 このファセットを見つけることは非常に困難であり、これを行うための普遍的なレシピはありません。 ただし、これを行うのに役立つヒントがいくつかあります。









多くの必要なしにカバーしないでください









まあ、それは基本的にそれです。







まとめると。 良いコードは





この難しい方法で頑張ってください。 そしておそらく、あなたはこれを嫌うでしょう。 まだそうでない場合は、ようこそ。







実際、これは発見、機会、創造性の驚くべき世界です。ここでは、フォームスパンキングの退屈、20年以上のレガシーコードの暗闇、燃えるような日付のための松葉杖のフィールドがあります。ですから、ヘアラインブリッジ(C)と呼びたいです。書き込むプロジェクトを探します。良いことをしようとしてください。単に、世界をより良い場所にすれば、すべてがうまくいきます。








All Articles