友達と小さなプロジェクトをいつ放棄するかを決定する方法に影響する要因は何ですか?[閉まっている]


30

私は最近、厳しい状況に陥っています。ほぼ8か月間、プログラミング仲間とのゲームに取り組んでいます。私たちは両方とも昨年の8月頃にプログラミングの初心者としてスタートしました。彼は2年目のCS学生であり、私は業界のITサポート技術者であり、多数の書籍とオンラインサブスクリプションを持つ独学のプログラマーです。

私が常に見てきた問題は、コードの塊を書き出すと、多くの場合、一緒に少しハッキングされ、多くの失敗があり、それが私たちの新しいコンセプトである場合、素朴なソリューションでいっぱいです。これは問題ありません。学習中です。最初のパスまたは2回目のパスで、両方のコードが少しハッキングされることを期待しています。問題は、ハッキングされたこれらの動作を実際に修正およびリファクタリングするときに発生します。

私のパートナーは、動作を開始した瞬間にエラーを見ることを露骨に拒否して、彼の新鮮な一緒に行動を保持します。構造の一部からほぼ完璧を主張して、コメントがあり、適切な名前のメソッドとフィールドがあっても、使用することさえできません。どんなに一生懸命努力しても、動作を完全に破壊することなく、それ以上の変更や動作の拡張を妨げる明白な欠陥を彼に見せることはできません。それらはすべて同じクラスに属する可能性があります。ハッキングされたソリューションは、常にハッキングされたままであり、設計が十分に検討されていないため、最初に考案およびテストされたときの設計はそのままです。

新しいコードを自分で作成するのと同じくらい多くの時間をベビーシッターに費やしています。私のパートナーは今夜それを失い、ベンチマーク、一般的な慣行、反論できない証拠に関係なく、彼のコードは彼が最初に作った方法のままであることを明らかにしました。あなたが何かをすることを避けたい理由について本全体が書かれていたとしても、彼はそれが単なる誰かの意見であると主張する彼らの妥当性を認めることを拒否するでしょう。

私は私たちのプロジェクトに強い関心を持っていますが、パートナーと一緒に仕事を続けられるかどうかはわかりません。私には3つの選択肢があります。

  • コンパイルの時点を過ぎて機能するコードベースを気にするのをやめ、かろうじてリンプしている動作を維持および解析しようとすることに対処します。物事が真剣に壊れ始めたら、彼はそれを見て、根本的に欠陥のあるデザインにただ絆創膏をかける以上のことをしようとするでしょう。
  • 他のはるかに有能な個人によって10年前に見つけられた問題についての無限の議論を続けてください。
  • このプロジェクトでのプログラミングを停止し、コードの10,000行近くを放棄し、設計に時間を費やす無数の時間を費やして、自分で新しいプロジェクトを見つけてみてください。

この人とこのプロジェクトを続ける価値があるかどうかを判断するには、どのようなアプローチを取ることができますか?または、どの要因が私の決定に影響を与えるべきですか?私たちは多くのコードを書きましたが、必要がない限りこれをあきらめたくありません。


3
合意されたコーディングスタイルガイドラインとコードレビュープロセスを考え出すのはどうですか?論争の多い問題を避け、あなたが両方に同意できるほど十分に標準に入れてください。
ブランディン

25
4番目のオプション(許容ライセンスの場合):コードを分岐して、自分で作業を続けます。
ロバートハーヴェイ

4
コードはどのようにライセンスされますか?あなたはそれを分岐し、他の誰かと続けることができますか?
ジェイディー

14
@enderlandが彼の答えで言及しているように、あなたが書いたものには絶対に巨大な赤い旗があります:「私のパートナーは今夜それを失いました反論の余地のない証拠、彼のコードは彼が最初に作った方法のままです。」これから逃れることができるなら、そうしてください。本当にやりがいのある人は、時々物事を間違えることを受け入れる謙虚さがあります。
リチャードJフォスター

3
何を決めても、10,000行のコードは失われません。コードを書いて学んだことを考えてください。コーディング中に得た喜びを考えてください。そして、(強制的な)3回目/ 4回目/ n + 1回目の反復で学んだことを適用すると、現在のバージョンよりも改善される可能性があります。さらに、1 万行のコードを何を書くべきかを知っていれば、比較的短時間で1万行を書くことができます。多くの場合、物事を機能させるために何を書くかを知ることが、最も時間がかかることです。
キャスパーヴァンデンバーグ

