私たちは、ダース程度のソフトウェア開発者を抱える中小企業であり、社内で使用するための自社ソフトウェアを開発しています。私たちの人数が少なく、実行する作業が非常に多いことを考えると、ほとんどの場合、各開発者はシステムの個別の部分を処理し、他の開発者とあまり作業を共有しません。いわば、それぞれに「ドメイン」があります。
ただし、ドメインが重複していて、共同作業が必要になる場合があります。また、この取り決めは、人を置き換えるのが難しいことを意味します。何かがうまくいかない場合、他の誰もそれを行うことができないので(少なくともすぐには)、問題を修正するためにそこにいなければなりません。したがって、この配置はニース(私たちはそれぞれ完全に創造的なコントロールを持っています)であり、ニースではありません(実際にはそれよりも少しリラックスしていますが、基本的に24時間年中無休で電話をかけざるを得ません).
最近、私たちは自分たちの間で少しの「ワークショップ」を試して、いくつかの優れたコーディング標準、つまり単体テストを宣伝しました。 (うん、私たちはまだそれらをやっていない人の一人です...)2時間のミーティングの間、私たちはユニットテストを含む小さなサンプルプログラムを作成することを目指しました。
楽しい2時間でしたが、最終的には少しのコードを生成することができましたが、興味深い問題が痛々しいほど明らかになりました。非常に長い間孤立して住んでいたので、私たちそれぞれが基本的に独自のコーディングスタイルを持っています。
今、私はタブとスペース、キャメルケースとスネークケース、またはそのような他のいくつかの表面的な違いについて話していません。コードの配置の原則について話している。物事に名前を付ける方法。それらを配置するフォルダーと名前空間。このコードを3つのクラスまたは1つのクラスに分割しますか? 5つの小さなファイルまたは1つの巨大なファイル?インターフェイスとファクトリーでそれを抽象化しますか、それとも直接呼び出しますか?ゲッターとセッターまたは裸のフィールド?等。
時々、完全にささいなプログラムを書くことは叫びの試合にほとんど発展しました、しかし私達は結局私達の冷静さを保つことができ、感情が傷つくことはありませんでした。
だから、私は不思議に思いました-それぞれ独自の強い好みを持つ複数の熟練した開発者の間でコーディングスタイルをどのように正規化しますか?異なるスタイルは確かにare煩わしいdoがお互いのコードとやり取りする必要がある場合、煩わしいのは言うまでもありません。また、あるコードがある人のドメインから別のドメインに渡されるとき、自分の方法に合わせてそれを書き換えたいという強い欲求が常にあります。
まず第一に、あなたのコードをどのようにレイアウトするかのルールはありますか?何か基準は?これまでのところ、スペースとケースに関する化粧品だけを見てきました。基本的に、(少なくとも頭の中で)コードが記述された後にコードをフォーマットする方法。しかし、コードをwriteにする方法、コードの配置方法、および名前の付け方に関するガイドはありますか?どこでどのように分割して、どのように分割するか?
標準がなく、私たちが独自に作成する必要がある場合、誰が何が正しくて何が間違っているかについて強い意見を持っているときに、どのようにそれを行うのですか?さて、ここで皆さん、私たちはすべて熟練した開発者です。私たちは、どのアプローチも他のどの方法よりも本質的に優れているわけではなく、それぞれに特定の長所と短所があることを認識しています。しかし、どの長所と短所が最も重要であるかについても強い意見があります。では、どのようにThe Right Way™を決定し、どのようにして誰もが感情を損なうことなく(あまりにも)それに固執するようにするにはどうすればよいのでしょうか。
私が聞いた1つの方法は、自分の好みのスタイルを他の人に強制する(コードレビューや会議などを介して)栄光のリーダーを選択することです。 。あなたが持っていない場合はどうなりますか?
最初のステップ(そして、これはすでに順調に進んでいるようです)は、すべての開発者から問題があり、修正する必要があることについて同意を得ることです。彼らはすべて、自分たちの習慣をより良いものに変える必要があるかもしれないことを理解する必要があります。誰もがコードの記述方法について少なくとも1つのことを変更する必要があることはほぼ確実ですが、うまくいけば、いつもの方法でいくつかのことを続行し続けることもできます。誰もがこれを購読する必要があります。
次に、違いを正確に特定し、それらをリストに書き込む必要があります。あなたが正しく指摘しているように、これのいくつかは些細で見栄えがよく、いくつかははるかに論理的です。しかし、あなたがそれを飼いならすことができるように、それは言葉で捉えられる必要があります。
第三に、おそらく開発者の間である種の投票システムを使用して、ぶら下がっている果物を見つける必要があります。すべての開発者が強い好みを持っているため、違いは解決するのが難しいでしょう。ただし、75/25分割を超えるものや、均等に分割されるものもありますが、一方の側は他方の側よりもはるかに強く感じます。これらの問題は簡単に解決できます。それらを識別し、一度に1つずつ使用します。投票の結果を開発者に知らせてください。今後のすべての新しいコードは、グループの推奨するアプローチに準拠することになります。
最後に、決定を強制する方法が必要であり、これに対する解決策は単にコードレビューです。すべての変更は、少なくとも1人の他の開発者が確認する必要があります。これは、コーディングスタイルを正規化しようとしていない場合でも、優れたプロトコルです。レビューアは、潜在的なバグ、不明確なコード、誤解を招くコメント、そしてもちろん、コーディングスタイルガイドラインへの準拠を探す必要があります。
1つの変更が組み込まれたら、次の変更に進みます。開発者がこのプロセスに慣れるにつれ、問題の多い問題に取り組むにつれて、開発者はよりオープンマインドになります。
ミーティングの目的は、経験豊富な開発者グループの間でコードの品質を向上させるためにユニットテストについて話し合うことでした。次に、次のことについて議論していることに気づきました。
物事に名前を付ける方法。それらを配置するフォルダーと名前空間。このコードを3つのクラスまたは1つのクラスに分割しますか? 5つの小さなファイルまたは1つの巨大なファイル?インターフェイスとファクトリーでそれを抽象化しますか、それとも直接呼び出しますか?ゲッターとセッターまたは裸のフィールド?
上記のトピックはいずれもユニットテストに不可欠ではなく、純粋にコーディングスタイルであり、経験豊富な開発者なら誰でも、前述のオプションのいずれかを使用してコードベースに飛び込み、文体的に互換性のあるコードをためらうことなく書くことができるでしょう。
そのため、少し後戻りして、本当に重要なことは何もないという議論に巻き込まれ、テスト(ユニットテストだけに限定されない)のトピックに戻ることに気づきました。
開発者の間でのテストの重要性を強調し、個々のスタイルに最適な方法でそれらのテストを作成する時間/スペースを与えます。彼らがコードのテストを見つける/実行する場所/方法を明確に文書化している限り、問題はありません。
プラットフォームの慣例以外のコーディング標準はありません。また、開発者はすべて大人であると想定します。
2つのルール:ファイルを編集する場合、そのコーディングスタイルに適応します。そして、新しいコードはそれを書く開発者のスタイルで書かれています。
そして寛容であること。叫ぶ必要はありません。誰が叫ぶのは間違っています。
あなたは間違った問題を解決しようとしていると思います。私が理解しているように、あなたの問題は、すべての開発者がサイロで作業しており、他の開発者は問題が深刻な場合にのみ飛び込むことです。もちろん、この場合は共通の(ディープコーディング)スタイルを使用することで問題が解決する可能性がありますが、サイロを最初に解除することをお勧めします。あなたが孤立して働いている限り、誰もが彼らの標準でコーディングし続けるでしょう。これは悪意のある意図である必要はありません(標準に同意していないため)。解釈が異なるだけかもしれません。私たちは何年もの間、同じコアチームで何年にもわたってコーディング標準を持っていますが、コードレビューが異なる人々のためのコーディング標準の異なる解釈を明らかにするという問題に時々遭遇します。議論と意見の相違だけでコーディング標準を進化させることができるので、これは悪いことではありません。
したがって、私の推奨事項は、最初にサイロを壊してみることです。たぶん、2〜3人の開発者が一緒にこれを作成できる新しいプロジェクトが近づいています。同様のプロジェクトのグループで複数の開発者をチーム化できるかもしれません。それらのミニチームが実際にコーディング標準を開発し、コードレビューを実践することで抽象的な標準の解釈を検証します。
個人から共同でコードの所有権に移行すること(そして共通の基準はこれの1つの要素です)は一晩では発生せず、会議で決定することはできません。それはあなたが目標とし、日々の日々の改善によって達成する目標です。
これは表面的なスタイルだけでなく、人々が書く方法についてもあるので、もしあなたがwayを「標準」の形でみんなに苦痛と考えを強制すると、あなたはチームメンバーの創造性を阻害し、チーム/会社を殺す可能性があります。あなたがする必要があるのは、それらの叫びの試合をより生産的なものに変えることに取り組むことです。そして、あなたの強い意見をより緩く保持することを学びます。
大きな変化を1つ導入しないでください。抵抗に遭遇します。代わりに目標を設定し(「特定のコーディングスタイルが必要」ではなく、「チーム全体でより統一されたレベルのデザインスキルが必要」)、その方向に進むための小さなステップを理解します。次に、そこに到達したと感じたら、次のステップを理解します。ある人のコードが別の人のコードとやり取りする必要がある場所は、1人の人の責任であってはならず、関係者は設計についてより注意深く、相互作用の問題をよりよく理解するために少し時間をかけてください。そこで始めましょう。境界のコードは1人で決められているわけではなく、1人の人が所有しているという概念も導入します。システム/コンポーネント間の依存関係と「パワー」関係を明示的に調査して同意してもらいます。
あなたができる別のことは、あまり混乱させない方法で(おそらくいくつかのローテーションスキームを使って)労働にいくつかの形のペアプログラミングをルーチンに組み込んでもらうことです(あなたは理解する必要があります)現在の作業方法に関してそれが何を意味するか)。このようにして、彼らは互いにスキルを身につけ、コードの設計方法に関して自分たちの間で「戦い抜く」ことができます。なぜなら、会議での白熱した議論とは異なり、彼らは実際の問題を解決し、お互いのアイデアに挑戦し、状況に応じてそれらを評価して試すことができるからです。これは、誰も自分のコードを理解している人がいないという問題にも役立ちます。
追伸TDDを始めたばかりなので、チームに強制するつもりはありません。代わりに、私は彼らがいくつかのサイドプロジェクトでそれを実践し、それを日常の仕事にゆっくりと組み込む方法を見つけます。なぜなら、IMO、TDDには、ある程度の実践と一定レベルの(テストの作成と設計)が必要だからです。 )それが効果的に使用される前のスキル。さもなければ、彼らは彼らの生活を楽にしないテストスイートを書くことになりかねないので、彼らは結局それを無視し始め、そして/または実践に対する敵意を発達させます。また、優れたコンサルタントの採用、ワークショップの増加などを検討することもできます。
チームカルチャーが独自のドメインとスタイルを持つ各開発者とうまく機能していて、人々が状況に満足している場合は、それを変更しようとしないでください。この分離が問題でない場合は、問題にしないでください。
現地の基準に従うことが原則となるようにしてください。各ドメインのリーダーは、ドメインの標準を決定する必要があります。また、ドメイン外で作業している場合は、ローカルドメインリーダーのコーディングスタイルを尊重する必要があります。
これはあなたがコーディング標準を持っていてはならないということではありません。一部のコーディング標準はかなり単純で、広範囲にわたる合意があるため、それらを標準化してください。しかし、より議論の多い人のために、みんなの意見を統一しようとしないでください。
私たちの数が少なく、実行する作業が非常に多いことを考えると、ほとんどの場合、各開発者はシステムの個別の部分を処理し、他の開発者とあまり作業を共有しません。言うまでもなく、それぞれに「ドメイン」があります。
これは、見た目よりも問題です。プロジェクトに1人の開発者しかいないと、この種の過保護が助長され、サブシステムを知っている唯一の人がバスに襲われたり、突然無力になったり、去ったりした場合に、「バス要因」のリスクがあります。
チームとして振る舞うには、チームとして作業する必要があります。つまり、作業をより均等に分散させる必要があります。これは決して簡単ではなく、継続的な管理入力が必要ですが、長期的には価値があります。
これを実行し、お互いの作業を確認しながら、詳細について話し合うことになりますが、大きなグループの設定ではなく、ペアで行われます。それはコンセンサスの出現を促すはずです。彼らの意志を押し付けようとする「最も不合理な」人がいない限り。
明確ではありませんなぜコーディングスタイルはあなたにとって重要です。それは不一致を引き起こして時間を浪費し、摩擦を引き起こしたためなのか、それともソフトウェアの実行に問題を引き起こしているためなのか、それともソフトウェアの作成/保守を困難にするためなのか?
したがって、最初に行うことはwhyまたはwhatを計算することであり、howはおそらくあなたを逃れます(他のすべての答えはここにあなたがやるべきことについての良い考えがあります)。
この状況でおそらく私がすることは:
あなたがコンセンサスを通じて権力を得るか、マネージャーのような権限を通じて権力を得るまで、物事を行うことができる唯一の方法は例です。あなたの作品に触れる人は誰でも、あなたが提供した仕様を使わなければならないでしょう。それはあなたの作品のエラーを減らし、それゆえにそれ自身のポイントを証明します。この方法で権限を取得します(最良の方法)。
最終的に、予想される入力が与えられたときにインターフェイスが正しいものを出力する場合、コードに3つのクラスまたは5つのクラスがあるかどうかを気にするのはなぜですか?あなたは彼らのものを読むことができないか、それが好きではないので?あなたが持っているものよりスタイルを試し、実行するより良い理由が必要です。
最後に、仕様/テストがない場合は、サルにコーディングするタイプライターを与えても、そのスタイルが気に入らなくても問題は大きくなります。
ロバートの答え は素晴らしいですが、テクニカルデザインがチームワークに与える影響について、もう少し言えることがあります。
ユニットテスト。 (うん、私たちはまだそれらをやっていない人の一人です...)
OOを使用していない場合は、単体テストは必要ありません。 OOを使用している場合は、テストhelpを実行して、コードが壊れたときに警告します。ただし、テストには他のコードと同じルールが適用され、通常のコードと同じように予期せずブレークする可能性があります。
OOではなく、より機能的なスタイルを使用している場合、単体テストは存在しなくなります。それらが存在する場合は、コードをコピーして貼り付けるのとまったく同じように見えます。その時点では、コードをコピーしないので、コードを小さく読みやすく保つことができます。例については、以下を参照してください。
このコードを3つのクラスまたは1つだけに分割しますか? 5つの小さなファイルまたは1つの巨大なファイル?インターフェイスとファクトリーでそれを抽象化しますか、それとも直接呼び出しますか?ゲッターとセッターまたは裸のフィールド?
あなたはこれらについての議論に自分自身を見つけるかもしれませんが、あなたは1つの正しい答えを見つける必要があります。インターフェース、抽象化、ファクトリー、クラス、ゲッター、セッターはすべて任意の概念であり、優れているように聞こえますが、それらがどのように機能し、ソフトウェアにどのように適合するかを理解する必要があるため、開発者のオーバーヘッドになります。オーバーヘッドがあるため、開発者はパズルの解決に長い時間をかけないように、新しいソリューションを見つけたいと思っています。これらの概念には測定可能な利点がないため、完全にスキップして、コードを読みやすく、操作しやすくすることができます。
これらの議論から抜け出すのは難しい場合があります。耳を傾け、適切な質問をし、質問を短く、正確に、要点を明確にし、設計に早い段階で穴を開けます。誰かがファクトリパターンの使用を提案した場合は、コードの行数を減らした例で対抗することもできます。 「コードが少ない方が良いとは限らない」、「標準に達していない」などの証明不可能なことを言った場合は、説明を求めてエラーを見つけるために彼らの考えを内省するように依頼することができます。彼らが失敗した場合、彼らは混乱し、イライラします。選択をスライドさせて操作し、もう一度やり直してください。彼らはあなたが尋ねるたびに内省するのが良くなるでしょう。
開発者に複数回のイントロスペクションを行わせることができず、改善が見られない場合は、開発者に問題があります。チーム全体が同じであれば、状況を改善できない可能性があります。議論を受け入れるか、別の仕事を見つけてください。
あなた コメント ロバートの答えについて
私たちは経験が多すぎて、それに基づいて誰もが自分の意見を持っています
あなたの説明に基づいて、あなたはまだあまりの経験に達していないと思います。そのレベルに達すると、異なる意見ではなく、同じレベルの他の開発者とコンセンサスが得られます。正解であり、あなたがそれを上回っているとは限りません。彼らが何をしているのかを彼らに示すことができる誰かを見つけ、彼らを正しい方向に導きます。
機能スタイルの単体テストについて
これは元の質問とあまり関係がなく、少し長いので、興味がない場合はスキップしてください。それを説明するように求められたので。
機能するサーバーは次のようになります。
//main
http.Listen((request,response)=>{
response.write(request.username);
});
そして、テストは次のようになります。
//test that it returns the right value
var username="billy";
http.request({username:username}, response=>{
if(response!==username){
console.error("test failed");
return -1;
}
});
しかし、私の基本的なサーバーが何か他のことをする必要があるとしたら、私はテストを破るでしょう。リファクタリングは必要ですが、今は2つの場所で行う必要があります。
テストもソフトウェアと同じように失敗しました!ユーザー名が定義されていない場合、未定義の値を読み取ろうとしているため、エラーがスローされます。これについてのテストも、真に赤緑の方法で記述できます。
//red: write the test first which will find undefined values
http.request({}, (response,error)=>{
if(response){
console.error("got a valid response, test failed");
return -1;
}
if(error){
return 0;
}
});
緑のコードを修正します。
//main
http.Listen((request,response, error)=>{
if(!request.username) error.write("no username");
else response.write(request.username);
});
しかし、再び、同じ問題。私はコードを2回書いただけで、リファクタリングを難しくし、読み取る行を追加しましたが、テストでは何も役に立ちませんでした。
では、テストはいつ役立つのでしょうか。 OOで。テストはそれ自体が関数型のスタイルであり、関数はプログラムフローを安定に保つことを目的としていますが、開発者はより小さくてよりクリーンなコードを書くように指導します。
class server{
listen(IPerson request,string response){
response.write(request.username);
};
}
interface IPerson{
string username;
}
class Person{
string username;
}
class TestPerson inherits IPerson{
string username{
get{usernameCheckedCount++; return _username;}
set{_username=value;}
};
string _username;
int numTimesUsernameWasChecked=0;
}
static int TestServer(){
//setup
var didTestFail=0;
var srv=new server();
var invalidPerson=new TestPerson{username=null};
var validPerson=new TestPerson{username="billy"};
//test that an invalid person throws an error
srv.listen(invalidPerson,(string response, string error)=>{
if(error==null) didTestFail=1;
});
//test that a valid person throws no error, the server checks the username, and the response is the username
srv.listen(validPerson,(string response, string error)=>{
if(error != null) didTestFail= 1;
if(validPerson.numTimesUsernameWasChecked == 0) didTestFail=1;
if(response != "billy") didTestFail=1;
});
//return
return error;
}
テストを念頭に置いてこれを記述していなかった場合は、作業自体を始める前に、サービス、2つのインターフェース、および別の依存関係注入ファイルを作成することから始めた可能性が高いため、作業がはるかに困難になります。すべてを追跡するのは本当に難しいです!
ここでの提案に加えて、開発者が共同で作業できるように、画面共有を使用してペアプログラミングセッションをいくつか行うことを強くお勧めします。 [〜#〜]ない[〜#〜]毎日1週間、ペアで作業し、誰とペアを組んで、正規化の慣行に関して途方もない利益を得るのかを混ぜ合わせるそして、お互いにヒントを共有します。
私があなたの質問を理解している限り、人々が異なるコーディングスタイルやデザインの好みを持っているという純粋な事実は問題ではありません。問題が発生するのは、
ドメインが重複しており、協力する必要がある
これらのスタイルと設定は互いに衝突します。ここでの計画は、コーディングスタイルを「正規化」することによってその問題を解決することです。
私にとって、正規化はこの文脈ではかなり奇妙な言葉です。どのコーディングスタイルも他のどのコーディングスタイルよりも標準的であろうか。現在のコーディングスタイルはどのように正常ではないのですか?通常のコーディングスタイルを定義するものは何ですか?多分それは私がネイティブの英語を話す人ではないからかもしれませんが、あなたのWordの選択は、あなたがここで少し間違った方向に進んでいることのヒントになっているかもしれません。
人々は通常、より良いコードを書くのに役立つコーディングスタイルを開発します。すべての人が異なる場合があるため、コーディングスタイルも異なります。もちろん、共通のコーディングスタイルを作成して、全員に使用を強制することもできますが、それは、一部の人が右利きで他の人が左利きであっても、すべての人に同じ手で書くように強制するようなものです。手渡し。
一般的なコーディングスタイルは、通常、妥協であり、自分のコーディングスタイルに勝るものはありません。一部の人々は、スタイルが自分の好みに近いので、問題が少なくなりますが、他の人にとっては実際の問題になります。基本的にここで私が言おうとしていること:成熟した開発者にコーディングスタイルを強制すると、一般に開発者はより悪いコードを生成するようになります。そして、重なり合う領域の改善が他のすべての領域の損失を補うかどうかはわかりません。
私があなたの質問で読んだのは、誰もが独自のコードスタイルを持っているという事実は、これまでのところ深刻な問題ではなかったということです。みんなに共通のコードスタイルを強制することによって深刻な問題にすることが賢明かどうかはわかりませんそしていつも、あなたは私の意味がわかりますか?
コラボレーションに関しては、すぐに古き良きデザインパターンが思い浮かびました。
実装ではなくインターフェイスへのプログラム!
コラボレーションの場合、共通のインターフェースについて合意することが必要です。これらのインターフェースの背後にある一般的な実装に同意する必要はありません。だからここに私の提案があります:
すべての人に好きなコーディングスタイルを残しますが、ドメインが重複する(または将来重複する可能性がある)セクションのインターフェースを設計するときは、1人だけでそれらを設計しないようにしてください。チームミーティングでそれらを設計するか、少なくとも3〜4人がすべてのインターフェイスで一緒に作業する必要があるようなルールを作成します。そうすれば、はるかに優れたインターフェイスが得られ、より優れたインターフェイスが自動的に優れたコードにつながります。また、問題を断片に分割する方法や要素に名前を付ける方法などの質問にも答えます。最も重要なのは、断片が互いにどのように相互作用するかです。
また、覚えておいてください。優れたインターフェースは、他のコードに触れることなく、その背後にある実装をいつでも置き換えることができるため、非常に長い間存続できます。それが本当に大変な作業であるインターフェースを置き換えるので、インターフェースは実装よりも重要である理由です。しかし、どんなに上手であっても、自分でインターフェイスを設計するときには間違いを犯します。あなたは問題を見落とすでしょう、あなたは欠けている詳細を見落とすでしょう、そしてあなたの隣にいくつかの余分な目があることは本当に役に立ちます。
私の提案は基本的に別の古い開発者の知恵に従います:
実行中のシステムには絶対に触れないでください。必要がない限り、少なくともそうではありません。コーディングスタイルをすべての人に強制すると、システムはゼロから再設計されますが、これまでは非常にうまく機能しているように見えますが、そうではありませんか。システムの壊れていない部分を修正しないでください。実際の問題のみに焦点を当ててください。それは、ドメインが重複している領域です。