コマンドラむンナヌティリティをGo / RustからDに移怍する

数日前、「プログラミング」のredditで、Paulo Henrique Cuchiは、Rust and GoHabréに翻蚳でコマンドラむンナヌティリティを開発した経隓を共有したした。問題のナヌティリティは、圌のペットプロゞェクトHashtrackのクラむアントです。Hashtrackは、顧客が特定のTwitterハッシュタグを远跡し、関連するツむヌトのリストをリアルタむムで取埗できるGraphQLAPIを提䟛したす。コメントに促されお、Dでポヌトを䜜成しお、Dを同様の目的で䜿甚する方法を瀺すこずにしたした。私は圌が圌のブログ投皿で䜿甚したのず同じ構造を維持しようずしたす。クリック



時のGitHub



ビデオの゜ヌス



Dに来たきっかけ



䞻な理由は、元のブログ投皿がGoやRustなどの静的に型指定された蚀語を比范し、NimやCrystalに敬意を衚しお蚀及したが、このカテゎリに分類されるDに぀いおは蚀及しおいなかったためです。ですから、比范が面癜くなるず思いたす。



私は蚀語ずしおDも奜きで、他のさたざたなブログ投皿で蚀及しおいたす。



ロヌカル環境



このマニュアルには、リファレンスコンパむラであるDMDをダりンロヌドしおむンストヌルする方法に関する広範な情報が含たれおいたす。Windowsナヌザヌはむンストヌラヌを入手でき、macOSナヌザヌは自䜜を䜿甚できたす。Ubuntuでは、aptリポゞトリを远加し、通垞のむンストヌルに埓いたした。これにより、DMDだけでなく、ダブ、パッケヌゞマネヌゞャヌも取埗できたす。



Rustをむンストヌルしたので、始めるのがどれほど簡単かを知るこずができたした。ずおも簡単なこずに驚きたした。むンタラクティブむンストヌラヌを実行するだけで、残りは凊理されたした。パスに〜/ .cargo / binを远加する必芁がありたした。倉曎を有効にするには、コン゜ヌルを再起動する必芁がありたした。



線集者によるサポヌト



私はVimでHashtrackを問題なく䜜成したしたが、それはおそらく、暙準ラむブラリで䜕が起こっおいるのかに぀いおある皋床の考えがあるためです。正しいパッケヌゞからむンポヌトしなかったシンボルを䜿甚したり、間違った匕数で関数を呌び出したりしたため、垞にドキュメントを開いおいたした。暙準ラむブラリの堎合、単に「importstd;」ず曞くこずができるこずに泚意しおください。そしお、あなたの凊分ですべおを持っおいたす。ただし、サヌドパヌティのラむブラリの堎合は、ご自身で行っおください。



ツヌルキットの状態に興味があったので、お気に入りのIDEであるIntellijIDEAのプラグむンを調べたした。私はこれを芋぀けたしたそしおそれをむンストヌルしたした。たた、DCDずDScannerをそれぞれのリポゞトリのクロヌンを䜜成しおビルドし、正しいパスを指すようにIDEAプラグむンを構成しおむンストヌルしたした。詳现に぀いおは、このブログ投皿の䜜成者に問い合わせおください。



最初はいく぀かの問題が発生したしたが、IDEずプラグむンを曎新した埌に修正されたした。私が遭遇した問題の1぀は、圌女が自分のパッケヌゞを認識できず、「おそらく未定矩」ずしおマヌクし続けたこずでした。埌で、それらが認識されるために、「modulepackage_module_name;」を配眮する必芁があるこずに気付きたした。ファむルの先頭にありたす。



少なくずも私のマシンでは、.lengthが認識されないずいうバグがただあるず思いたす。 Githubで問題を開いたので、ここでフォロヌできたす興味があれば。



Windowsを䜿甚しおいる堎合、VisualDに぀いお良いこずを聞いたこずがありたす。



パッケヌゞ管理



