コードが共有されたとき:オープニングからエンドゲームまでのストーリー





「私を放っておいてください、私はクリエーターです!作成させてください!」-プログラマーのジェナディは、夕方に3回目、このマントラを頭の中で発します。それにもかかわらず、彼が開発しようとしているライブラリに別のプルリクエストが到着したため、彼はまだ1行のコードを記述していません。また、会社のポリシーに従って、コードレビューは最小限の遅延で実行する必要があります。現在、Gennadyは何をすべきかを考えています。変更を受け入れることも、拒否することも、その本質を理解するために貴重な時間を費やすこともありません。結局のところ、彼以外の誰ですか?彼はこのコードを書きました、彼はそれに従います。そして、これは終末の図書館であるため、すべての変更は彼の個人的な同意によってのみ可能です。 



一方、文字通り壁の後ろで、「Cedar Beavers」と呼ばれるチームは、リクエストを表示する負荷がほぼ均等になるように、リクエストを再配布します。はい、彼らはDoomsday Libraryを扱いませんが、迅速なコード変更とより迅速なプロセスを必要とする他のタスクを行います。



すべての場合に万能の解決策はありません。プロセスの合理化と速度が重要な場合もあれば、しっかりとした手と完全な制御が必要な場合もあります。さらに、同じ製品の開発のさまざまな段階で、相互に置き換えるためにさまざまなアプローチが必要になる場合があります。それぞれに長所と短所があり、それらに基づいて、私たちは現在の場所に到達しました。



では、Wrikeではどちらの方向に進んだのでしょうか。



コードを所有する独自の方法を選択したオプションは何ですか?



厳密に個人的です。私たちはこれを考慮していません。さて、Gennadyが自分のライブラリへのプルリクエストの作成を禁止し、彼がすべての変更を個人的に行う場合、厳密に個人的なアプローチが得られます。確かにジェナディはこのように始めました。



このアプローチの明らかな欠点の1つは、開発の世界における単純な全体主義です。 Gennadyは、コードを完全に知っていて、その開発の計画を持っている(またはしていない)、そしてそれを変更できる地球上で唯一の人です。 「ベースファクター」である同じバスがすでに角を曲がっています。ジェナディが風邪をひいた場合、おそらく、プロジェクトは彼と一緒に失敗します。別の開発者はフォークする必要があり、それらはたくさんあり、完全な混乱が起こります。



このアプローチには1つのプラスがあります。それは、開発に対する完全に統合されたアプローチです。 1人の担当者がアーキテクチャ、コードスタイルに関するすべての決定を行い、問題を個人的に解決します。通信のオーバーヘッドはありません。



条件付きで個人的。これはまさにGennadyが望んでいないことです。すべてのMRを監視し、ライブラリのコードを他の人に変更する機会を与えますが、変更を完全に制御し、拒否する権利があります。長所と短所は前の段落と同じですが、サードパーティの開発者に直接リポジトリにプルリクエストを送信する機能によって少しスムーズになり、一部の機能を実装するための技術的なタスクを作成しません。



コレクティブシーダービーバーのように。この場合、チーム全体がコードに責任を持ち、メンバー自身が誰がどのリクエストを監視するかを決定します。



利点の中には、レビューのレビューの高速性、チームメンバー間の専門知識の分散、およびバスファクターの減少があります。もちろん、デメリットもあります。インターネットでの議論の中で、それが複数の人々の間で「広がっている」場合、多くの人が責任の欠如に言及しています。ただし、チームの構造と開発者の文化によって異なります。シニア開発者またはチームリーダーがチームの責任を負うことができ、質問のエントリポイントになります。また、MRと新機能の作成は、開発者トレーニングのレベルに応じて分けることができます。結局のところ、コードをリファクタリングするためにアプリケーションのアーキテクチャを理解し始めたばかりの初心者に与えるのは間違っているでしょう。





Wrikeでは、チームリーダーを主な責任として、コードの所有権に対して共同アプローチを採用しています。この人物は、コードに関する最も専門知識があり、特定の複雑さのレビューにどの開発者が有能であるかを知っており、チームのコードの品質に全責任を負います。



しかし、このソリューションの技術的な実装への道は最も簡単なものではありませんでした。はい、言葉で言えば、すべてが非常に簡単に聞こえます。ここに機能があり、ここにコマンドがあります。チームは自分が何に責任があるかを知っています。つまり、チームはそれを監視します。



コマンドの数が手の指の数より少ない場合、そのような合意は口頭の契約として機能することができます。そして私たちの場合、それは30以上のコマンドと数百万行のコードです。さらに、多くの場合、機能の境界をリポジトリで指定することはできません。一部の機能は他の機能と非常に緊密に統合されています。



右側のフィルターパネルは、すべてのビューで同じです。これは「A」チームの特徴です。さらに、すべてのビューは他の3つのチームの機能です。



最も明白な例はフィルターです。ビュー自体は機能が異なる場合がありますが、すべての可能なビューで同じように見え、同じように動作します。これは、ビューが1つのチームに属し、単一のフィルターパネルが別のチームに属していることを意味します。そして、数十のリポジトリ、異なるコードの数千の​​ファイル。特定のファイルに変更を加える必要がある場合は、誰にレビューを依頼する必要がありますか?



