大きくて複雑なソフトウェア製品を長年にわたって維持可能にする方法は?


156

私は長年ソフトウェア開発者として働いています。多くの開発者が製品の開発に関与するにつれて、プロジェクトがより複雑で維持できなくなるというのが私の経験でした。

開発の特定の段階でソフトウェアが「ハッカー」と「ハッカー」を獲得する傾向があるようです。特に、アーキテクチャを定義したチームメンバーが会社で働いていない場合です。

何かを変更しなければならない開発者が、アーキテクチャの全体像をつかむのに苦労しているのはイライラするものです。したがって、問題を修正したり、元のアーキテクチャに対して機能する方法で変更を加えたりする傾向があります。その結果、コードはますます複雑になり、理解しにくくなります。

何年もの間ソースコードを本当に保守しやすくする方法について何か役に立つアドバイスはありますか?


9
強くお勧めする書籍:Steve McConnellの「ソフトウェアプロジェクトサバイバルガイド」、Steve McConnellの「Rapid Development」、Martin Fowlerの「Refactoring」
Imran Omar Bukhsh

15
...およびボブおじさんによる「クリーンコード」;)(ロバートC.マーティン)
ガンダルフ

34
これは、大学での数十年に及ぶ読書や講座全体の価値を生み出したものではありませんか?
12

17
@Eric Yin-私はコメントに同意しません。私にとってそれらはコードのにおいであり、長期的なプロジェクトでは必然的に時代遅れになり誤解を招くため、良いプロジェクトよりも害を及ぼす傾向があります。
JohnFx

8
@Eric Yin:自己文書化コードに努めます。意図のコメントは、理解を高める場合にのみ使用してください。
ミッチ小麦

回答:


138

コードの腐敗を避けるための唯一の本当の解決策は、適切にコーディングすることです!

うまくコーディングする方法は別の質問です。あなたが一人で働いている優秀なプログラマーであっても、それは十分に難しいです。異機種混合のチームでは、さらに難しくなります。アウトソース(サブ)プロジェクトでは...ただ祈ってください。

通常の良い習慣が役立つかもしれません:

  1. 複雑にしないでおく。
  2. 複雑にしないでおく。これは、特に「全体像」のアーキテクチャに当てはまります。開発者が全体像をつかむのに苦労している場合、彼らそれに対してコーディングするつもりです。したがって、すべての開発者が取得できるように、アーキテクチャを単純にしてください。アーキテクチャをシンプルにする必要がある場合、開発者はそのアーキテクチャを理解するためのトレーニングを受ける必要があります。彼らがそれを内部化しないなら、彼らはそれをコード化するべきではありません。
  3. 低結合高凝集を目指します。チームの全員がこの考えを理解していることを確認してください。疎結合の粘着性のある部分で構成されるプロジェクトでは、一部の部分が保守不能な混乱に陥った場合、その部分を単に取り外して書き換えることができます。カップリングがきつい場合、それはより困難またはほぼ不可能です。
  4. 一貫してください。どの標準に従うべきはほとんど問題ではありませんが、いくつかの標準に従っください。チームでは、誰もがもちろん同じ基準に従う必要があります。一方で、標準に執着しすぎて残りを忘れるのは簡単です。標準は有用ですが、良いコードを作成するためのほんの一部にすぎないことを理解してください。たくさん作らないでください。
  5. コードレビューは、チームを一貫して機能させるために役立つ場合があります。
  6. IDE、コンパイラ、バージョン管理、ビルドシステム、ドキュメントジェネレータ、ライブラリ、コンピュータチェア全体的な環境など、すべてのツールが適切に維持されていることを確認してください。プロジェクトファイルのバージョンの競合、Windowsの更新、ノイズなど、ありふれたがいらいらするものと戦うように。このような面白くないものでかなりの時間を繰り返し無駄にしなければならないため、士気が低下しますが、少なくともコードの品質は向上しません。大規模なチームでは、開発者ツールの保守を主な仕事とする1人以上の人がいる可能性があります。
  7. 技術的な決定を下すときは、技術を切り替えるのに何が必要かを考えてください。どの決定が不可逆的であり、どの決定が不可逆的であるか。不可逆的な決定をさらに慎重に評価します。たとえば、プロジェクトをJavaで記述することにした場合、それは非常に不可逆的な決定です。データファイルに自己沸騰型バイナリ形式を使用することにした場合、それはかなり不可逆的な決定でもあります(コードが公開されてから、その形式をサポートし続ける必要があります)。ただし、GUIの色は簡単に調整でき、最初に省略した機能を後で追加できるため、このような問題についてのストレスが少なくなります。

