*コード所有者*システム:それは効率的な方法ですか?[閉まっている]


50

チームに新しい開発者がいます。アジャイル方法論は、私たちの会社で使用されています。しかし、開発者には別の経験があります。コードの特定の部分を特定の開発者に割り当てる必要があると考えています。したがって、1人の開発者がプロ​​グラムプロシージャまたはモジュールを作成した場合、プロシージャ/モジュールのすべての変更は自分だけが行うのが正常であると見なされます。

プラス面では、おそらく提案されたアプローチでは、各開発者がコードの自分の部分をよく知っており、修正を迅速に行うため、共通の開発時間を節約できます。欠点は、開発者がシステムを完全に知らないことです。

このアプローチは、中規模システム(ソーシャルネットワークサイトの開発)でうまく機能すると思いますか?


23
私はこの方法で働いており、自分が所有していないコードを常に変更しなければなりませんでした。コードは「私のもの」ではなかったため、常に誰かを怒らせ、変更が簡単になるほどコードが十分に文書化またはテストされなかった。私が所有していたプロジェクトでは、グループの所有権と迅速な統合(長いマージを防ぐため)を常に推奨していました。
ダニーヴァロード

26
これがいかに悪いアイデアであるかを十分に強調することはできません。以下の答えは、コードの所有権に関するすべての誤りを要約しているので、私が追加できる唯一のことは、私が働いていたソフトウェア開発ショップが、良い人々と仕事をする素晴らしい場所から、2倍の怠zyな利己的な開発者の悪夢に変わったことです開発者、そしてひどく保守不能なカウボーイコード。
maple_shaft

6
私は完全に長い時間前にこの質問をした:programmers.stackexchange.com/questions/33460/...
ジム・PULS

7
彼は自分をかけがえのないものにしようとしているようです。
イアンホルダー

6
明確化:「プロシージャ/モジュールのすべての変更は彼だけが行う」と言うとき、他の誰もそのモジュールに触れることを許可されていないという意味ですか、それともタスクを配るときにタスクを割り当てるという意味ですか可能であれば、最初にそれを書いた(またはそれに精通している)プログラマーにそのモジュールに関連しますか?それは微妙な違いですが、それは本当に質問の性質を変えます。
スコットホイットロック

回答:


37

これらの質問の非常に多くのように、答えは次のとおりだと思います。

場合によります

すべてのプログラマーがすべてのコード行を知っているべきであるという立場を取ることは、誤った方向に導かれると信じる理由があります。

コードを深く理解している人は、コードをまったく知らない人(私の経験に対する大きな飛躍ではない)の5倍の速度で変更を行い、約1か月かかりますかなり大きなサイズのモジュール(また不合理ではない)を非常によく理解するためにコーディング経験を積むと、いくつかの(完全に偽の、架空の)数値を実行できます。

  • プログラマーA:深い理解
  • プログラマーB:なし

プログラマAが1日に1単位の作業を完了したとします。5就業日の4週間で、20単位の作業を完了できます。

したがって、プログラマBは、1日あたり0.2作業単位で開始し、20日目に0.96作業単位で終了します(21日目にはプログラマAと同じくらい良い)、同じ11.6単位の作業を達成します20日間。その月の間に、プログラマーBはプログラマーAと比較して58%の効率を達成しました。しかし、今では、最初のモジュールと同様にそのモジュールを知っている別のプログラマーがいます。

もちろん、まともなサイズのプロジェクトでは、50個のモジュールがありますか?そのため、それらすべてに慣れるには約4年かかります。つまり、学習中のプログラマは、平均してプログラマA ...に比べて58%の効率で作業しています。

したがって、このシナリオを考えてみましょう。同じプログラマー、同じプロジェクト(Aはそれをすべて知っており、Bはそれをまったく知らない)。ワークロードが50のモジュールにランダムに分散されていると仮定しましょう。両方のプログラマーを均等に分割すると、AとBは両方とも各モジュールで5営業日かかります。Aは各モジュールで5単位の作業を実行できますが、Bは、私の小さなExcelシミュレーションによると、各モジュールで1.4単位の作業を実行します。合計(A + B)は、モジュールあたり6.4単位です。これは、Bが作業中のモジュールのスキルがなくてもほとんどの時間を費やしているためです。