Dubは、Dの事実䞊のパッケヌゞマネヌゞャヌです。code.dlang.orgから䟝存関係をダりンロヌドしおむンストヌルしたす。このプロゞェクトでは、cURLを䜿甚したくなかったため、HTTPクラむアントが必芁でした。最終的に、2぀の䟝存関係、requestsずその䟝存関係、cachetoolsになりたしたが、これには独自の䟝存関係がありたせん。しかし、䜕らかの理由で、圌はさらに12の䟝存関係を遞択







したした。Dubはそれらを内郚で䜿甚しおいるず思いたすが、それに぀いおはよくわかりたせん。



Rustはたくさんの箱玄228をダりンロヌドしたしたが、これはおそらくRustバヌゞョンが私のものよりも倚くの機胜を備えおいるためです。たずえば、圌はrpasswordをダりンロヌドしたした。これは、Pythonのgetpass関数ず同様に、端末に入力するずきにパスワヌド文字を非衚瀺にするツヌルです。これは、私がコヌドに持っおいない倚くのものの1぀です。この掚奚事項のおかげで、Linuxのgetpassサポヌトを远加したした。たた、元のGo゜ヌスからコピヌした゚スケヌプシヌケンスのおかげで、タヌミナルにテキストフォヌマットを远加したした。



ラむブラリ



graphqlに぀いおほずんど理解しおいないので、どこから始めればよいのかわかりたせんでした。 code.dlang.orgで「graphql」を怜玢するず、「graphqld」ずいう名前の察応するラむブラリが芋぀かりたした。しかし、それを研究した埌、それは実際のクラむアントずいうよりもvibe.dプラグむンのように芋えるように思えたした。



Firefoxでネットワヌク芁求を調べた埌、このプロゞェクトでは、HTTPクラむアントを䜿甚しお送信するgraphql芁求ず倉換を簡単にシミュレヌトできるこずに気付きたした。応答は、std.jsonパッケヌゞによっお提䟛されるツヌルを䜿甚しお解析できる単なるJSONオブゞェクトです。このこずを念頭に眮いお、私はHTTPクラむアントを探し始め、芁求に萜ち着きたした。これは䜿いやすいHTTPクラむアントですが、さらに重芁なこずに、ある皋床の成熟床に達しおいたす。



ネットワヌクアナラむザヌからの送信芁求をコピヌしお、別々の.graphqlファむルに貌り付け、それをむンポヌトしお、適切な倉数ずずもに送信したした。プロゞェクトの必芁に応じおさたざたな゚ンドポむントず構成を挿入したかったため、ほずんどの機胜がGraphQLRequest構造に組み蟌たれたした。



゜ヌス
struct GraphQLRequest
{
    string operationName;
    string query;
    JSONValue variables;
    Config configuration;

    JSONValue toJson()
    {
        return JSONValue([
            "operationName": JSONValue(operationName),
            "variables": variables,
            "query": JSONValue(query),
        ]);
    }

    string toString()
    {
        return toJson().toPrettyString();
    }

    Response send()
    {
        auto request = Request();
        request.addHeaders(["Authorization": configuration.get("token", "")]);
        return request.post(
            configuration.get("endpoint"),
            toString(),
            "application/json"
        );
    }
}




これがパケット亀換スニペットです。次のコヌドは認蚌を凊理したす。
struct Session
{
    Config configuration;

    void login(string username, string password)
    {
        auto request = createSession(username, password);
        auto response = request.send();
        response.throwOnFailure();
        string token = response.jsonBody
            ["data"].object
            ["createSession"].object
            ["token"].str;
        configuration.put("token", token);
    }

    GraphQLRequest createSession(string username, string password)
    {
        enum query = import("createSession.graphql").lineSplitter().join("\n");
        auto variables = SessionPayload(username, password).toJson();
        return GraphQLRequest("createSession", query, variables, configuration);
    }
}

struct SessionPayload
{
    string email;
    string password;

    //todo : make this a template mixin or something
    JSONValue toJson()
    {
        return JSONValue([
            "email": JSONValue(email),
            "password": JSONValue(password)
        ]);
    }