8
これらは素晴らしい点です。私は「シンプルに保つ」ことに苦労していることを認めなければなりません。それは、異なるコンテキストの異なる人々にとって異なることを意味するようで、「シンプル」ではなく複雑になります(しかし、私は物事を複雑にする自然な傾向があります)。
Kramii

3
あなたのポイント、特に「KIS」に完全に同意します。しかし、より若い(若い?)開発者は、最も単純なコンテキストを記述するためにかなり複雑な構造を使用する傾向が見られます。
-chrmue

10
@chrmue:「JavaでFactorialを書く方法」を参照してください;-)
ジョナスプラッカ

8
ええと、「8。シンプルに保つ」。
ダウッドイブンカリーム

7
#6は+10に値します。
ジムG.

55

ユニットテストはあなたの友達です。それらを実装すると、低結合が強制されます。また、プログラムの「ハッキング」部分を簡単に識別してリファクタリングできることも意味します。また、既存の機能を損なわないように、変更をすばやくテストできることも意味します。これにより、開発者は、破壊を恐れてコードを複製するのではなく、既存のメソッドを変更することを奨励するはずです。

単体テストは、コードのドキュメントの余分な部分としても機能し、各部分の動作の概要を示します。広範な単体テストを使用すると、プログラマは、プログラムのアーキテクチャ全体を変更して既存のクラス/メソッドを使用する必要はありません。

良い副作用として、ユニットテストはバグカウントを減らすことも期待しています。


3
非常に重要なポイント。レガシーシステム、多くのクラス、多くのコード行、ドキュメントなし、ユニットテストなしに引き継ぎました。すべてのコードの修正と機能強化のためのユニットテストを熱心に作成した後、システム設計はよりクリーンでメンテナンス可能な状態に進化しました。そして、重要なコア部分を書き換える「勇気」があります(単体テストでカバー)。
サムゴールドバーグ

40

ここの誰もがすぐにコードの腐敗について言及し、私はこれを完全に理解し、同意しますが、それでもここでのより大きな全体像とより大きな問題を見逃しています。コードの腐敗は発生しません。さらに、優れた単体テストが記載されていますが、実際には問題に対処していません。単体テストのカバレッジは良好で、比較的バグのないコードを使用できますが、それでもコードとデザインは腐っています。

プロジェクトに取り組んでいる開発者は機能を実装するのが難しく、全体的なアーキテクチャの全体像を見逃しており、システムにハッキングを実装しているとおっしゃいました。設計を実施し、影響を与える技術的なリーダーシップはどこにありますか?このプロセスのコードレビューはどこにありますか?

あなたは実際にコードの腐敗に苦しんではいませんが、チームの腐敗に苦しんでいます。事実は、ソフトウェアの元の作成者がチームにいないかどうかは問題ではないということです。既存のチームの技術主任が基礎となる設計を完全かつ真に理解し、技術主任としての役割に長けていれば、これは問題ではありません。


非常に良い点は、雄牛の目を打つ!悲しいことですが、それがまさにここで起こっていることです。そして、技術リーダーなしでは物事を変えることは不可能のようです
...-chrmue

4
@chrmue物事がどうなるかは推測しますが、私はそれでうんざりしています。多くの点で、私が自分の周りのすべてがいかに間違っているかをあまり知らなかったときに、私が再びジュニア開発者になればいいのにと思います。私は中途半端な危機に早く直面しているようです。しかし、私はとりとめのない...助けてうれしいです。
maple_shaft

1
@Murphメンテナンスフェーズ中に、すべてを知っているチームリーダーがいないのはなぜですか?関係なく、チームリーダーにこれまで以上に期待していたすべてのボス。
maple_shaft

1
@maple_shaft a)そのプロジェクトに専念するチームリーダーがいて、それが多かれ少なかれ最初の要件であるとは思いません。b)デザイン実装(すべて)を理解する必要があると思います。ハード。一方では、プロジェクトに関するすべての知識の単一のフォントを使用するべきではないと主張しますが、ここでは1つ持っている必要があると言っています。それは合計されませんか?
マーフ