回答:


26

出荷された不完全なコードは、出荷されないホワイトボード上の完全なコードよりも優れています。

言われていること...

より多くの経験をお持ちの方、または同様の状況にある方。あなたは何をした?どうすればいいですか?

次のことを検討します。

  • このプロジェクトの目的は何ですか?楽しい?お金?学ぶために?
    • 実際にこの目的を達成していますか?
  • この人は実際にあなたがあなたの目標をより良く達成できるようにしているのですか?
  • 実際に出荷するのはどれくらいですか?
  • これらの問題は起動を妨げますか?それとも個人的な誇りの問題ですか?
  • 欲求不満なときに誰かと自発的に仕事をすることには利点がありますか?

このプロジェクトでのプログラミングを停止し、コードの10,000行近くを放棄し、設計に時間を費やす無数の時間を費やして、自分で新しいプロジェクトを見つけてみてください

上記を考慮し、必要な追加作業を検討してください。

あなたはあなたの優先順位を把握し、この人と働くことに関連する問題がそれの価値があるかどうかを決定する必要があります。これを把握することはできません。

私のパートナーは今夜それを失い、ベンチマーク、一般的な慣行、反論できない証拠に関係なく、彼のコードは彼が最初に作った方法のままであることを明らかにしました。

あなたはこのタイプの人と働きたくないことを知っています。

おそらく、プログラミングを学び、クラフト自体に優雅さを求めたいので、このようなプロジェクトを行っているのでしょう。


1
お返事ありがとうございます。私は楽しみ(内紛ではないとき)と学習の目的を達成しています。お金を稼ぐ天気は、まったく異なる話です。彼は私の目標を達成するのを手伝ってくれますが、私は自分で目標を達成できると信じています。このゲームは機能クリープの好例であり、いつ出荷できるかは正直わかりません。私のパートナーは、数か月前から2Dから3Dへの変更を推進しようとしていますが、すでに範囲を超えているため、拒否します。
ダグラスガスケル

1
私自身のプロジェクトであれば数か月前に削除されていたので、プロジェクトを削除してもかまいません。続けようとする動機付けの要因は、内乱が私をその日疑問にさせたとしても、誰か他の人と仕事をすることです。私がそれを放棄することを阻む唯一のことは、コーディング以外で彼とつながるような友情です。もちろん、これはあまり論理に基づいた説明ではありません。彼らが関与する個人的な感情なので、私の意思決定能力を本当に曇らせます。
ダグラスガスケル

1
友人を失う最も簡単な方法は、彼らと平等に働くことです!

58

これは文化的なことかもしれません。いくつかの文化では、あなたが間違いを犯したことを認めることは前代未聞であり、間違いを犯すことを認めるように誰かに頼むことはあなたがすることができる最も粗いことについてです。そのような状況であれば、逃げます。

非常に賢い人との私の経験では、彼らがしていることは完璧ではないと彼らに言うと、彼らは(1)彼らがやっていることが実際に正しい理由をあなたに正確でわかりやすい理由を与え、(2)伝える彼らはそれが間違っていることを知っているが、彼らは優先順位のためにそれを修正する時間がない、または(3)それを指摘して修正してくれてありがとう。

学ぶことを拒否することは、ソフトウェア開発者が持つことができる最悪の属性についてです。彼に任せてください。人生は短すぎて貴重なので、彼に時間を費やすことはできません。


Gnasherに感謝します。実際にスケジュールはありませんが、定期的に#2が表示されるので、応答の有効性はわかりません。私はこれで寝て、私がAMで何を考えているかを見るつもりです、これは決定を下す前に多くの審議が必要です。
ダグラスガスケル

1
「それがその状況なら、逃げなさい。」-そしてちょうど一般的に、あなたの目標が何であるかについてコンセンサスに近づけることができない場合、誰かと協力することはできません。理由に関係なく、彼が「彼の」コードを変更することに同意しないようです。
スティーブジェソップ

まあ、時間のプレッシャーが変更を拒否する理由ではないようです。
gnasher729