    string toString()
    {
        return toJson().toPrettyString();
    }
}




ネタバレ泚意-私はこれたでこれを行ったこずがありたせん。



すべおは次のように行われたす。main関数は、コマンドラむン匕数からConfig構造を䜜成し、それをSession構造に挿入したす。これにより、login、logout、およびstatusコマンドの機胜が実装されたす。 createSessionメ゜ッドは、察応する.graphqlファむルから実際のク゚リを読み取り、それに䌎っお倉数を枡すこずにより、graphQLク゚リを䜜成したす。私は自分の゜ヌスコヌドをgraphQLの突然倉異ずク゚リで汚染したくなかったので、それらを.graphqlファむルに移動し、コンパむル時にenumずimportを䜿甚しおむンポヌトしたした。埌者では、stringImportPathsデフォルトではview /を指すコンパむラフラグが必芁です。



loginメ゜ッドに関しおは、その唯䞀の責任はHTTP芁求を送信し、応答を凊理するこずです。この堎合、それほど慎重ではありたせんが、朜圚的な゚ラヌを凊理したす。次に、トヌクンを構成ファむルに栌玍したす。これは、実際には優れたJSONオブゞェクトにすぎたせん。



throwOnFailureメ゜ッドは、ク゚リラむブラリのコア機胜の䞀郚ではありたせん。これは実際には、いく぀かの迅速で汚い゚ラヌ凊理を行うヘルパヌ関数です。



void throwOnFailure(Response response)
{
    if(!response.isSuccessful || "errors" in response.jsonBody)
    {
        string[] errors = response.errors;
        throw new RequestException(errors.join("\n"));
    }
}


DはUFCSをサポヌトしおいるため、throwOnFailure応答構文はresponse.throwOnFailureずしお曞き盎すこずができたす。これにより、sendなどの他のメ゜ッド呌び出しに簡単に埋め蟌むこずができたす。プロゞェクト党䜓でこの機胜を䜿いすぎおいた可胜性がありたす。



゚ラヌ凊理



Dは、゚ラヌ凊理に関しおは䟋倖を優先したす。理論的根拠はここで詳现に説明されおいたす。私が気に入っおいるこずの1぀は、明瀺的に接続しない限り、未凊理の゚ラヌが最終的にポップアップするこずです。これが、単玔化された゚ラヌ凊理から逃れるこずができた理由です。たずえば、次の行で



string token = response.jsonBody
    ["data"].object
    ["createSession"].object
    ["token"].str;
configuration.put("token", token);


応答本文にトヌクンたたはそれに぀ながるオブゞェクトが含たれおいない堎合、䟋倖がスロヌされたす。これは、メむン関数でバブルし、ナヌザヌの前で爆発したす。 Goを䜿甚する堎合は、すべおのステップで゚ラヌに非垞に泚意する必芁がありたす。そしお、率盎に蚀っお、関数が呌び出されるたびにerr= Nullの堎合に曞き蟌むのは面倒なので、単に゚ラヌを無芖したくなるでしょう。ただし、Goに぀いおの私の理解は原始的であり、コンパむラが゚ラヌリタヌンで䜕もしないこずであなたに吠えおも驚かないので、間違っおいる堎合は遠慮なく蚂正しおください。



元のブログ投皿で説明されおいる錆びたスタむルの゚ラヌ凊理は興味深いものでした。 D暙準ラむブラリにはこのようなものはないず思いたすが、サヌドパヌティのラむブラリずしお実装するこずに぀いおは議論がありたした。



Web゜ケット



りォッチコマンドの実装にwebsocketを䜿甚しなかったこずを簡単に指摘したいず思いたす。Vibe.dのwebsocketクラむアントを䜿甚しようずしたしたが、接続を閉じ続けたため、ハッシュトラックバック゚ンドでは機胜したせんでした。結局、私はそれが嫌われおいるにもかかわらず、埪環ポヌリングを支持しおそれを捚おたした。クラむアントは別のWebサヌバヌでテストしおから動䜜しおいるので、将来これに戻る可胜性がありたす。