2
@maple_shaftおそらく私は気難しい古いプログラマーです(-:しかし、多くの場合、既存のコードベースの奥深くに従う必要がある実装の「スタイル」であるという問題があります-そして、それはコーダーとリードの両方にとって異質かもしれません(多くの場合現実世界の理由の)。
Murph

18

できることはいくつかあります。

アーキテクチャ全体に対して1人の責任を与えます。その人を選ぶときは、アーキテクチャを開発および維持するためのビジョンとスキルを持ち、他の開発者がアーキテクチャに従うのを支援する影響力と権限を持っていることを確認してください。その人は、経営陣から信頼され、仲間から尊敬されているベテランの開発者でなければなりません。

すべての開発者がアーキテクチャを所有する文化を作成します。すべての開発者は、アーキテクチャの整合性を開発および維持するプロセスに関与する必要があります。

アーキテクチャの決定が容易に伝達される環境を開発します。人々に、現在のプロジェクトの文脈だけでなく、一般的にも、設計とアーキテクチャについて話すように勧めます。

コーディングのベストプラクティスにより、コードからアーキテクチャを簡単に確認できます。リファクタリング、コードのコメント、単体テストの開発などに時間がかかります。命名規則やクリーンなコーディングプラクティスなどは、アーキテクチャの伝達に役立ちます。独自の標準を開発し、それに従うために時間をかける。

必要なすべてのドキュメントが明確で簡潔、最新かつアクセス可能であることを確認してください。高レベルと低レベルの両方のアーキテクチャ図を公開し(壁に固定すると役立つ)、一般に保守可能にします。

最後に(自然な完璧主義者として)アーキテクチャの完全性は価値ある願望ですが、より重要なこともあることを認識しておく必要があります。


1
+1、特に「うまく連携して実際に機能する製品を出荷できるチームを構築する」ため。
-deworde

1
1人の人がアーキテクチャの責任を負うことをお勧めします。ただし、その責任が頻繁に使用される場合、「チームのにおい」があります。チームは、回答を提供するのに1人の人に頼るのではなく、自然に共通の結論に達する必要があります。どうして?プロジェクトの全知識は常に共有され、1人に固定すると最終的にはより大きな問題につながります。彼の意見だけが満足され、チームの残りの部分を効果的に削減します。代わりに、最高の人材を雇い、彼らに一緒に解決させます。
キャスパー

1
@casper:そのとおりです。あなたは私が思っていたものを、私がやったよりもずっとよく表しています。
Kramii

18

私がこの問題に取り組む方法は、ルートでそれを切り取ることです:

私の説明では、Microsoft / .NETの用語を使用しますが、すべてのプラットフォーム/ツールボックスに適用できます。

  1. 命名、コーディング、チェックイン、バグフロー、プロセスフローに標準を使用します-基本的には何でも。
  2. 標準を順守していないチームメンバーに別れを告げることを恐れないでください。一部の開発者は、定義された標準セット内で作業することができず、コードベースをクリーンに保つために戦場で5列目の敵になります
  3. スキルの低いチームメンバーを長期間テストすることを恐れないでください。
  4. 武器庫内のすべてのツールを使用して、腐敗コードのチェックインを回避します。これには、専用のツールと、ビルドファイル、プロジェクトファイル、ディレクトリ構造などをテストする事前に作成されたユニットテストが含まれます。
  5. 約5〜8人のメンバーで構成されるチームで、あなたの最高の男にほぼ常にリファクタリングを行わせます。他の人が残した混乱を一掃します。たとえその分野で最高の専門家を見つけたとしても、混乱は避けられません-それは避けられませんが、絶え間ないリファクタリングによって制約される可能性があります。
  6. 単体テストを作成して保守します-プロジェクトをクリーンに保つために単体テストに依存しないでください。
  7. すべてを話し合います。チームで物事を議論するのに何時間も費やすことを恐れないでください。これにより、情報が広まり、不正なコードの根本原因の1つであるテクノロジー、目標、標準などの混乱が解消されます。
  8. コンサルタントがコードを書く際には非常に注意してください。ほとんどの場合、彼らのコードは本当のくだらないものになります。
  9. チェックイン前のプロセスステップとして、できればレビューを行ってください。コミットをロールバックすることを恐れないでください。
  10. リリース前の最後の段階にない限り、オープン/クローズの原則を使用しないでください。コードの臭いがするだけです。
  11. 問題が発生したときはいつでも、ソリューションを実装する前に十分に時間をかけて理解してください。ほとんどのコードの腐敗は、完全に理解されていない問題に対するソリューションの実装に起因します。
  12. 適切なテクノロジーを使用してください。これらはしばしばセットになって新鮮になります:サポートされていない非常に安定しているが時代遅れのフレームワークに依存するよりも、将来サポートされることが保証されているフレームワークのベータ版に依存する方が良いです。
  13. 最高の人を雇います。
  14. 残りをレイオフ-あなたはコーヒーショップを運営していません。
  15. 経営陣が最高のアーキテクトではなく、意思決定プロセスに干渉する場合は、別の仕事を見つけてください。

1
さて、「予備時間」でC#の書き換えを行いながら、悪夢のような12年前のVB6アプリを100種類のフォームとクラスで維持し、強化しなければならなかったらどうしますか?
-jfrankcarr

7
#3に反対。テストは、訓練を受けていない人に対する罰と見なされるべきではありません。実際、それはすべての開発者が行い、コーディングと設計と同様に重要であるとみなされるべきです!チームに未訓練の人がいる場合、トレーニングのために彼をチームから降ろしてください!
-NWS

1
「#3に反対。テストは訓練されていない人に対する罰と見なされるべきではありません。」-それは私が書いたものではなく、説明すべきではありません。テストは、あなたがまだコードを取得するために変更をコミットすることを信頼していない人々に許可する良い方法です。私が見つけた最高のテスターは、コードの貢献者になりたいと思っている人で、コードを調べてプログラムを実行することで能力を証明しており、ランタイムでの発見をソースコードと相関させる能力を示しています。それは罰ではありません-その訓練。
キャスパー

1
「#10に同意しない-正しく行われればコードの品質が向上する」これは私の実務経験では絶対に間違っています。ロックされたコードはリファクタリングできません。つまり、ロックが解除されるまで現在の状態のままになります この状態は、ある段階で機能していることを確認できますが、後の段階ではこの確認は誤検知です。すべてのコードは、最終システムテストの前の段階までリファクタリングのために開いたままにする必要があります。
キャスパー

3
@casper:私見、オープン/クローズの原則は「ソースを変更することはできない」と理解すべきではなく、「コードがフリーズするように設計する」必要があります。変更を要求せずに、コードをnessisaryとして拡張できることを確認してください。その結果、平均的なコードよりも疎結合であり、結合性が高くなっています。この原則は、サードパーティが使用するためのライブラリを開発するときにも重要です。サードパーティがコードを入力して変更することはできないため、適切に拡張できる必要があります。
ケビンキャスカート

12

単体テストを作成しながら、リファクタリングにより腐敗したコードをクリーンにします。次の場合はいつでも、触れるすべてのコードに対して(この)設計上の負債を支払います。

  • 新しい機能を開発する
  • 問題を修正する

テストファースト開発サイクルを大幅にスピードアップします:

  • コードモジュールをスクリプト言語に変換するリファクタリング
  • 高速なクラウドベースのテストマシンを使用する

コードをリファクタリングして、(非常に内部凝集性の高い)低結合を使用します:

  • より単純な(その他の)関数(ルーチン)
  • モジュール
  • オブジェクト(およびクラスまたはプロトタイプ)
  • 純粋な機能(副作用なし)
  • 継承よりも委任を優先する
  • レイヤー(APIを使用)
  • 一緒に動作することができる小さな、単一目的のプログラムのコレクション

有機的成長は良好です。大きな初期設計は悪いです。

現在の設計について知識のあるリーダーを配置します。そうでない場合は、知識が得られるまでプロジェクトのコードを読んでください。

リファクタリングの本を読んでください。


1
+1良い最初の答え、私たちを自己紹介する完璧な方法!
ヤンニス

11

簡単な答え:できません

だから、小さくシンプルなソフトウェアを書くことを目指すべきです。簡単ではない。

それは、一見複雑に見える問題について、できるだけ単純で簡潔な方法でそれを定義するのに十分長い間考えている場合にのみ可能です。

小さくてシンプルなモジュールを構築することで、本当に大きく複雑な問題の解決策を解決できることがよくあります。

言い換えれば、他の人が指摘したように、単純さと疎結合が重要な要素です。

それが不可能または実行可能でない場合は、おそらく研究を行っています(既知の単純な解決策がない、または既知の解決策がまったくない複雑な問題)。研究が保守可能な製品を直接生産することを期待しないでください。それは研究の目的ではありません。


9

1999年から継続的に開発されている製品のコードベースに取り組んでいるので、ご想像のとおり、かなり複雑になっています。コードベースのハッキングの最大の原因は、ASP ClassicからASP.NETへ、ADOからADO.NETへ、ポストバックからAjaxへ、UIライブラリの切り替え、コーディング標準などを何度も移植しなければならなかったことです。

全体として、コードベースを保守可能な状態に保つ合理的な仕事をしました。これに貢献した主なことは次のとおりです。

1)継続的なリファクタリング-ハッキングや理解しにくいコードに触れる必要がある場合、それをクリーンアップするのに余分な時間がかかることが予想され、そうするためのスケジュールの余裕が与えられます。ユニットテストを使用すると、回帰をより簡単にテストできるため、これがはるかに怖くなりません。