1
これは素晴らしい答えです。誰かにやり方を変えるように強制することはできません!しかし、彼とあなたのプロジェクトには多くの時間と労力が費やされているようです。私の考えでは、彼はあなたがそれを行うべきだと思う方法を理解していないので、彼は自分のコードを変更したくないかもしれません。それか彼は頭がおかしいのですが、もし彼がそれを理解していないのなら、彼がイライラしているかもしれないと心に留めておいてください。私のアドバイスは、あなたとあなたの両方がそれをやっているときに彼と話し合うことです。
-zfrisch

^ +同じレベルで始めたとき、誰かに腹を立てられ、彼らはあなたのスキルを上回ります。確かにそうだと言っているわけではありませんが、確かにそれは何か関係があるようです。
zfrisch

12

おそらく最も簡単な方法は、他の誰かをプロジェクトに参加させることです-あなたが間違っていて、彼のコードベースがあなたにとってあまりにも賢いか、あなたが正しくて誰にとっても賢いかのどちらかです。すぐに判明し、ゴミ、複雑で、ジュニアプログラマーレベルのコードであることが判明した場合は、バックアップを取得します。

一方、動作する製品は、長年にわたって細かく調整されたエレガントで明確なコードの価値があります。ゲームを作成し、それを出荷し、その後立ち去ります-彼にそれを維持するように任せ、v2では動作しません。


2
返信してくれてありがとう。あなたがあなたの最初のポイントに言及しているのは面白い。彼は、プロジェクトを支援するために教えることができる初心者プログラマーを見つけて持ち込もうとしています。2人が同じスタイルのハックをして忘れている場合にのみ、これが恐ろしい結果になると予想できました。私は2番目のオプションが好きで、それを作り、それを出荷し、そしてそれをそのままにします。私が遭遇するかもしれない問題は、私たちがゲームを出荷するための名前を持っているように、私たちはLLCを作っているが途中でいるということです。どちらの使用ももちろん50%のシェアを持ちます。しかし、私はそれを終えて次に進むことができました。プロジェクトは大規模で、しばらく時間がかかる可能性があります。
ダグラスガスケル

20
どんな状況でも、そのような人と法的拘束力のあるビジネス関係を結びたいとは思わないでしょう。
gnasher729

3
@ douglasg14bは、教えるために後輩を連れてきます。「経験を積んだ人を連れてきて、「スピードを上げて製品を仕上げるのを手伝う」ように提案してください。フィニッシュラインに照準を合わせますか?それとも、二人ともこの趣味に永遠に取り組むつもりですか?(それがキャンセルされるまで起こる)
gbjbaanb

間違いなく仕上げる予定です。私は最初のプロジェクトとして取り組むにはあまりにも大きなプロジェクトだったと思いますが。シンプルなデザインとして始まりましたが、現在の規模に近い場所には想定されていませんでした。私たちのスコープの境界線は、私のパートナーによる機能のクリープで常に押し進められています。それを部分的に責めています。範囲は、放っておけばおそらく1年以内に完成を見ることになるということです。ありがたいことに、どのようにプログラミングしたかによって、部品を簡単に取り出して、後で他のプロジェクトに入れることができます。
ダグラスガスケル

4
コードはあなたではなくプロジェクトに属していると考えてください。製品の共同所有権がある場合は、次のプロジェクトですべてのコードを再利用できます。誰が何を所有しているかわからない場合は、今すぐその議論をしてください。がんばろう。
gbjbaanb

9