この状況では、Bがより小さなモジュールのサブセットに焦点を合わせることがより最適です。Bが25個のモジュールのみに焦点を合わせている場合、各モジュールで10日間、合計3.8個の作業が行われます。プログラマAは、Bが作業していない25のモジュールにそれぞれ7日間、Bと同じモジュールにそれぞれ3日間を費やすことができます。合計生産性の範囲はモジュールあたり6.8から7ユニットで、平均6.9で、これはかなり高いです。 AとBが均等に作業を行ったときに完了したモジュールごとの6.4ユニットよりも。

Bが動作するモジュールの範囲を狭めると、さらに効率が上がります(ある程度まで)。

トレーニング

また、モジュールについてあまり知らない人はより多くの経験を持つ人より多くのことをする人を邪魔すると主張します。したがって、上記の数値では、Bが理解できないコードに費やす時間が長くなるほど、Aが質問をすることにより多くの時間を費やし、時にはAがBが行ったことの修正またはトラブルシューティングを手伝わなければならないことを考慮していません。誰かを訓練することは時間のかかる活動です。

最適なソリューション

だからこそ、最適なソリューションは次のような質問に基づいている必要があると思います。

  • チームの大きさは?全員がすべての部分でクロストレーニングを受けることは理にかなっていますか、または10人のチームがある場合、各モジュールが少なくとも3人で認識されていることを確認できますか?(10人のプログラマーと50のモジュールで、各プログラマーは3つのカバレッジを得るために15のモジュールを知っている必要があります。)
  • 従業員の離職率はどうですか?平均して3年ごとに従業員を離職させ、システムの隅々まで実際に知るのにそれよりも時間がかかる場合、従業員はトレーニングが報われるのに十分な長さではありません。
  • 問題を診断するには専門家が本当に必要ですか?多くの人が「その人が休暇に入ったらどうなるか」という言い訳を使用しますが、私は経験のないシステムの問題を診断するために何度も呼ばれています。経験豊富な人がそれをはるかに速く見つけることができたというのは本当かもしれませんが、1〜2週間彼らなしでは生きられないという意味ではありません。ミッションクリティカルなソフトウェアシステムはほとんどないため、5時間ではなく1時間で問題を診断する必要があります。そうしないと、世界は終わります。これらのリスクを比較検討する必要があります。

だから「依存する」と思うのです。柔軟性がないため、20モジュールを2人のプログラマーの真ん中(各10)に分割するのは望ましくありませんが、50モジュールすべてで10人のプログラマーをクロストレーニングしたくはありません。効率性とあなたはそれほど冗長性を必要としません。


3
一部の人々は、一部の部分を他の部分よりもよく知るようになるのは当然です。しかし、「所有権」の概念は、他の人許可なくそのコードに触れはならないこと、または所有者だけが最終決定権を持ち、それが行き過ぎであることを意味します。明らかにはい、それが彼らが実際に意味するものである場合、「それは依存します」。
プーリー

1
@poolie-私は同意しますが、それがそのカットと乾燥かどうかはわかりません。所有権は本当に「触れてはならない」ことを意味しますか?私はそれを確信していません。その特定のコードについて、「これが最終的な権限を持つ人」であることを意味すると思います。ここには複数の問題があります...しかし、質問の根本はプログラマーにタスクを割り当てることであり、特定のプログラマーが特定のコードで作業することを禁止することではないと思います。「プログラマBはこのコードで動作してはいけません」と言うのは愚かなことです。
スコットホイットロック

所有権とは、コードの断片を扱うための最優先事項を意味すると思います。プログラマーAが自由で、最高の優先度を持っている場合、彼はフラグメントの使用を開始する必要がありますが、プログラマーBはこれを行うべきではありません。
セルザッハ

76

それはひどい考えです。それは短期的にはより速いかもしれませんが、それを書いたコーダーだけがそれを維持する責任があるので、それは理解しにくいひどく文書化されたコードを奨励します。誰かが会社を辞めたり休暇をとったりすると、計画全体が台無しになります。また、ワークロードの割り当てが非常に難しくなります。1つのコーダーが「所有する」コードで2つの緊急のバグが発生するとどうなりますか?

チームとしてコーディングする必要があります。人は自然にタスクを割り当てられ、特定の領域に焦点を当てますが、ワークロードを共有し、一緒に働くことを奨励する必要があります。