2)きれいな開発環境を維持する-使用されなくなったコードの削除には注意し、プロジェクトディレクトリにバックアップコピー/作業コピー/実験コードを残さないでください。

3)プロジェクトの存続期間中一貫したコーディング標準-それに直面しましょう。コーディング標準に関する私たちの見解は時間とともに進化します。戻って新しい標準に準拠するためにすべてのコードを改良する時間がない限り、プロジェクトの存続期間中はあなたが始めたコーディング標準に従うことをお勧めします。ハンガリー語の表記法理解していることは素晴らしいことですが、その教訓を新しいプロジェクトに適用し、その新しいプロジェクトの途中で切り替えることはしないでください。


8

あなたはプロジェクト管理で質問にタグを付けたので、私はいくつかの非コードポイントを追加しようとしました:)

  • 離職の計画-開発チーム全体がメンテナンスフェーズに達するまでに姿を消すことを想定します-自分のシステムを永久に維持するのに苦労したい開発者はいません。時間があるとすぐに引き渡し資料の準備を開始します。

  • 一貫性/均一性を十分に強調することはできません。これは、「独りで行く」という文化を思いとどまらせ、新しい開発者に疑問があるかどうか尋ねることを奨励します。

  • チームの新しい開発者(どのレベルでも)がすぐに立ち上がって実行できる可能性が高くなるため、使用するテクノロジ、設計パターン、および標準を主流にしてください。

  • ドキュメント-特にアーキテクチャ-決定が行われた理由とコーディング標準。また、ビジネスドメインを文書化するための参照/メモ/ロードマップを保持します。ドメインエクスペリエンスのない開発者に企業ビジネスが何をしているのかを説明するのは非常に困難です。

  • 現在の開発チームのためだけでなく、将来のメンテナンス開発者についても考えてください。これが、関連するデザインへのハイパーリンクを配置し、すべてのページに標準ドキュメントをコーディングすることを意味する場合は、そうしてください。

  • アーキテクチャと特にコードレイヤーが明確に区別され、分離されていることを確認します-これにより、新しいテクノロジーが登場するにつれてコードのレイヤーを置き換えることができます。たとえば、WebフォームUIをHTML5 jQuery UIなどに置き換えることができます。長寿を追加して1年ほど購入します。