いくつかは互いに排他的であっても、いくつかのアイデアがあります。

  • 個別のソース責任。モジュールAで作業し、モジュールBで作業する場合、さまざまなスタイルと競争できます。彼は頻繁に機能をリリースしていますか?彼は自分のコードをゼロから書き直す必要があるポイントに達しましたか?モジュールのコードをリファクタリングし、彼のコードに触れないでください。

  • 彼に彼の最悪のコードのメンテナンスをさせてください。彼がそれをうまくやれば、あなたはひどい仕事を避けました。彼ができない場合、彼は痛みを感じるでしょう。

  • ユーザーまたはビジネスの観点から考えてください。場合によっては、GoogleまたはMicrosoftが購入する実行可能な製品のみが必要です。他では、製品を市場に投入し、バグのあるコードまたはハッキングされたコードで数千のクライアントをサポートするのは大変なことです。コードが核ミサイルを搭載したドローンを制御している場合や、ティーンエイジャー向けの楽しいビデオを作成している場合は同じではありません。

  • 彼はクラスを行い、あなたはテストを行います。テストによるコードのリファクタリングは、より簡単で安全です。この方法では、コード内をJunitバーだけで見る必要はありません。これは、A)テストをプログラミングしていること、B)同僚のコードがテスト可能であることを前提としています。コーディング段階でテストを構築するのが難しいと思う場合、後の方が悪いでしょう。

  • トレーニングやイベントに一緒に行きます。あなたが正しい方法を知らないとき、あなたが知っている唯一の方法を使用するのは非常に自然です。他人のコードを見ると、すべてを解決できるわけではありませんが、試してみても害はありません。

  • 補完的な強みを見つけます。リファクタリングは楽しいこともあります。彼が少なくとも機能するものを書いたら、リファクタリングを行うかもしれません。彼は、本番コードで終わらないソリューションを調査するためにスパイクを行うことができます。

  • 彼はコードを書き直したくないかもしれませんが、新しいコードをより良く書くことに同意するかもしれません。書き直しはつらくて退屈で、物事を壊す可能性があることを理解しています。質の高い島をいくつか育てます。このようにして、彼は物事を行う方法の良い例を持っています。

  • ボーイスカウトルールを使用します。作業する必要がない限り、何も手を加えないでください。モジュールの記述がひどくても動作し、変更する必要がない場合は、そのままにしておきます。バグを修正したり、機能を完成させる必要がある場合は、少し改善してください。しばらくすると、時間の80%を変更するクラスの20%が改善されます。質の高い島々。

両方を知らない限り、最善の解決策を提案することはできません。がんばろう。


4

OK、あなたがたぶん好きではない答えです。

機能の実装に失敗しない限り、コードを「修正」しないでください。

これが私の推論です。あなたはおそらくお金を稼ごうとしています。お金を稼ぐには、完成した機能を迅速に出荷する必要があります。「よくコード化された」コンピューターゲームにこれ以上お金を払う人はいません。

ほとんどの企業には同じ問題があります。リファクタリングは、速度や信頼性の面で、時には客観良く、それがより良い"作るために既存のコードをORの新機能を記述します。

単純な費用便益分析の結果、99%の時間で新機能の作成を選択しました。


15
しかし、これは「技術的負債」の議論全体に該当しますよね?新しい機能を作成する(または既存の機能を変更する)場合、リファクタリングを続けた場合の3倍の時間がかかり、10倍のバグが発生しますか?もしそうなら、おそらくリファクタリングをスキップすることは誤った経済でした。
ベンアーロンソン

1
あなたはそう思うだろうが、私は多くの成功した企業で働いてきた。私の結論は、単に報われるということです。
ユアン

それは十分に公正であり、これについてはさまざまな意見があると確信していますが、どちらか一方に対処することは答えからの重大な省略であるように思えます。また、私は間違っているかもしれないが、問題の行の間に読んで、私はOPが心配された不正なコードがかもしれないと思う方法でコードおうとしている思考のようなものよりも悪いです。
ベンアーロンソン

へえ、うん!しかし、変更を行うコストが非常に高いようにも思えます。私の答えでは、「お金のためにあなたはこれにいますか?」という目的を与えようとします。答えに加えて、確率のバランスがどこにあるかについての私の主観的見解
ユアン

1
これは場合によっては合理的ですが、誰かの「作業コード」が他の人にコードの2倍の時間を費やさせたり、システムを統合したり、将来の作業をさせたりする場合、単純な「船対非船」の決定ではなくなります。多くの大規模プロジェクトは、迅速に行うのではなく、適切に行うための意思決定を行わないために死にます。
エンダーランド

3

私はこれまでのところ、すべての答えが好きです。enderlandの答えからポイントの1つを取る:

欲求不満なときに誰かと自発的に仕事をすることには利点がありますか?

コードレビュースタック交換のためにプラグインするためにこの時間をとりたいです。専門家がコードを批評できるすばらしい場所です。正直なところ、そこにあるコードレビューの多くは、質問者、回答者、およびそれらを偶然読んで読んでいる関係者に非常に役立ちます。プロフェッショナルな環境でこのような有用なレビューを受け取ることはめったにありません(これは、何らかの理由で働いた場所に当てはまる場合があります)。