5
私は原則としてチームとして働くことに同意しますが、実際には、人々は自分の仕事について所有権を持っているとき、「あなたがそのコードを修正できない限り、それは私の!" そのため、私が働いているチームプロジェクトはありますが、個々の開発者はコードの割り当てられた部分を完了する責任があります。
ロバートハーヴェイ

1
コード所有権の最大の問題の1つは、シリアル化です。作業の90%がすべて1人の領域内にある場合はどうなりますか?チームの残りのメンバーは、親指を立てて待機することになっていますか?
ニールティブルアラ

5
私が働いている場所には、誰か(またはグループ)が「所有」しているコードのセクションがありますが、それらのファイルに触れるのは決してそれらだけではありません。誰もがすべてを知るにはコードが多すぎるため、人々は特定のサブシステムに特化しており、特定のシステムで大規模な設計決定を行い、それを理解する責任がありますが、他の人にとっては珍しくなく、必要に応じて小さな迅速な変更を加えることも珍しくありません。
アレックス

3
@Robert Harvey:チームはすべてのコードを所有ています。
スティーブンA.ロウ

2
「ひどい考え」は強すぎる。Linuxカーネルはそのモデルを使用しており、うまく機能しているようです。
ジョー

28

それは問題の領域が何であるかによります。

一般的なもの(つまり、単純なCRUDアクションなど)であれば、Tom Squiresに同意します(誰でも作業して編集できるはずです)。

しかし ...

問題のソリューションにドメインの専門知識が必要な場合(多くの時間が過去に投資されているか、実装前に多くの研究を行う必要があります。プロジェクトの全員が持っているわけではありません)、コードのその部分に所有者を必ず割り当てる必要があります。そうは言っても、誰でも必要に応じて変更できるはずですが、プロジェクトのその領域を所有している人が常にレビューする必要があります。

チーム全体(またはチームの多数の人)が同じテーマ(無駄なサイクル)を調査および学習することは望ましくありません。所有者を割り当てますが、彼らに彼らの学習と設計を文書化し、多分彼らに技術に関する非公式の(または正式な、本当に重要ではない)トレーニングセッションを行わせます。


2
エッジケースについての良い点。+1
トムスクワイアズ

1
@ダニー:投稿を完全に読んだとは思わない。私は、所有者によってレビューされている限り、誰でもコードを変更できるはずだと言いました。また、ドメインエキスパート、公式または非公式のトレーニングセッションを通じて知識を共有することを提案しました。
デミアンブレヒト

すみません、疲れてその部分を見逃しました。
ダニーヴァロード

+1これは、プロジェクトによって所有権のレベルが異なるとメリットがあることを示す唯一の答えだと思います。
トーマスレバイン

1
私はこれを所有権として本当に見ていません。コードレビューは自然(はい、自然)であり、特定のサブシステムの最も専門的な開発者がこのサブシステムの変更をレビューするのも自然です。
マチューM.

10

これは恐ろしい考えです。私はこのアプローチを使った会社で働いたことがありますが、それは技術的な負債の積み上げのためのレシピです。一番下の行は、2つのヘッドが1つよりもほとんど常に優れていることです。どうして?あなたはばかでない限り、あなたはあなたが完璧なプログラマーではないことを知っており、あなたが犯すすべての間違いをキャッチするつもりはないからです。これがチームを必要とする理由です-異なる視点から同じコードを見るより多くの目。

要約すると、1つは規律です。コーディングスタイルで本当に規律を守られている人はどれだけいるでしょうか?規律を使用してコーディングしないと、ショートカットを使用して(後で修正するため)、コードの保守性が低下します。私たちは皆、「後」が決して来ないことを知っています。事実:チームの仲間にすぐに説明責任を負う場合、ショートカットを作成するのは難しくなります。どうして?あなたの決定は疑問視され、ショートカットを正当化することは常に困難だからです。最終結果?より優れた、より保守性の高いコードを作成し、より堅牢です。


9

利点は、すべての人がすべてを調査して理解する必要があるわけではないことです。欠点は、それによって各人が自分のコード領域に必要になることであり、それを維持する方法を誰も知らないということです。