7

高度に維持可能なコードの1つの特性は、関数の純度です。

純度とは、関数が同じ引数に対して同じ結果を返すことを意味します。つまり、他の関数の副作用に依存するべきではありません。さらに、副作用がない場合にも役立ちます。

このプロパティは、カップリング/凝集プロパティよりも簡単に目撃できます。あなたはそれを達成するためにあなたの邪魔をする必要はありません、そして私は個人的にそれがより価値があると思います。

関数が純粋な場合、その型はそれ自体非常に優れたドキュメントです。さらに、引数/戻り値の観点からドキュメントを書いたり読んだりすることは、グローバルな状態(他のスレッドO_Oによってアクセスされる可能性がある)に言及するよりもはるかに簡単です。

保守性を高めるために純度を広範囲に使用する例として、GHCを見ることができます。これは約20年前の大規模なプロジェクトであり、大規模なリファクタリングが行われ、新しい主要機能がまだ導入されています。

最後に、「シンプルに保つ」という点があまり好きではありません。複雑なものをモデリングする場合、プログラムをシンプルに保つことはできません。単純なコンパイラを作成してみてください。生成されたコードは、おそらく非常に遅くなります。確かに、個々の機能を単純にすることはできます(そしてすべきです)が、結果としてプログラム全体が単純になることはありません。


2
あなたが説明する別の名前は、決定論的であるという特性です
ジングレスチュラ14

6

他の答えに加えて、レイヤーをお勧めします。多すぎませんが、異なるタイプのコードを分離するには十分です。

ほとんどのアプリケーションで内部APIモデルを使用しています。データベースに接続する内部APIがあります。次に、UIレイヤー。アプリケーションの他の部分を中断したり壊したりすることなく、さまざまな人が各レベルで作業できます。

別のアプローチは、すべての人にcomp.risksThe Daily WTFを読んでもらい、悪いデザインと悪いプログラミングの結果を学び、The Daily WTFに投稿された自分のコードを見ることを恐れます。


6

これらの回答の多くは、当初から大きなチームに焦点を当てているように思われるため、スタートアップの2人の開発チーム(デザイナーを含めて3人)の一部として自分の見解を述べます。

