開発者の新年の約束

画像

ローマプロンスキーによる写真







これは、Go言語の主要な開発者の1人であるRuss Coxの投稿の翻訳です。RussCoxは、伝統的な新年の時間形式で約束を果たし、それを実現する計画を立てています。







意思決定の時が来たので、Goに関連して今年取り組んでみたいことについて少し話をするのは理にかなっていると思いました。







毎年、目標を設定します-Go-developers支援します。 Goの作成者が行うことは、すべてのGo開発者にプラスの効果があることを確認したいと思います。 ミスを犯す多くの方法があるため、たとえば、不要なコードのクリーニングや最適化に時間がかかりすぎることがあります。 最も一般的または最近の苦情や質問にのみ対応する。 短期的な改善に不必要に焦点を合わせます。 したがって、外部からすべてを見て、Goコミュニティに最も利益をもたらすものを実行することが非常に重要です。







この記事では、今年焦点を当てる主なタスクのいくつかを説明します。 これは私自身のリストであり、Goチーム全体ではありません。







まず、ここに書かれているすべてのことについてフィードバックをもらいたいです。 第二に、以下で説明する問題が本当に重要だと考えていることを示したいと思います。 Goチーム側のアクティビティの欠如は、すべてが非常にうまくいっていることを示すシグナルであると多くの人が感じていることが多いと思いますが、実際には他の優先度の高いタスクを解決しているだけです。







タイプエイリアス



大規模なコードベースのリファクタリングで、あるパッケージから別のパッケージに型を移動すると、常にポップアップの問題が発生します。 昨年、 一般的なエイリアスを使用してそれを解決しようとしましたが、これは機能しませんでした:変更の本質をあまりにも不十分に説明し、変更自体が遅かったため、コードはGo 1.8をリリースする準備ができていませんでした。 この経験から学び、根本的な問題について記事書いて書いたところ、Goバグトラッカーで可能な解決策について生産的な議論が行われました。 より限定的な型エイリアスを導入することが次のステップになると思われます。 Go 1.9に登場することを願っています。 #18130







パッケージ管理



2010年2月に、公開パッケージをダウンロードするためのGoのサポートを開発しました(goinstallはgo getになりました)。 それ以来、多くのことが起こっています。 特に、他の言語のエコシステムはパッケージ管理システムへの期待を真剣に高めており、オープンソースコミュニティはセマンティックバージョニングとほぼ一致しており、異なるバージョンの互換性の基本的な理解を提供します。 ここでGoを改善する必要があり、人々のグループはすでに解決策に取り組んでいます 。 これらのアイデアが標準のGoツールに正しく統合されるようにします。 パッケージ管理をGoのもう1つの利点にしたいのです。







ビルドシステムの改善



go



チームとのビルドには、修正が必要ないくつかの欠陥があります。 以下は、私の仕事に専念する3つの典型的な例です。







go



ユーティリティはアセンブリの結果を十分にキャッシュしないため、アセンブリは非常に遅くなる可能性があります。 多くの人は、 go install



がその作業の結果を保存することを理解していませんが、 go build



は保存しないので、彼らはgo build



も何度go build



を実行し、ビルドが遅くなると予想されます。 同じことは、依存関係が変更されたgo test –i



なしでgo test –i



を繰り返すgo test



も当てはまります。 可能な限り、すべてのタイプのアセンブリはインクリメンタルでなければなりません。 #4719







テスト結果もキャッシュする必要があります。入力データが変更されていない場合、通常はテスト自体を再起動する必要はありません。 これにより、軽微な変更または変更がない場合に「すべてのテスト」を実行するコストが大幅に削減されます。 #11193







GOPATH外での作業は、その内部での作業とほぼ同じ方法でサポートされる必要があります。 特に、 git clone



を実行し、 cd



を使用してディレクトリにgo