妥協案は、コードの各領域に少なくとも2人の所有者を置くことです。その後、誰かが休暇に出たり、新しい仕事に就いたり、退職したりできますが、コードを知っている(そして新しい2番目の人を訓練できる)誰かがまだいます。誰もがすべてを学ぶ必要はありません。これはもう少し効率的です。

常に同じ2人(または3人)で作業することは避けてください。異なる領域のペアを切り替えて、関連するプログラム領域で別の人と作業するときに知識が不注意に共有されるようにします。


1
または、言い換えれば、XPをお勧めします:-)
ダニーヴァロッド

6

はい、短期的にはわずかに効率的です。そして、そこには利点があります。それはコストを上回ることすらありません。

彼が休日にいるとき、予期せぬ病気になっているとき、去るとき、またはことわざのバスにぶつかったときはどうなりますか?あるジョブを別のジョブよりも早く完了するためにリソースを柔軟にしたい場合はどうなりますか?コードレビューはどれほど効果的ですか?マネージャー、特にコードベースに属していないマネージャーは、開発者が一生懸命働いているのか、それとも目を覆っているのかをどのようにして知ることができますか?技術的な負債が増え始めたら、誰が気づくでしょうか?

私の経験では、このように働くのが好きな人は、せいぜい栄光狩人であり、最悪の場合は怠け者です。彼らはあなたが与えられた問題であなたが行くことができる唯一の人でありたいです、そして彼らは彼らのコードがプライベートのままでいるのが好きです。そして、彼らはしばしば、読みやすさを考慮せずに、高速にコーディングすることを好みます。

50人の開発者のチームでは、誰もがすべてのコードを知っている必要があるというわけではありませんが、5〜7のチームは、それらの人々が機能し続けるのに十分なモジュールを所有する必要があります。個人は何も所有してはなりません。


コードベースのサイズと範囲に依存すると思います。数億行に達すると、間違いなく「1人の人間がすべてを頭の中に収めることができます」ドメインの外にいるので、主要な責任を分割する必要があります。
Vatine

1
@Vatine:そうです。したがって、コードをモジュールに分割し、各モジュールで作業するチームを作成します。まだ1人が所有するコードはありません。
pdr

はい、それを単一の個人に分割することは(おそらく)意味をなしませんが、確かに「コードベースのさまざまな部分の異なる所有権」についていくつかの議論があります。
Vatine

6

他の回答が指摘している少なくとも3つの問題があります。しかし、私はそれらの両方を一緒に扱いたいと思います。2つの問題は次のとおりです。

  • 専門知識:チームの誰かが特定の分野に関する詳細な知識を持っています。この知識は、プロジェクトにおけるそのドメインの特定の実装とは無関係です
  • リーダーシップ:プロジェクトを構築する作業は、多くの開発者の間で共有される場合があります。ロードマップ、および重要な実装の詳細に関する即時の決定は、特定のチームメンバーまたはチームの少数のメンバーのみが管理します。
  • 自我のないコード:プロジェクトが実装される特定の方法は、チームの特定の開発者のコ​​ーディングスタイル、実践、または知識に依存しません。そして、よく知られたコーディングスタイルまたは十分に管理された仕様を厳守することにより、新しいチームメンバーは経験豊富な開発者と同じようにプロジェクトの方法と理由を理解することができます。

トピックが純粋に専門知識の1つである場合、プロジェクトの成功は、ドメインに関する高度な知識に依存する場合があります。ただし、そのドメインに関する特定の専門家の知識に依存するわけではありません。専門家は、おそらく希少で貴重ですが、本質的に交換可能です。経験豊富な税理士は、その分野の知識の観点から、他の税理士と同じように税務計画ソフトウェアプロジェクトに役立ちます。この問題は、専門家が自分の知識をプロジェクトにどれだけうまく伝えることができるかの1つになります。

トピックが純粋にリーダーシップの1つである場合、プロジェクトの成功は、主にプロジェクトリーダーが下した決定の一貫性と洞察力に依存します。ドメインでの経験がある、またはプロジェクトリーダーとして証明されているプロジェクトリーダーを優先する傾向がありますが、これは役割の二次的な場合もあります。決定がケースごとに一貫しており、各決定がチームによって迅速に実行される場合、「リーダー」は日々変わる可能性があります。これが正常に機能している場合; 多くの決定は、プロジェクトリーダーが「決定」する必要はありません。チームは決定が下されることを既に理解しているためです。