明らかに、シンプルなデザインとソリューションが最善ですが、文字通り給料を支払う人が首を下ろしている場合、最もエレガントでシンプルで保守可能なソリューションについて考える時間は必ずしもありません。それを念頭に置いて、私の最初の大きなポイントは:

ドキュメントコメントではなく、コードはほとんど自己文書化する必要がありますが、デザインドキュメント、クラス階層と依存関係、アーキテクチャパラダイムなどのようなものです。新しい、または既存のプログラマーがコードベースを理解するのに役立つもの。また、「このクラスをこの機能の要素に追加する」など、最終的にポップアップする奇妙な疑似ライブラリを文書化することも役立ちます。

ただし、時間制限が厳しい場合でも、留意すべきもう1つの良い点は次のとおりです。

ハッキングや迅速な修正を避けます。クイックフィックスが実際のフィックスでない限り、根本的な問題を何かに突き止めてから修正する方が常に良いです。「次の2分間でこれを機能させるか、解雇される」というシナリオを文字通り持っていない限り、今すぐ修正を行うことをお勧めします。コードを後で修正する必要はないので、次のタスクに進みます。

そして、私の個人的なお気に入りのヒントは引用のようなものですが、ソースを思い出すことはできません:

「あなたの後に来る人は、あなたがどこに住んでいるかを知っている殺人精神病患者であるかのようにコード化してください」


構文の強調表示を使用して関数とクラスの場所でコードセグメントを分離するだけでも、関数とクラスのコメントが役立つことが常にわかっています。関数コードにコメントを入れることはめったにありませんが、クラスや関数ごとに、/** Gets the available times of a clinic practitioner on a specific date. **/or などの行を書き/** Represents a clinic practitioner. **/ます。
ニックベッドフォード

5

言及していないが私が重要だと思う原則の1つはオープン/クローズド原則です。

開発およびテストされたコードは変更しないでください。そのようなコードは封印されています。代わりに、サブクラスを使用して既存のクラスを拡張するか、ラッパー、デコレータークラスを記述するか、適切なパターンを使用して使用します。ただし、動作中のコードは変更しないでください

ちょうど私の2セント。


作業コードで表現されたビジネス要件が変更された場合はどうなりますか?特に必要な変更を行う時が来た場合、ファクタリングは不十分だが技術的には「機能する」コードに手を触れないことは、長期的にはあなたを傷つける可能性があります。
ジングレスチュラ14

@jinglesthula:Open for extensionは、既存のインターフェイスの新しい実装(クラスなど)として新しい機能を追加できることを意味します。もちろん、不十分な構造のコードはこれを許可しません。既存のコードを変更するのではなく、新しいコードを追加することでコードを「変更」できるインターフェースのような抽象化が必要です。
ジョルジオ14

5
  • スカウトになりましょう。見つけたコードよりも常にコードをきれいにしておきます。

  • 壊れたウィンドウを修正します。これらのコメントはすべて、バージョン3.0を使用しているときに「バージョン2.0で変更」されます。

  • 大規模なハッキングが発生した場合は、チームとしてより良いソリューションを設計して実行します。チームとしてハックを修正できない場合、システムを十分に理解していません。「大人に助けを求めてください。」周りの最も古い人々はこれを前に見たことがあるかもしれません。システムの図を描画または抽出してみてください。相互作用図として特にハッキングされているユースケースを描画または抽出してみてください。これは修正されませんが、少なくともあなたはそれを見ることができます。

  • 特定の方向に設計を押しやったどのような仮定はもはや真実ではありませんか?その混乱のいくつかの後ろに隠れている小さなリファクタリングがあるかもしれません。

  • システムがどのように機能するかを説明し(1つのユースケースでさえ)、サブシステムを何度も謝罪しなければならないことに気付いた場合、それが問題です。どんな動作があれば、システムの残りの部分がよりシンプルになります(実装されているものと比較して実装するのがどんなに難しくても)。書き換える古典的なサブシステムは、他のすべてのサブシステムをその動作セマンティクスと実装で汚染するものです。「ああ、frooサブシステムに値を入力する前に値をgrozする必要があります。frooから出力を取得したら、それらの値を再びungrozします。そして、システムの残りの部分は間違っていますか?これは、2つ以上の異なるgrozificationsがあるとき、より刺激的になります。

  • 実際の問題が見えるように、警告を削除するチームとして1週間過ごします。

  • すべてのコードをコーディング標準に再フォーマットします。

  • バージョン管理システムがバグトラッカーに関連付けられていることを確認してください。これは、将来の変更が素晴らしく説明責任があることを意味し、なぜ解決できるかを示しています。

  • いくつかの考古学を行います。元の設計文書を見つけて、レビューします。彼らは、オフィスの隅、廃屋のスペース、誰も開かないファイリングキャビネットの古いPCにいるかもしれません。

  • Wikiで設計ドキュメントを再公開します。これは知識の制度化に役立ちます。

  • リリースおよびビルド用のチェックリストのような手順を作成します。これにより、人々が考える必要がなくなり、問題の解決に集中できます。可能な限りビルドを自動化します。

  • 継続的な統合を試してください。ビルドの失敗が早くなると、プロジェクトがレールから離れる時間が短くなります。

  • チームリーダーがこれらのことを行わない場合、それは会社にとって悪いことです。

  • 新しいコードはすべて、測定されたカバレッジで適切な単体テストを取得するようにしてください。したがって、問題はそれほど悪化することはありません。

  • 単体テストされていない古いビットの一部を単体テストしてみてください。これにより、変化の恐れを減らすことができます。

  • 可能であれば、統合および回帰テストを自動化します。少なくともチェックリストがあります。パイロットは賢く、多くの給与を受け取り、チェックリストを使用します。また、めったにめちゃくちゃになりません。