コマンドを実行すると、すべて正常に機能するはずです。 パッケージ管理は、このタスクの重要性を高めるだけです。異なるバージョンのパッケージ(たとえば、v1とv2)を別々のGOPATHを維持することなく操作できる必要があります。 #17271







基本コードセット



コードベースのリファクタリングに関する私のプレゼンテーションと記事は、実際のプロジェクトの具体的な例から恩恵を受けたように思えます。 また、獣医に追加することで実際のプログラムに特有の問題を解決する必要があるという結論に達しました。 この実際の実践の分析が、囲inの変化を議論し評価する標準的な方法になることを望んでいます。







現在、このような分析を行うための一般的に受け入れられている特徴的なコードのセットはありません。誰もが最初に独自のプロジェクトを作成する必要があり、これは大変な作業です。 コミュニティがチェックできる分析用の公式のコアコードセットを含む単一のスタンドアロンGitリポジトリをまとめたいと思います。 考えられる出発点は、GitHubの上位100のGoリポジトリで、星、フォーク、またはその両方の数です。







自動獣医



Goディストリビューションには、一般的なエラーを示す強力なツールgo vet



が付属しています。 これらのエラーの基準は高いため、彼のメッセージを聞く必要があります。 しかし、主なことは獣医を実行することを忘れないことです。 これを覚えていない方が便利でしょうが。 減速なしでgo test



実行したときに発生するバイナリの最終コンパイルとリンクと並行してvetを実行できると思います。 成功し、許可された獣医検査を100%正確なサンプルに制限すると、一般に獣医合格をテスト実行の前提条件に変えることができます。 その場合、開発者はgo vet



を実行する必要があることを覚えておく必要はありません。 彼らはgo test



を実行し、獣医は時折重要な何かを報告し、不必要なデバッグを避けます。 #18084 #18085







エラーと一般的な慣行



Goのエラーメッセージの一般的な慣行の一部として、関数には関連するアクセス可能なコンテキストが含まれ、どの操作が試行されたかに関する情報(関数名とその引数)が含まれます。 たとえば、このプログラム







 err := os.Remove("/tmp/nonexist") fmt.Println(err)
      
      





ディスプレイ







 remove /tmp/nonexist: no such file or directory
      
      





すべてのGoコードがos.Remove



と同じことをos.Remove



わけではありません。 多くのコードはただ







 if err != nil { return err }
      
      





コールスタック全体にわたって表示される必要がある便利なコンテキストをスローします(たとえば、上記のremove /tmp/nonexist:



)。 コンテキストを含めることに対する期待に間違いがないかどうか、そしてより有益なエラーを返すコードを簡単に作成できるようにするために何かできるかどうかを理解したいと思います。







コミュニティからは、コンテキストからエラーをクリアするためのインターフェースについてさまざまな議論があります。 そして、いつ正当化されるのか、そして何らかの公式な勧告を考え出すべきかどうかを理解したいと思います。







コンテキストとベストプラクティス