質問はエゴレスコードに関するものではないと思いますが、この問題の重要性についても議論せずにコードの所有権について話すことは困難です。プロジェクトの維持は、おそらく開発サイクルの大部分です。この問題を理解する方法は、開発者の何人かがすぐにそれを去らなければならなかったらどうなるかと思うことです。チーム全体を交換する必要がある場合はどうなりますか?一部のキープレーヤーに依存しているためにプロジェクトが疑わしい場合は、失敗のリスクが高くなります。チームメンバーを1人も失うことはありませんが、プロジェクトを進めるために1人または数人の開発者が必要であるという単純な事実は、より多くの開発者が集まる場合ほど効率的に作業できない可能性があることを意味します。


6

コードの所有権は、リファクタリングを妨げ、開発のボトルネックを作成し、コードに対処すべき問題がある場合に自我の問題を引き起こす傾向があります。

変更を行う前にコード作成者と相談することをお勧めします。高水準のコードは十分に文書化、単体テスト、統合テスト、システムテストを行って冗長性を確保する必要がありますが、それでも別の意見を得るのに害はありません。


5

これは多くの理由で悪いです、私は彼らがこれからもっと合理的なものに変えようとした店で働いていましたが、それはいものでした。

これが悪い理由:

  • コードの所有者が休暇を取り、大きなバグがポップアップする場合、コードを学習してバグを修正しようとするのは非常に困難で時間がかかります
  • コードの所有者が会社を辞めた場合、すべての遺産と部族の知識がドアから出て行っただけなので、彼らのプロジェクトはひどく後退します。
  • ドキュメントは貧弱です。コーディングするのが私だけなら、なぜそれを文書化するのですか?関連するのは、ドキュメンテーションが完全であるか正確であるかを実際に言うほどコードについて十分に知らないため、作成を強制されるドキュメンテーションも貧弱になるという問題です。
  • 誰もが自分の小さなサンドボックスを持っていると、コードの聖戦は簡単に発火する可能性があります。これが問題になるのは、2人が一緒に仕事をしなければならない場合であり、どちらも妥協することに慣れていません。
  • 上記の点により、チームワークのスキルは決して形成されません。人々は他の人と働く必要はありません。
  • 領土は簡単に形成することができ、会社を買わない廃棄物のポケットから作られた小さな王国ができます。モジュールまたはツールXは、ボブの責任である、とさえボブはに行っていることを問い合わせる必要があります誰があなたに災いので、手遅れになるまであなたは、これらが起こっているかわからない彼のコード。
  • 誰もコードについて何も知らないので、コードレビューとピアレビューは苦しみます。コードがわからない場合、正しくない場所を見つけることはできず、テキストの書式設定と命名規則に関するコメントのみに限定されます。
  • そして、もしあなたが私のために働いたら...会社はあなたではなくコードを所有しています。私たちは何をして何を成し遂げ、何を書いているかに誇りを持っていますが、それはあなたのチームが難しい試合に勝ったときのように、グループのことです。会社で働いている従業員は誰でも同じようにコードを所有しており、仕事をする過程で会社の目標を転送するという仕事をするために好きなように編集することができます。

最大のものは、実際には人事問題とドキュメントです。その人はいつの日か去り、少年は数週間左にスケジュールをプッシュします。

より良いアプローチは、コードベースのすべての部分(または、それが本当に大きく多様な場合は半ダース程度)を全員が理解できるようにすることです。

  • その領域の欠陥を修正する
  • マイナーまたは中程度の新機能または機能強化を追加する

各人は、あるものについて他の人よりも少し詳しく知る傾向があるため、2、3の困難な問題を解決するため、または事実上の専門家がそれを引き受けることができます。私はこれが当てはまるグループで働いており、本当にうまくいきました。上記の短所がなかっただけでなく、専門家を探し回っていなかったので、人員配置ははるかに予測可能でした。

唯一のコード所有権の長所は、「コード所有者」が他の人よりも速く処理できる可能性が高いことですが、これは全員が重複しないプロジェクトの「コード所有者」である場合にのみ当てはまります。言い換えれば、人々が「唯一のコード所有者」の利点を中心に回転すると、消えます。