4

Steve McConnellによるCode Completeを読んでから、もう一度読んでください。それは、最初のプロジェクト設計からコードの1行およびその間のすべてまで、優れたソフトウェア記述のバイブルのようなものです。私が最も気に入っているのは、何十年にもわたる確かなデータに裏付けられていることです。それは、次善のコーディングスタイルだけではありません。


3

これを「ウィンチェスターミステリーハウスエフェクト」と呼ぶようになりました。家のように、それは十分にシンプルに始まりましたが、長年にわたって、多くの異なる労働者は、誰もそれを本当に理解していない全体的な計画なしで非常に多くの奇妙な機能を追加しました。なぜこの階段はどこにも行かず、なぜそのドアは片道しか開かないのですか?知るか?

この効果を制限する方法は、拡張を処理するのに十分な柔軟性を備えた適切なデザインから始めることです。これに関していくつかの提案が既に提供されています。

しかし、多くの場合、すでに損傷が発生している仕事に就くことになり、高価でリスクを伴う可能性のある再設計と書き換えを実行せずに、優れた設計には遅すぎます。そのような状況では、ある程度混乱を抑えながら混乱を制限する方法を見つけるのが最善です。すべてが巨大でいシングルトン「マネージャー」クラスを通過する必要があることや、データアクセスレイヤーがUIに密接に結合されていることをデザインの感覚に迷惑をかけるかもしれませんが、対処することを学びます。そのフレームワーク内で防御的にコーディングし、過去のプログラマーの「ゴースト」が出現したときに予期しないことを期待しようとします。


2

コードのリファクタリング単体テストはまったく問題ありません。しかし、この長期実行プロジェクトはハッキングに駆り立てられているため、これは経営陣が腐敗を一掃するために足を踏み入れていないことを意味します。誰かが人々を訓練して問題/リクエストを分析するのに十分なリソースを割り当てていないため、チームはハッキングを導入する必要があります。

長期にわたるプロジェクトの維持は、個々の開発者と同じくらいプロジェクトマネージャーの責任です。

彼らはそれが好きなので、人々はハックを導入しません。彼らは状況によって強制されています。


状況によって強制されますか?ハッキングを導入する理由は、(a)よくわからない =>コーチングが必要、(b)全体像が見えない =>コミュニケーション、ドキュメント、規律が必要、(c)より賢いと思う =>それが最大だ克服するためのハードル(d)状況によって強制される =>時間的なプレッシャーにさらされた場合、迅速なホットフィックスは問題ありませんが、誰かが責任を負い、その後コードをクリーンアップする必要があります。その他の「状況」は単にBSです。その経験則には例外がありますが、最もいわゆる例外は「怠laz」を意味します。
JensG 14年

2

非技術的な問題と(おそらく)実用的なアプローチをしたいだけです。

マネージャーが技術的な品質(管理可能なコード、シンプルなアーキテクチャ、信頼できるインフラストラクチャなど)を気にしない場合、プロジェクトを改善するのは難しくなります。この場合、管理者を教育し、保守性技術的負債への取り組みに「投資」するよう説得する必要があります。

それらの本に見られるコード品質を夢見ているなら、これを心配している上司も必要です。