私のアドバイスは、レビューのためにコードの一部を投稿することです。この男が間違っていることを証明するために弾薬として使用することはお勧めしません-彼がそれを心に留めるとは思いませんが-あなたが書いたコードと彼が書いたコードの両方について非常に有用な情報を得ることができます。あなたが二人で最も争うコードの断片を提出することをお勧めします。ほとんどの場合、あなたは両方ともある程度間違っており、客観的な第三者が介入する方法としてレビューを使用できます。これにより、いくつかのことが実現します。

  • 状況の感情的な緊張から切り離すことができます。

  • リアルタイムの専門家のアドバイスが得られます。学んでいることを大きく後押しします。

  • 誰かがあなたが間違っていると言うでしょう。これは良いことです。なぜなら、どんな時間でもプログラミングをしている人なら誰でもこれを聞くからです。あなたが働いているこの男のようにそれを不十分に扱うことができます、またはあなたはそれに対処することを学ぶことができます。

コードレビューを正しい方法で使用すると、この非常にイライラする人に対処することで多くのことが得られると思います。また、「ほとんどの場合正しい方法だから、これを行う」という本やウェブサイトよりもはるかにインタラクティブです。

同様に、ゲーム開発者のスタック交換があります。レビューのためにコードを投稿する場所ではありませんが、苦労している概念/アイデアについて尋ねる場所です。繰り返しますが、その場所は関係者全員にとって非常に役立ちます。

これらのサイトの両方を見たことがあるかもしれません。ツールセットの一部であることを確認したかっただけです。


2

それはかなり絶望的に聞こえます。あなたがそうであると感じたら、おそらくあきらめて先に進むでしょう。間違いなく立ち去る時間があり、そこにいるかもしれません。

まだ立ち去る準備ができていない場合は、プロセスについてより良い合意に達する方法を見つける必要があります。コーディング標準はあるようですが、合意された標準ではないようです。次に岐路に立つとき、次にちょっとしたコードで猿になりたいとき、そしてあなたの仲間がそれを放っておきたいとき、次の行に沿って会話のために撃ってください:

ダグラス:Xを変更したいのですが、これはガイドラインの右にあります。

相棒:それは大丈夫です。

ダグラス:ガイドラインを変更すべきだと言っているのですか?

バディ:いいえ、私はそれがどんなに良いと思うだけです。

ダグラス:では、ガイドラインは何ですか?

バディ:知らない-あなたが書いた。

ダグラス:どのようなガイドラインを書きますか?

バディ:ガイドラインを書きません。時間の無駄です。

ダグラス:それでは、ガイドラインを捨てて、当時考えていたがらくたを書いてください。

バディ:これはがらくたではありません。

ダグラス:完璧ですか?理想的ですか?

バディ:仕事を終わらせます。次の機能に移りましょう。

ダグラス:Xが良いコードであり、Yが悪いコードであるという点で私たちが同意できるものはありますか?

バディ:放っておけ。コーディングしたいだけです!

まあ、それはうまくいきませんでしたか?私はあなたとバディが違うものを欲しがっているという感じだと思います。同意できるものがあれば、素晴らしい。そこから始めて、それに基づいて構築します。しかし、あなたは彼があなたが望むものを望んでいることに同意させることはできません-あなたが自分が彼が望むように見えるものを望み得る以上に。その共通の欲求を見つけて、そこから共通の合意に達することができれば、おそらく一緒に働くことができます。

ダグラス:何が欲しい?

バディ:コーディングしたいだけです。

ダグラス:私もコーディングしたいのですが、自分のコードを誇りに思いたいです。

バディ:私は自分のコードを誇りに思っています。

ダグラス:ここに私が誇りに思う機能があります-あなたはそれについてどう思いますか?

buddy:まあ、大丈夫ですが、ループ内でXを再計算しないでください。非効率的です。

ダグラス:では、常にループの外側で定数値を計算するべきだと言っているのですか?

バディ:まあ、当たり前!

ダグラス:それがガイドラインにあるべきだと思いますか?

バディ:もちろん。

ダグラス:OK、ガイドラインに追加し、コードを更新します...

ダグラス:今はどうですか?

バディ:元気。