2
あなたは、私が主張しておらず、私はまれだと思う一種の厳しいサ​​イロ化について話している。彼がまだチームの一員であることを理解している限り、誰かに課題を与えてそれを実行させることはまったく問題ありません。つまり、彼はショップのプログラミング標準と慣習に従う必要があり、一般的には自分のコードを維持しなければならない人に親切でなければなりません。つまり、チームは自分のコードがどのように機能するかを理解し、必要に応じて他の誰かが「所有権」を引き継ぐことができるように、ソース管理システムを通じて完全にアクセスできる必要があります。
ロバートハーベイ

5

トラック番号別名バスファクターを参照してください

バス係数トラック係数、またはバス/トラック番号とも呼ばれます)は、個々のチームメンバーの情報の集中度の測定値です。バスファクターとは、プロジェクトを進行できないほど混乱させるために(バス/トラックに衝突するなどして)無能力にする必要がある主要な開発者の総数です。プロジェクトは、残りのチームメンバーがなじみのない情報(ソースコードなど)を保持します。バス係数が高いということは、プロジェクトが必ず失敗する前に多くの開発者を削除する必要があることを意味します。

「バスにぶつかる」にはさまざまな形があります。これは、新しい仕事に就く人、赤ちゃんを産む人、ライフスタイルや生活状態を変える人、または文字通りバスにぶつかる人などです。効果は同じです...


情報源の歴史的重要性を考えると、私はそれが信頼できると感じました。en.wikipedia.org/wiki/WikiWikiWebでは、バスファクターの一般的な使用が約4年前に行われているようです。
ジョシュアドレイク

1

多くのものと同様に、それは大きな「依存」です。厳格な「他の誰もコードを操作できない」場合、おそらく悪い方向に向かっています。「所有者が変更を受け入れる前にコードレビューを行う必要がある」場合、所有者が外部の変更を受け入れる意思に応じて、それは良いことです。


1

欠点は深刻です。チームの「トラック番号」はほぼ1になります。

確認するために、「トラック番号」は、「最悪の場合、チームの何人かのメンバーが、重要なタスクを実行するために必要な知識がチームに失われる前にトラックにぶつかる可能性がある」と定義されます。

開発者がサブ分野に集中することは自然であり、やや奨励されるべきです。誰もがプロジェクトに関係するすべてを知っていなければならない場合、誰もが他の全員が何をしたか、なぜ機能し、それを壊さずに変更できるかを学ぶため、何も実行されません。さらに、開発者が異なる領域に対して異なることを行っている場合、変更が衝突する可能性は低くなります。そのため、通常はプロジェクトの特定のサブシステムで主に働く2〜3人の開発者または開発者のペアがいて、それをよく知っているとよいでしょう。

ただし、特定のコード行に触れる人が1人だけの場合、その男が辞めたり、解雇されたり、休暇をとったり、病院に行ったりすると、そのコード行がバグの原因として示されます。修正する必要があります。誰か他の人がコードを理解する必要があります。それを書いた人以外に誰も見たことがないなら、それ以上開発することなく、バグを修正する変更を開発者が行えるレベルの理解を得るには時間がかかります。TDDは役立ちますが、開発者に「間違った」変更を加えた場合にのみ伝えることができます。繰り返しますが、開発者は、どのテストがどのコードを実行しているかを理解して、失敗したテストが間違ったアサーションを作成しようとしていないことを確認する必要があります。


1

私はそれを極端に考えませんが、コードの責任を好みます。壊れたコードを書いたら、修正する必要があります。これは、個人、ペア、またはチームレベルで実行できます。あなたの混乱を他の人に渡してクリーンアップするのを防ぎます。これは変更にも当てはまります。

ワークロードとスケジューリングの問題がこれを上書きします。犯人は2週間の休暇中なので、主要なバグの修正を保留するのは愚かなことです。

目標は、チームに「非難ゲーム」をプレイさせたり、バグを数えすぎないようにすることではありません(とにかくすべてが同じというわけではありません)。誰が最後にコードをチェックしたかに基づいて、またはコードのすべての行のすべての部分を通過するのではなく、スーパーバイザーに決定をさせて誰かに割り当てます。

優れたプログラマーは、割り当て方法に関係なく、他の多くのコードを修正することになるでしょう。

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