または、「フランケンシュタインプロジェクト」を飼いならしたい場合は、次のヒントを参考にしてください。

  • 整理と簡素化
  • 機能を短縮する
  • 読みやすさを効率よりも優先します(もちろん許容範囲内であり、一部の効率の向上は維持できないほど悲惨です)

私の経験では、プログラミングは創発的というよりもエントロピーです(少なくとも一般的な命令構造パラダイムでは)。人々が「ただ動作する」ようにコードを書くとき、その組織を失う傾向があります。現在、コードの整理には時間が必要であり、時にはそれを単に機能させるだけではありません。

機能の実装とバグ修正以外にも、コードのクリーンアップに時間をかけてください。


「...プロジェクトは運命にある」 -私の経験では、これは必ずしもそうではありません。代替言っマネージャーを教育し、努力の中に「投資」するために説得することで保守性およびアドレッシング技術・負債
ブヨ

マネージャーが技術的負債に関する私のアドバイスをすべて無視したときにすでに経験したので、申し訳ありませんが、私はそれを書くことを我慢できませんでした。しかし、あなたは正しいと思います。そのプロジェクトをあきらめた約1年後、マネージャーは技術チームを管理することができないため、技術チームに対する権限をすべて失いました。
Eric.Void 14

1

多数の回答のどれもが明白なことを強調していないことに驚いた。ソフトウェアを多数の小さな独立したライブラリで構成する。多くの小さなライブラリを使用すると、大きくて複雑なソフトウェアを構築できます。要件が変更された場合、コードベース全体を破棄したり、現在実行中のもの以外の何かを行うために大きな警doコードベースを変更する方法を調査する必要はありません。要件を変更した後でも、これらのライブラリのうちどれが関連するか、それらをどのように組み合わせて新しい機能を持たせるかを決めるだけです。

ライブラリを簡単に使用できるように、これらのライブラリでプログラミング技術を使用します。たとえば、関数ポインタをサポートする非オブジェクト指向言語は、実際にはオブジェクト指向プログラミング(OOP)をサポートしていることに注意してください。したがって、たとえばCでは、OOPを実行できます。

これらの小さな独立したライブラリを多くのプロジェクト間で共有することを検討することもできます(gitサブモジュールはあなたの友人です)。

言うまでもなく、それぞれの小さな独立したライブラリはユニットテストされるべきです。特定のライブラリが単体テスト可能でない場合、何か間違ったことをしていることになります。

CまたはC ++を使用し、多くの小さな.soファイルを作成するという考えが嫌いな場合は、すべてのライブラリをリンクして大きな.soファイルにするか、静的リンクを実行できます。同じことがJavaにも当てはまります。.soを.jarに変更するだけです。


これは私の観点からは少し理論的すぎるようです。もちろん、私の質問で言及したプロジェクトは、複数のライブラリとモジュールで構成されていました。過去26年間のソフトウェア開発での私の経験は、プロジェクトが古いほど初期の組織を獲得すること
でした-chrmue

0

シンプル:メンテナンス可能な数の可動部品ができるまで、ほとんどのコードのメンテナンスコストをゼロまで減らします。変更する必要のないコードには、メンテナンスコストはかかりません。私は、多くの小さくて面倒なリファクタリングの繰り返しにかかるコストを削減しようとせずに、コードのメンテナンスコストを本当にゼロにすることを目指すことをお勧めします。すぐにコストをゼロにします

さて、確かにそれはたくさんあります。しかし、始めるのは難しくありません。インターフェース設計が混乱している場合は、コードベースのチャンクを取得してテストし、その上に素敵なインターフェースを構築し、同時に信頼できる、安定した(変更する理由がないため)コードベースの部分の成長を開始することができます信頼性が低く不安定な部分を縮小します。維持するのが悪夢のように感じるコードベースは、多くの場合、すべてが信頼性が低く、変更されやすいと見なされるため、変更する必要がある可動部分とそうでない部分を区別しません。

実際、コードベースの組織を「安定」部分と「不安定」部分に分離することをお勧めします。安定部分は、再構築および変更するための巨大なPITAです(これは良いことです。それらが本当に「安定」セクションに属している場合、変更および再構築されます)。

保守性を難しくするのはコードベースのサイズではありません。維持する必要があるのはコードベースのサイズです。たとえば、オペレーティングシステムのAPIを使用するときは常に、何百万行ものコードに依存しています。しかし、オペレーティングシステムのソースコードを保守する必要がないため、これは製品の保守コストには寄与しません。コードを使用するだけで機能します。私が単に使用するだけで、保守する必要のないコードは、私の側で保守費用が発生しません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.