Go 1.7では、新しいコンテキストパッケージを追加して、リクエストに何らかの形で関連する情報(たとえば、 タイムアウト、リクエストがキャンセルされたかどうか、認証データなどを保存しました 。 個々のコンテキストは不変です(文字列や整数値など)。新しく更新されたコンテキストのみを取得して、コールスタックに明示的に渡すか、(あまり一般的ではありませんが)トップに戻すことができます。 現在、コンテキストはAPIを介して送信されます(たとえば、 database / sqlおよびnet / http )。主に、呼び出し元が処理の結果を必要としなくなったときに、要求の処理を停止できます。 タイムアウトに関する情報は、コンテキストでの転送に非常に適していますが、たとえば、クエリ実行中に可能なすべてのデータベース操作に等しく適用される可能性が低いため、データベースオプションには絶対に適していません。 タイムソースまたはロガーはどうですか? コンテキストに保存することは可能ですか? コンテキストで使用できるものとできないものの基準を理解し、説明しようとします。







メモリモデル



他の言語とは異なり、Goのメモリモデルは意図的に控えめであり、ユーザーに多くの約束を与えません。 実際、この文書には特に読む価値はないと書かれています。 同時に、他の言語よりもコンパイラが必要です。特に、整数値の競合は、プログラムの任意の動作の言い訳にはなりません。 完全なスペースもあります。たとえば、 sync / atomicパッケージは言及されていません。 メインコンパイラおよびランタイムシステムの開発者は、これらのアトムがC ++のseqcst-atomsまたはJavaのvolatileと同じように動作する必要があることに同意すると思います。 しかし同時に、これをメモリモデルと長期的なブログ投稿にきちんと入力する必要があります。 #5045 #7948 #9442







不変性



Race検出器は、Goのお気に入りの機能の1つです。 しかし、レースをまったく行わない方がさらに良いでしょう。 リンクの不変性をGoに統合して、 書き込み可能なものとできないものについて明確で検証済みの判断を行い、特定の競合状態がコンパイルされないようにするための合理的な方法が本当に欲しいです。 Goにはすでに1つの不変型がありstring



-string; string



が不変の[]byte



名前付き型(またはエイリアス)であると遡及的に判断するとよいでしょう。 今年は実装できないと思いますが、可能な解決策を見つけたいと思います。 Javari、Midori、Pony、Rustはすでに興味深いオプションを特定しています。さらに、このトピックに関する一連の研究があります。







長い目で見れば、競合状態の可能性を静的に排除できれば、ほとんどのメモリモデルを放棄できます。 おそらくこれは夢のような話ですが、繰り返しますが、解決策の可能性をよりよく理解したいと思います。







ジェネリック



Goの開発者と他の言語のプログラマーの間で最も活発な議論は 、Goがジェネリックをサポートするかどうか(またはこれが発生する期間)を巡って起こりました。 私の知る限り、GoチームはGoがジェネリックを必要としないと言ったことはありません。 対処する必要があるより重要なタスクがあると述べました。 たとえば、パッケージ管理サポートの改善は、ジェネリックを導入するよりも、ほとんどのGo開発者に非常に強いプラスの効果をもたらすと考えています。 しかし同時に、パラメトリック多型の欠如が深刻な障害になることもあります。







個人的には、チャネルを操作するための一般的な関数を作成できるようにしたいと思います。例えば:







 // Join        //      . func Join(inputs ...<-chan T) <-chan T // Dup    c   c1   c2 func Dup(c <-chan T) (c1, c2 <-chan T)
      
      





また、 FlumeJavaLINQに似たGoの高レベルのデータ処理抽象化を記述できるようにして、型の不一致エラーが実行時ではなくコンパイル時にキャッチされるようにします。 ジェネリックを使用して多数のデータ構造またはアルゴリズムを作成できますが、このような高レベルのツールはより興味深いと思います。







数年にわたり、ジェネリックをGoに導入する適切な方法を模索しています。 最後のいくつかの提案は、一般的なパラメトリック多相性( chan T



ような)およびstring



[]byte



統合を提供するソリューションの開発に関するものでした。 前の部分で説明したように、不変性に基づいたパラメータ化によって後者が解決される場合、おそらくこれにより汎用アーキテクチャの要件が簡素化されるでしょう。







2008年にGoでジェネリックについて初めて考えたとき、主な例はC#、Java、Haskell、およびMLでした。 しかし、これらの言語で実装されたアプローチはどれもGoに最適とは思えませんでした。 今日では、たとえばDart、Midori、Rust、Swiftなどの最新のソリューションがあります。







敢えてこのトピックに取り組み、可能なオプションを検討してから数年が経ちました。 おそらく、特に可変性/不変性に関する情報と新しい言語のソリューションに照らして、もう一度見て回るときが来たでしょう。 今年はジェネリック医薬品がGoに登場するとは思いませんが、この問題を理解したいと思います。








All Articles