現在、バディはガイドラインに(間接的に)貢献しているので、彼は少し所有権を持っています。たぶん-たぶん-彼はそれらをもっと真剣に受け止め始めるでしょう。スレートを一掃し、最初からガイドラインのほとんどまたはすべてをバディから取得できるようにガイドラインからやり直したいと思うと思います。先に進んで、たわごとのコードを書いて、ガイドラインに追加する必要があると感じてください。それらを彼から出させてください。たぶん、彼はそれらの理由を理解し始めるでしょう。

しかし、あなたがむしろあきらめて先に進みたいなら、それはそのような悪いオプションでもないかもしれません。


2

プロジェクトを放棄すると決めたと仮定します。

  • コードを分岐し、「前/後」ポートフォリオ項目として使用してリファクタリングします
  • 目標は(主にまたは部分的に)プログラミングを学習することであり、何かを学習することは既に知っていることを実行するのに2〜4倍かかるため、その作業は無駄になりません。
  • 「サンクコストアタッチメント」(学習する前にベンチャーに行った投資は悪い考えでした)は、意思決定における最も一般的な人為的ミスの1つです。
  • 友情を保つには、コーディングよりも友情を優先するという決定を下してください。

1

tl; dr間違いなくプロジェクトを放棄する必要があります。

これについてもう知ることなく、あなたは私たちに言った、私はあなたが経験している摩擦は経験に関連していると推測するだろう。

あなたがITプロとしての職業上のプログラマーではないとしても、おそらく物事を最初から正しく行うための難しい方法を学んだと思いますが、将来の自己への言及は、過去に彼/彼女をめちゃくちゃにし、学んだことを示していますしないで。

あなたの2年生のCSの生徒は、たとえかなり才能があっても、おそらくそれをしたという見方を欠いているでしょう(あなたが私のようなら、繰り返し:)。

彼/彼女は、そうしないことで傷を燃やすか、例外的なエンジニアリングの規律のある文化で指導されるまで、あなたが行くときに物事を修正することの価値を本当に信じないでしょう。

この人あなたのプログラミングピアであるかもしれませんが、あなたのプロジェクトピアではないので、ピアゲームとしてこのゲームをすることは失われた原因である可能性が高いです。将来のコストを食べるだけの準備ができていない限り。関係はあなたにとって十分に価値があるかもしれません。その場合、自分自身を掛けるのに十分なロープを裾に付けて、その人が問題を認めざるを得ない場合に混乱を一掃するのに役立つように介入してください。

それ以外の場合は、仲間と一緒に保釈してプロジェクトを行うか、最初からダイナミックなメンター/メンティープロジェクトを行います。


1

すべての素晴らしい答えにポイントを追加するには:

  • プロジェクトを完了するのにどれだけの労力がかかりますか?「最後の10%」を完了するには、人々が予想するよりもはるかに時間がかかることに注意してください。これには、プレイのテスト/調整、ユーザビリティの修正、さまざまなターゲットプラットフォームへの対応、リリースなどが含まれます。iOSゲームの場合は、コード署名があり、Appleのレビューを通過します。正直なところ、仕上げには最初の「90%」までかかることがあります。そして、コードがあなたが提案するほど悪いなら、それはさらに難しくなります。(今すぐテストを開始できますか?)
  • 現実的には、人々があなたのゲームを楽しむ可能性はどれくらいですか?
  • サンクコストヒューリスティック」に注意してください。全体像に照らして、その10,000行のコード投資を評価し、完成した製品を振り返り、過度の楽観的な見方はしません。
  • さらに3年かかっても続けられますか?あなたの2人は異なる開発スタイルを持っています(チームにはあまり適していません)。あなたは忍耐の終わりに近づいているように聞こえます、そして、あなたが続けるならば、友人でいるのは難しいかもしれません。

3
コードの90%がゴミである場合、「最後の10%」はかなり長くかかります:
gnasher729

0

コメントなどを使用して、自分が正しいと思う方法でコードを実行し、コードのバージョンをコピーしてください(彼がコードを変更した場合)。

戦わないで、怒らないで、彼の悪い決断を見たら微笑んでください。

ユーザーとして文句を言うのは、それが機能している場合にのみ文句を言うことです。

eitherめないでください、あなたとは違う人に慣れることが重要です。それは実際の仕事で起こります。

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