最初に、リポジトリのルートにある単純なJSONファイルを使用してこの問題を解決しようとしました。機能と責任者の名前の説明がありました。プルリクエストのレビューを取得するために連絡することができます。



これは、条件付きの個人コード所有モデルに少し似ています。唯一の例外は、責任者として1人ではなく、2人または3人がリストされていることです。しかし、このアプローチは私たちには決して適していませんでした。人々は他のチームに移動し、病気になり、休暇を取り、辞めました。そのたびに、指定された所有者に代わる人を探し、所有者に手動で名前を変更して変更をプッシュするように指示する必要がありました。



その後、彼らは特定の人々からコマンドを指定するようになりました。ただし、すべてが同じJSONファイルにあります。コードをレビューのために提出できるチームメンバーを見つける必要があったため、それほど良くはなりませんでした。また、フロントエンドの開発者は数百人(少し狡猾で約70人)で、当時はすべての参加者を見つけるのは簡単ではありませんでした。所有権システムはすでに集合的になっていますが、適切な人を見つけることは、以前のバージョンから副所有者を探すことよりも簡単ではない場合がありました。さらに、いくつかの機能が交差する可能性があるコードの問題は、まだ解決できませんでした。



:したがって、二つの質問解決することが非常に重要だったか、別のチームのリポジトリ内の特定のチームに個々の機能を割り当てることと、どのような情報を簡単に作成すると、コードを所有する可能性のあるすべてのチームのためにアクセスを。



既製のツールが私たちに合わなかった理由。人々をレビューに割り当て、特定の個人をコードに関連付けるためのツールが市場に出回っています。それらを使用する場合、レビュー、バグ、複雑なリファクタリングの場合に実行する必要がある人の名前でファイルを作成することに頼る必要はありません。



で、AzureのDevOpsチームサービス機能を備えています-自動的にコードレビューアが含まれています。その名前はそれ自体を物語っています、そして私の元同僚の一人は彼らが彼らの会社でそして非常にうまくこのツールを使っていると言います。私たちはAzureとは連携していないので、オートレビュアーの状況を読者から聞くのは素晴らしいことです。



私たちはGitLabを使用しているので、GitLabコード所有者に目を向けることは論理的です。しかし、このツールの操作の原則は私たちには適していませんでした。GitLabの機能は、リポジトリ(ファイルとフォルダー)内の一連のパスと、GitLab内のアカウントを介したユーザーです。このバンドルは、特別なファイルcodeowners.mdに書き込まれます。たくさんのパスと機能が必要でした。さらに、機能は特別な辞書に含まれており、コマンドに割り当てられています。これにより、複数のリポジトリに存在し、複数のチームによって開発され、特定の名前に関連付けられていない複雑な機能をマークアップできます。さらに、チーム、関連機能、およびすべてのチームメンバーの便利なディレクトリを作成するために、この情報を使用する計画がありました。



その結果、独自のコード所有権管理システムを作成することにしました。システムの最初のバージョンの実装は、Dart SDKの機能に基づいていました。これは、最初はフロントエンド部門のリポジトリ用に、Dartファイル用にのみ起動されたためです。独自のメタタグを使用し(幸い、これは言語レベルでサポートされています)、静的アナライザーを使用してすべてのソースファイルを実行し、テーブルのようなものを作成しました:ファイル/機能-所有者コマンド。個々のファイルとパス全体の両方を複数のフォルダーでマークアップできます。



しばらくすると、機能を備えたマークアップがDart、JS、Javaのコードで利用できるようになりました。これは、フロントエンドとバックエンドの両方のコードベース全体です。所有者に関する情報を取得するために、静的アナライザーが使用されます。ただし、もちろん、最初のバージョンと同じではなく、Dartコードでのみ機能しました。たとえば、Javaファイルの場合、javaparserライブラリが使用されます。これらのアナライザーはスケジュールどおりに実行され、すべての関連情報を単一のレジストリに収集します。



特定のコードを所有者チームにバインドすることに加えて、本番環境でエラーを収集するためのサービスとの統合を構築し、チームと機能に関するすべての有用な情報を内部リソースに投稿しました。これで、特定のビューで突然質問があった場合に、どの従業員も誰に駆けつけるかを確認できます。また、DartやAngularの新しいバージョンへの移行など、グローバルな変更が発生した場合に責任者のタスクを自動的に作成できるようにしました。



コマンドをクリックすると、すべての機能、すべてのチームメンバー、純粋に技術的な機能、および製品である機能を確認できます。



その結果、機能をチームにリンクするためのかなり柔軟なシステムだけでなく、コードから始めて、それに関連付けられた機能、すべての参加者を含むチーム、機能の製品所有者、およびバグレポートを見つけるのに役立つ本格的なインフラストラクチャも得られました。



欠点の中には、コードをリファクタリングしてある場所から別の場所に転送するときに機能のマークアップを注意深く監視する必要があること、およびマークアップに関するすべての情報を収集するための追加の電力が必要なことがあります。



コードを所有する問題をどのように解決しますか?そして、関連する問題、そして最も重要なことに、それらの解決策はありますか?



All Articles