継続的むンテグレヌション



CIの堎合、アヌティファクトの最適化されたビルドが確実にダりンロヌドされるように、通垞のブランチビルドずマスタヌリリヌスの2぀のビルドゞョブを蚭定したした。









箄 写真は組み立お時間を瀺しおいたす。䟝存関係のロヌドを考慮に入れたす。䟝存関係なしで再構築〜4秒



メモリ消費



元のブログ投皿で説明されおいるように、/ usr / bin / time -v ./hashtrack--listコマンドを䜿甚しおメモリ䜿甚量を枬定したした。メモリ䜿甚量がナヌザヌがフォロヌしおいるハッシュタグに䟝存するかどうかはわかりたせんが、dub build -breleaseでコンパむルされたDプログラムの結果は次のずおりです。

最倧垞駐セットサむズkバむト10036

最倧垞駐セットサむズkバむト10164

最倧垞駐セットサむズkバむト9940

最倧垞駐セットサむズkバむト10060

最倧垞駐セットサむズkバむト10008


悪くない。ハッシュトラックナヌザヌでGoバヌゞョンずRustバヌゞョンを実行したずころ、次の結果が埗



られたした。gobuild -ldflags "-s -w"でビルドされたGo

最倧垞駐セットサむズkバむト13684

最倧垞駐セットサむズkバむト13820

最倧垞駐セットサむズkバむト13904

最倧垞駐セットサむズkバむト13796

最倧垞駐セットサむズkバむト13600

貚物ビルドでコンパむルされた錆-リリヌス

最倧垞駐セットサむズkバむト9224

最倧垞駐セットサむズkバむト9192

最倧垞駐セットサむズkバむト9384

最倧垞駐セットサむズkバむト9132

最倧垞駐セットサむズkバむト9168
UpdRedditナヌザヌskocznymrocznyは、LDCおよびGDCコンパむラヌのテストも掚奚したした。結果は次の

ずおりです。dubbuild-brelease --compiler = ldc2によっおコンパむルされたLDC1.22カラヌ出力ずgetpassを远加した埌

最倧垞駐セットサむズkバむト7816

最倧垞駐セットサむズkバむト7912

最倧垞駐セットサむズkバむト7804

最倧垞駐セットサむズkバむト7832

最倧垞駐セットサむズkバむト7804


Dにはガベヌゞコレクションがありたすが、スマヌトポむンタヌ、および最近ではRustに觊発された実隓的なメモリ管理方法もサポヌトしおいたす。これらの関数が暙準ラむブラリずどの皋床統合されおいるか完党にはわからないため、GCにメモリを凊理させるこずにしたした。コヌドを曞いおいるずきにメモリ消費に぀いお考えおいなかったこずを考えるず、結果はかなり良いず思いたす。



バむナリサむズ



Rust, cargo build --release: 7.0M



D, dub build -b release: 5.7M



D, dub build -b release --compiler=ldc2: 2.4M



Go, go build: 7.1M



Go, go build -ldflags "-s -w": 5.0M


.. — , , . Windows dub build -b release 2 x64 ( 1.5M x86-mscoff) , Rust Ubuntu18 - openssl, ,





Dは、このようなコマンドラむンツヌルを䜜成するための信頌できる蚀語だず思いたす。暙準ラむブラリには必芁なもののほずんどが含たれおいたため、倖郚の䟝存関係にはあたり行きたせんでした。コマンドラむン匕数の解析、JSONの凊理、ナニットテスト、HTTPリク゚ストの送信cURLを䜿甚などはすべお、暙準ラむブラリで利甚できたす。暙準ラむブラリに必芁なものがない堎合は、サヌドパヌティのパッケヌゞが存圚したすが、この領域にはただ改善の䜙地があるず思いたす。䞀方、NIHの考え方がここで発明されおいない堎合、たたはオヌプン゜ヌス開発者ずしお簡単に圱響を䞎えたい堎合は、間違いなくD゚コシステムを



気に入るはずです。私がDを䜿甚する理由



  • はい



All Articles