私は高校生で、C#プロジェクトに携わっている友人と私のスキルレベルはほぼ同じです。これまでに、約3,000行のコードと250行のテストコードを100回のコミットのスパンで記述しました。学校の都合で、プロジェクトを数か月延期しましたが、最近、再び取り戻すことができました。
私がそれを取り戻したときまでに、レンダラーに過剰なスレッドを含める、エミュレートされたCPU、GPU、およびゲームカートリッジ間の相互作用における競合状態の防止が不十分であるなど、私が書いたコードは設計が不十分であることがわかりましただけでなく、単に冗長で混乱を招くコードも同様です。
問題は、プログラムの主要な機能もまだ完成していないため、本当にリファクタリングできず、コードの設計に欠陥があることを完全に認識し続けることは思いがけないことです。同時に、私はプロジェクトを放棄したくありません。かなりの進歩があり、仕事が無駄になってはいけません。
いくつかの選択肢があるように感じます:貧弱なデザインを回避して機能を完成させ、すべてが機能するようになったらリファクタリングし、すべてを停止し、残りの機能が完了する前にすべてを解きほぐしてプロジェクトを開始しますそれがまた私の心の中で新鮮になるように、あるいはその過度のサイズのためにプロジェクトを完全に放棄するように(本質的には「図面に戻る」)。
そのようなプロジェクトにおける他の人の経験に基づいて、自分を正しい軌道に戻すための手段は何ですか?このサイトの回答から、一般的なコンセンサスは 書き換えは通常不要です ですが、コードを過度のコストなしに維持できない場合に利用できるオプションです。私は本当にこのプロジェクトを追求したいと思っていますが、現状では、私のコードは私が継続するのに十分に設計されておらず、落胆感が私を継続させません。
私があなたの立場にあったなら、私はおそらくこのようにそれを試してみるでしょう:
最初に、現在のプロジェクトを少なくとも部分的に-できるだけ早く完了しますが、作業状態です。おそらく、元の目標を下げる必要があります。「バージョン1.0」で本当に必要な最低限の機能について考えてください。
次に、そしてそのときだけゼロからの書き換えについて考えます(これを「バージョン2.0」と呼びます)。たぶん、V1.0のコードの一部を再利用できます。多分、あなたがその状況で再び眠った後、あなたはV1.0をリファクタリングしてその大部分を保存することができるという決定に達したでしょう。ただし、「概念実証V1.0」が手元にない場合は、この決定を行わないでください。
動作しているプログラム「1.0」は、コードが悪い場合でも(他の誰も気にしないでしょうが、自分を除いて)他の人に見せることができるものです。 V2.0を作成している最中に時間が足りなくなったことに気づいた場合でも、部分的に成功したV1.0が残っているので、士気が大幅に向上します。ただし、先にV1.0を完成させないと、途中でもう一度デザインに不満を感じるようになるため、V2.0が完成しない可能性が高いです。再びV2.0を放棄してV3.0で作業しますか?この決して終わらない円にぶつかり、決して終わらないという高いリスクがあります。
これを、プロジェクトを未完成の状態にしておく方法を学ぶ機会ではなく、中間目標を達成する方法を学ぶ機会と捉えてください。
完成したITプロジェクトは、不完全なプロジェクトであっても、未完成のプロジェクトよりもはるかに優れています。
未完成のものもあなたに多くを教えることができますが、完成したものほどではありません。
今は表示されないかもしれませんが、欠陥のあるコードでも機能する膨大な価値があります。
私の投票は、最終的に、そしておそらく、リファクタリングに行きます-必要であれば。さらに多くのプロジェクトで作業を開始すると、驚くべきことに、「リファクタリングするつもりだった」部分は何年も変更されずに残り、他の部分は拡張されることがわかります。
雇用の観点からは、ほとんどの場合、完成したプロジェクトに対してより多くの賞賛が得られます。
私は喜んでプロジェクトをやり直します。
あなたは学生であり、まだ学んでいます。これにより、リンク先の質問とは非常に異なる立場にいます。
あなたはあなたのコードに対して専門的な責任を負いません。今すぐプロジェクト全体を削除して立ち去ったとしても、影響はありません。これは開発者にとって大きな利点です。あなたがリンクした質問では、それらの開発者は人々がお金を払っているソフトウェアを維持しようとしています、そして小さなバグでさえ顧客に大きな問題を引き起こす可能性があり、ゼロから書くのは危険です。その問題はありません。
個人的なプロジェクトとして、これは新しいことに挑戦し、間違いから学ぶ絶好の機会です。古いコードに問題があることを認識するのは素晴らしいことです。それは、より良い方法を学んだことを意味します。試行錯誤による経験は、初心者のプログラマーにとって非常に貴重です。
プロジェクトは比較的小さく、基本的にテストはありません。特に次に何をすべきかについてすでにアイデアを持っているので、3000行を最初から作成するのは数夜と短いかもしれません。
壊れたコードベースで作業することは、書き換えが行うよりもはるかに大きな士気の浪費になります。
余談ですが、これはユニットテストを使用してよりモジュール化されたプログラムを作成するための絶好のチャンスです。そうすることで、長い休憩の後でコードに戻った場合にコードをより簡単に理解できるようになり、物忘れのために誤って導入する可能性のあるエラーを防ぐのに役立ちます。
最後に、 here は、大きなステップを前に進めるために、時々逆戻りするという知恵に関する意見の1つです。
あなたはおそらくあなたの開発の「速く学ぶ」部分にいるでしょう。今から数か月後には、新しくて素晴らしいデザインが、始めたときに気づかなかった方法でひどく壊れていることに気付くでしょう。
物事を成し遂げる-これはあなたが学ぶ必要がある単一の最も重要なことです。私を信じて、「このプロジェクトに着手する前に多くのことを学んだので、最初からやり直す」ループで立ち往生している多くの人々(プログラマーだけでなく)を知っています。問題はそれは決して終わらない-新しいことを学ぶのを止めるまで、これは良い場所ではない:)
実際に何かを仕上げられるようにすることも重要です。最初からやり直すことは、エキサイティングで、クールで、楽しいことです...しかし、それを学んだだけでは、何も終えることはできません。繰り返しになりますが、それはあまり有用な能力ではありません。実際、何かを有用(または楽しい)にするほど良いとは言えません。人生は短く、時間が限られているので、具体的な結果がないまま練習を続けることはできません。そこからかなり怒るでしょう。どのアプローチを採用するかを決めることができないために仕事を始めることができない場合は、すでに危険ゾーンにいます。
最初からやり直す衝動が常にあります。学習環境でさえ、それらはおそらく悪い考えです。だからといって、プロトタイプをすべてプロダクション対応のアプリケーションに運ぶ必要があるわけではありません。しかし、あなたは少なくともプロトタイプ段階に入る必要があります-それはおそらくあなたの士気を助けるでしょう、そしてそれはあらゆる種類の開発者にとって非常に有用な特性です。 物事を成し遂げる。楽しい部分は、プロトタイプを使用して「ゼロから書き直す」よりも、さらに多くの場合それをリファクタリングすることで、100万以上の楽しいまたは便利なことができることがすぐにわかるでしょう。あなたがするすべてのことにはコストがかかります-少なくとも、その間に他の何かをしていたかもしれません。
私はソフトウェア開発における "Make it Work、Make it Right、Make it Fast" イデオロギーに従います。
現在、ステップ1は完了していません。最初に機能させてから、コードがいかに醜いかを心配することができます。実際に機能する製品を作成することは、初めての開発者がコードを完璧にしようとすることに巻き込まれ、Optimization Hellに行き詰まり、実際に仕上げに取り掛からないため、新しい開発者にとって最も難しい作業の1つです。すべての機能を実装します。ソフトウェアを動作させることに集中できるように、リファクタリングと最適化に関するこれらすべての心配事を脇に置く方法を学ぶ必要があります。ある程度の経験を積むと、最初は当然、より多くのことを正しく行えるようになるため、必要なリファクタリングは少なくなります。
覚えておいてください: 時期尚早な最適化はすべての悪の根源です (良い議論については この優れたProgrammers.SEの質問 を参照してください)。コードを改善する方法を考えるのに時間をかけすぎると、 解析麻痺 に陥ります。これはプロジェクトを殺します。最適化を開始する前に、プロジェクトを完了させることをお勧めします。
やる気を起こさせる優れた講演者を引用するには:やるだけです。
いつものように、関連するxkcdがあります:
書き直してください。機能しないコードはほとんど価値がなく、3千行はあまりコードではありません。現在お持ちのコードを書くのにかかる時間とほぼ同じくらいかかりませんし、ずっと良いでしょう。私はしばしば500行または1000行の貧弱なコードを破棄しましたが、多くの場合、書き換えは1/5です。
「書き換えない」に関する概念のほとんどは、大規模なシステムが重要なことを行い、進化する要件を満たすために絶え間なく変化することに関連しています。使用中の複雑なシステムの書き換えはほとんど成功しません。
あなたの状況は全く正反対です。ユーザーのいない小さなアプリケーションがあり、唯一の要件は、実装することを選択したものです。だから先に進んでそれを書き直してください。
ゼロから再起動することは、通常、実際のプロジェクトでは悪い動きです。これは主に、実際のプロジェクトに、新しい開発者が気付かないバグ修正が蓄積されているためです(たとえば、 絶対にやらないこと を参照)。 fromJoel on Softwareblog。)
それにもかかわらず、学校のプロジェクトはそのような歴史を継承せず、通常、コーディングと設計と同時に、コンピューティングの部分的な知識と経験の欠如から始まります。私はあなたの最初のバージョンをプロトタイプと見なし、失敗した概念実証として使用しました。私は喜んでそれを捨てます( 使い捨てと進化的プロトタイプの違いは何ですか? 使い捨てvs進化的プロトタイピングについての議論。)
適切なデザインは頭の中で成熟しているので、コードで記述するのにそれほど時間はかかりません。
書き換えは悪い考えだという提案には敬意を払いません。
ソフトウェアライフサイクルの領域では、エラーを修正するために必要な時間と労力は、ライフサイクルの各レイヤーの桁で増加することが一般に受け入れられています。つまり、要件レベルでエラーを修正するのに1時間かかる場合、設計には10時間、コーディングテストには100時間、バグ修正には1000時間かかります。これらの数値は法外に聞こえるかもしれませんが、ほぼ正しいと業界で認められています。明らかに、小規模なプロジェクトでは少ないですが、一般的な考え方は残っています。プロジェクトに基本的な設計上の欠陥がある場合は、それを学習体験と呼び、戻って初期要件を確認して再設計する方が適切です。
また、構造化単体テストを使用したテスト駆動開発モデルを検討することをお勧めします。それらは苦痛であり、最初は時間の無駄のように見えますが、特に他の誰かのコードと統合するとき、エラーを発見するそれらの能力は言い過ぎではありません。
あなたはこの文章で私を失った:
問題は、プログラムの主要な機能もまだ完成していないため、本当にリファクタリングできず、コードの設計に欠陥があることを完全に認識し続けることは思いがけないことです。
私は( Systemantics で述べられている)原則を信じています
- 機能する複雑なシステムは、機能する単純なシステムから進化したものであることが必ずわかります。
- ゼロから設計された複雑なシステムは機能せず、パッチを適用して機能させることはできません。シンプルなシステムから始めて、最初からやり直す必要があります。
したがって、複雑なシステムの記述には、
...つまり、次の手順:
ステップ3には以下が含まれることに注意してください。
また、ステップ2の「テストして機能することを確認する」では、機能しない場合は書き換えが必要になる場合があります。
私が腐ったコードベースで構築している場合、私はさらなる機能を追加することに消極的になるでしょう。したがって、私は、「既存のスレッド実装を単純化する」のようなものを、実装される次の作業としてスケジュールする傾向があります。あなたが進んでいる間あなたがテストしていると仮定すると、あなたはこれをリファクタリングの練習として扱うことができるはずです。この作業フェーズの成功/終了基準は次のとおりです。
ちなみに、「動作確認のためのテスト」は必ずしも「単体テスト」を意味するわけではありません。チーム構造が単純な場合は、 (simple)を使用して(単純な)システムをテストできます。システムテスト(代わりに単体テスト) 。
このような問題が発生したときに直面する問題の1つは、これまでに作成したコードに何らかの形で感情的に執着していることです。
有名な教授からレッスンを受けているときに、同僚が大学でプログラムを書いていると同僚が言った(私はそれがダイクストラだと思う)。彼は教授に、彼が1か月以上取り組んできたコードを見るように頼みました。教授は彼にバックアップをとったかどうか尋ね、いいえと答えた。その後、教授は自分のコードをすべて削除し、もう一度コードを書くように言いました。
彼は腹を立てていましたが、3日後、コードがより簡潔になり、バグが少なくなり、コード行も少なくなり、プログラムを終了しました。
プロジェクトで利用可能な時間内でどのオプションが最適であるかを正直に見積もるようにしてください。
3つの選択肢は
私は10年以上プロのプログラマーであり、私の仕事の中で、最後のオプションが最も多くの場合選択されたものであると結論づけるようになりましたが、常に最良のオプションであるとは限りません。
リファクタリング。リファクタリング。リファクタリング!リファクター!!!!
正直なところ、どれほど経験を積んでも、これはよくある問題です。あなたはコードを書き、何かを学び、古いコードに新しい知識を使いたいと思っています。古い知識を新しい知識と比較して測定します。
それはうまくいきません。その場合、アプリケーション/ゲームは完了しません。代わりに、プロジェクトに時間を割り当てて、「タスク」の一部が不良コードをリファクタリングするようにします。たとえば、ゲームを保存する恐ろしい方法があったとしましょう。ゲーム自体の作業を続けますが、その恐ろしいメソッドをリファクタリング(置換)する時間を見つけてください。リファクタリングを小さく保つようにしてください、それは問題にはなりません。
あなたがリファクタリングを必要とするアプリケーションの主要な部分に到達したとき、あなたはそれを真剣に間違っているのです。そのリファクタリングを小さなパーツに分解します。コードの作成に7時間、リファクタリングに1時間を費やすようにしてください。
プロジェクトが完了して機能のフリーズが発生した場合、リファクタリングに膨大な時間を費やすことができます。とりあえず、ゲームを完成させますが、それでもいくつかリファクタリングしてみてください。それはあなたができる最高のことです。
常にリファクタリングするものがあります。
その期間にあなたのスキルは大幅に成長したようです。おそらく、そのプロジェクトに取り組んだことが貢献したのでしょう。目的のある学習体験としてそれを再設計することは実り多いでしょう。
これは、顧客向けの実用的なプログラムとして提供する必要があるものではありません。それは練習のために特別に書かれました。ですから、代わりに配送の問題や配送の欠陥を練習したくないのであれば、「設計の筋肉」を働かせることが実り多い開発段階にあると思います。
そうするときは、設計プロセスと計画に焦点を当て、既存のものを熟考し、理解していることをよく考えます。
それは、現在どのようなコードがあり、どこに問題があるのかによって少し異なります。つまり、基盤が良好である場合(ほとんどの部分で適切なクラス設計、優れたデカップリング/凝集性など、前述のスレッドのようないくつかの悪い選択)、必ず1.0を取得し、次のようにリファクタリングします。明日はありません。
一方、それが実際には、どういうわけかコンパイラを通過する醜いスラップされたテキストファイルの束であり、識別可能な構造などがない場合(つまり、概念実証のジョブオンザラートプロトタイプ)、次に、それを削除してやり直します。
次のバージョンでは、アジャイルアプローチを実行します。2週間など、スケジュールに合った一定の繰り返しタイムラインを自分で設定します。各チャンクの開始時に(スプリントと呼びましょう)、2週間で達成可能な目標を設定します。先に進んで、それらを実行してください。あなたの気の利いたことを試してみてください。目標を設定して、2週間ごとに、抽象的な内部作業だけでなく、友達に見せられるものを用意します。 Googleの「スクラム」と「スマートゴール」。これはすべて非常に簡単です。一人でいる場合は、紙に書かれたいくつかの箇条書き項目をすばやく書き留めておくだけです。
それができれば、最初からやり直すのが良いでしょう。最初からやり直した後、現在の場所に到達する可能性が高いことがわかっている場合は、とにかく、コードをそのまま使用して機能させることができます。
あなたは雇用者の靴に身を置く必要があります。
ほとんどの採用担当者にとって、あなたがこのようにすればあなたは最も価値があります:-あなたが書く新しいコードの100%テストでそれを終えてください。 -古い(設計が悪い)コードのテストを追加します。 -それをリファクタリングして、デザインとして望んだものを実現します。
すべてを適切なバージョン管理プロセス、ブランチ、タグで行います。
多くの場合、書き換えはセクシーなアイデアですが、それは多くの場合、新人が持っているアイデアであり、実際の生活では危険です。ゼロから始めることが、真面目な人であることの良い兆候であるというよりは、あなたがすでにやった仕事の質を改善することにもっと前向きであることを示す.
もちろん、書き換えることもできますが、その場合は別のプロジェクトにします。
私の過去の経験の一部をミックスに追加するだけです。私は余暇を数分得るたびに、1年以上にわたってサイドプロジェクトに取り組んできました。このプロジェクトは、単純なテストベッドから静的クラス、現在のオブジェクト指向のスリムな裏地付きデザインに移行しました。
これらすべての変更を通じて、バグ修正とパフォーマンス上の利点(可能な限り高速である必要がある)を除いて、コードの機能は同じに保ちました。同じコードベースでもリファクタリングは同じままなので、コードを一から書き直して時間を無駄にすることなく大幅に改善しました。
これは、以前よりも速くコードを改善できたことを意味します。また、私が行っているときに、何を削除する必要があるか、つまり不要なクラスと、以前のアイデアを念頭に置いて書き直すよりも簡単に維持できるものを簡単に伝えることができました。
したがって、私のアドバイスは、コードをリファクタリングし、必要に応じてそこから改善を加えることです。最初から書き直すことにした場合は覚えておいてください。古いプロジェクトの優れたアイデアを取り入れて、それらをよく調べて、どこに欠陥があるのかを確認する必要があります。つまり古いコードを新しいプロジェクトにコピーしないでください。
答えは、私が「複雑さの上限」と呼んでいるものに依存します。コードベースをどんどん追加していくと、コードがますます複雑になり、整理されなくなる傾向があります。ある時点で、「複雑さの上限」に達します。その時点で、前進は非常に困難になります。力ずくで動き続けるのではなく、バックアップして、再編成/書き換えしてから、先に進むのが良いでしょう。
それで、コードベースが非常に悪いので、複雑さの上限に近づいていますか?そうであると感じた場合は、先に進む前に、クリーンアップと単純化に少し時間をかけてください。クリーンアップする最も簡単な方法が一部を書き直すことである場合、それは問題ありません。
あなたが自問すべき最初の質問は「欠陥はどれほどひどいですか」です。
何を間違えたのですか?
何かが非常に悪いために問題を処理するために何時間もの時間を浪費したり、機密データ(パスワード/クレジットカード)を公開したり、脆弱な脆弱性を引き起こしたりする場合は、編集する必要がありますが、ほとんどの場合、あなたが持っているものを取り、それを仕上げ、後で問題を修正してください。
プログラマーはアプリケーションを改善することを好み、「最高の状態」になりたいと望んでいますが、それは正しいアプローチではありません。
100%でなくても、できるだけ早くアプリケーションをリリースすると、バグとすべてのバグが修正され、他のユーザーから[〜#〜] feedback [〜#〜]が得られます。バージョン1.1のバグおよびその他のもの。他の人々はあなたがアプリケーションをもっと良くするのを手伝うことができ、あなたは無駄な時間人々が嫌いかもしれない何かをするかもしれません。
ですから、あなたの場合は、それを入手してフィードバックを得てから、バージョン2.0をすべての変更で構成し、問題を修正してください。
覚えておくべきもう一つのことは、私たちは常に改善しているということです。 1年前のコードを見て、それが悪いことがわかるとしたら、それはまだ改善の余地があるということです。それは素晴らしいことです。
コードがモジュール式の場合、不適切に作成されたコンポーネントの周りの残りのコードを完成させ、残りのコードに影響を与えることなく、不適切に作成されたコンポーネントを書き直すことができます。
その場合、不適切に記述されたコンポーネントを書き直すのはあなた次第です。不適切に作成されたコンポーネントが非常に不適切に作成されており、完成したコードがそのままでは機能しない場合は、残りのコードを完了する前に、コンポーネントを再作成する必要があります。
どちらでもない?どちらも?
続けて、既存の設計の修正と新しい機能の追加にしばらく時間をかけます。
際どいやり取りがある場合は、それから始めるのが良いかもしれません(「レンダラーでの過度のスレッド」は、正確さの問題を引き起こすものではなく、非効率のように聞こえます)。レース(および場合によってはデッドロック)を回避する一般的な方法、または少なくとも特定の方法で回避できるかどうかを確認してください。
C#でデッドロックやレースディテクターなどをどの程度利用できるかはわかりませんが、存在する場合は、問題の特定や修正が機能していることの確認に役立ちます。
一般的に、私はそれを捨てて、最初からやり直すよりも、何か有用なコードの問題を修正したいという気持ちがあります。焦げた畑(グリーンフィールドやブラウンフィールドと同じように)の開発の方が満足できる場合がありますが、これは通常、既存のアプローチがそうであるはずの場所から大きく外れているため、間違っていることもありません。
それはあなたのコードがいかに混乱しているかに依存します。
コードが非常に複雑または冗長になる実際のn00bエラーが発生した場合は、それらの部分を書き直すことをお勧めします。
とにかく修正する必要がある深刻なバグがあると思われる場合は、バグを修正したかどうかを確認できる単体テストを記述します(まだプログラムを起動できないため)。バグを早期に修正することをお勧めします。コードの機能を覚えている間にバグを修正することは間違いなく優れています。
メソッドが何と呼ばれるか、どのクラスに属しているのか、またはそのような小さなことが気に入らない場合は、IDEを使用してください。 (これはC#であり、一部のjavascript、python、Perl、phpなどではないことに注意してください。)影響を受けるコンポーネントを使用するコードで作業していて、そのコンポーネントが何をするべきか頭にはっきりしているとき、 IDEで問題がなければ、リファクタリングします。
それ以外の場合は、機能させて、次のプロジェクトでスキルを磨きます。
他の人が示唆したように、これは個人的なプロジェクトであり、(まだ)専門的なプロジェクトではないので、私は真剣に書き換えを検討します。
ただし、実験を行うことにより、ここで科学的手法を活用できます。まず、仮説を立てます。鉱山は「おそらく書き直しの時間だ」となるだろう。時間を節約し、障害のコストを削減し、アプリオリバイアスをいくらか制限するために、これ以上プログラミングを行う前に、時間の長さ(「タイムボックス」)を決定します。私はおそらく4つの実時間を提案するでしょう。また、仮説を評価するための方法論を決定します。賭け金が少ないので、方法論として提案します。「これを実行してよかったですか?」さあ、実験を始めましょう。選択したタイムボックスの後、仮説の評価は何ですか?例えば私の例では、4時間を費やして今、書き直しをしてよかったですか。次に、それはおそらく正しい選択です。
あなたは世界中のすべてのアドバイスを求めることができますが、仮説を経験的にテストするのに勝るものはありません。
実験として書き換えを選択することを検討するいくつかの理由:
何かを仕上げることは良い考えですが、真空の中でではありません。書き換えを開始する場合、特定のサブモジュールを完了することで何かを完了することを選択できます。上記の実験の後、それを最初の目標として設定できます。仕上げとは、最初のメインプロジェクトをまだ仕上げる必要はありません。モジュールが完成したら、必要に応じて、元のプロジェクトのスコープ全体の書き換えが完了するまで、別のモジュールを完成させます。