きみはねこみたいなにゃんにゃんなまほう

ねこもスクリプトをかくなり

VSCode の Atom One Dark テーマをもう少しシックにカスタムする

ひと昔前まで Atom を使っていたのですが builtin terminal を始めとした機能性には抗えず VSCode に移行したのは記憶に新しいところです。

Atom の良かった点は何と言ってもあの、コーディングに最低限必要な情報以外を切り捨てたインタフェースです。ボタンの種類が少ないのもありますが、色使いのノイズの少なさは初めて見た時に目がハートマークになるくらいに気に入ったところです。

f:id:lightbulbcat:20180703232745p:plain

まさに私がエディタに求めていたものでした。

VSCode に移行するにあたって最後の後ろ髪になったのがこのカラーテーマで、何しろ VSCode のデフォルトのスタイルではこのように...

f:id:lightbulbcat:20180703234551p:plain

青色のステータスバーがチカチカするわ、ボタンが多いわ、バッジが目立つわで Atom のあのデザイン大好き人間からすると直視に耐えない(言い方が悪い)ユーザインタフェースです。機能が多いのはいいのですが、別に常に見えている必要はなく、そもそも使わないコントロールが大半だったりで、もっとこう何というか Zen な感じが欲しいんです。

VSCode の機能性は捨てがたい、しかしこのノイジーなインタフェースは...という葛藤。

で、VSCode には Atom One Dark という Atom のデフォルトのダークテーマをベースにしたテーマパッケージが存在します。それを適用すると以下のようになります。

f:id:lightbulbcat:20180703233427p:plain

とてもシックになりましたね。十分と言えば十分なのですが、まだ Atom には存在しない左端のバー(Activity Bar)が存在するのが気になります。どうでもいいと言えばいいのですがやっぱり気になります。ボタンなど少ないに越したことはないのです。しかし消したら消したで不便なので目立たせない方向性で微調整をしていきたいと思います。ついでにバッジの色も目立たないようにしていきます。コーディング領域以外は基本出しゃばらせたくはありませんね。

試行錯誤 & カラーピッキング & コピペの成果で以下のスタイルに行き着きました。

f:id:lightbulbcat:20180703232702p:plain

設定はこんな感じで行いました。差分だけ貼っておきます。

    "explorer.openEditors.visible": 0,
    "workbench.iconTheme": "vs-minimal",
    "workbench.colorCustomizations": {
        "activityBar.background": "#20252C",
        "activityBar.foreground": "#626C83",
        "activityBarBadge.background": "#567",
        "badge.background": "#20252C",
        "statusBar.background": "#20252C",
        "statusBar.noFolderBackground": "#222225",
        "statusBar.debuggingBackground": "#511f1f",
        "gitDecoration.ignoredResourceForeground": "#5B6270",
        "list.inactiveFocusForeground": "#444",
        "sideBar.background": "#20252C",
        "sideBarSectionHeader.background": "#20252C",
        "foreground": "#999",
        "terminal.foreground": "#999",
        "terminal.ansiRed": "#E26B73",
        "terminal.ansiGreen": "#96C475",
        "terminal.ansiBlue": "#5DADF1",
        "terminal.ansiCyan": "#51B6C3",
        "terminal.ansiMagenta": "#C774DF",
        "terminal.ansiYellow": "#E5C076",
    },
    "workbench.colorTheme": "Atom One Dark",

設定項目は VS Code Theme Color Reference を見ながら行いました。 色以外の設定項目は以下の通りです。

  • "explorer.openEditors.visible": 0 はファイルツリーと同じペインに表示される「Open Editors」を消しています
    • ペイン中のウィジェットが単一になるとメニューバーが上端にマージされるようなのでかなり見た目のノイズが減ります
  • "workbench.iconTheme": "vs-minimal" はデフォルトのアイコンがカラフルすぎるのでシックなものを採用しました
    • Atom だと git の変更ステータスがアイコンの色にも反映されたのですが VSCode にはそういう機能はありませんね

Atom だとウィンドウの上の白いバーが目立っていましたが、VSCode の場合はその領域もデザインに統合されているので、結果的に Atom 以上にシックなデザインにカスタマイズできたと思います。

ここまでやったらもう Atom に未練は無くなりました。ありがとう、Atom はとても素晴らしいエディタの形を私に見せてくれました。Atom のもたらしてくれたものを思い残すことなく VSCode に引き継ぎ、これからも思う存分 VSCode の機能性を満喫したいと思います。

最後にもう一度 Atom を見ておきます。エディタの表示面だけで言えばひとつの完成形です。

f:id:lightbulbcat:20180703232745p:plain

そして今回の VSCode を。

f:id:lightbulbcat:20180703232702p:plain

まだちょっと肩のボタンが多いですね。こういうのでも消せたら嬉しい人間はまちがいなくこの世に存在するのです。また時間があったらリファレンスを漁ってみます。

設定ファイルは myhome/settings.json at master · asa-taka/myhome · GitHub で管理していますので、最新版が気になる方は見ていただければと思います。

Wireshark でTLSの通信を読む

TLSの勉強中です。TLSの通信を眺めるにはやっぱりHTTPSだろうということで簡単なHTTPSサーバを立ててトラフィックを眺めてみたいと思います。『プロフェッショナルSSL/TLS』にも書かれていました。「一番良い方法は実際のパケットを見ることです」と。

下準備

Caddy を利用します。HTTPSとHTTP用の設定ファイルを用意します。

$ tree
.
├── Caddyfile.http
├── Caddyfile.https
├── cert.pem
├── key.pem
└── public
    └── index.html

$ cat Caddyfile.http
:8080
root public

$ cat Caddyfile.https
:8443
tls cert.pem key.pem
root public

自己署名証明書は以下のコマンドで生成しました。

$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes

HTTPS通信を覗いてみる

Wireshark 上であらかじめ lo0 をキャプチャする設定で待ち構えておきます。 フィルタは tcp.port == 8443 に設定しておきます。

$ caddy -conf Caddyfile.https

でサーバを立て

$ curl -v --insecure https://127.0.0.1:8443

で叩きます。

f:id:lightbulbcat:20180624035235p:plain

総パケット数は 39 でした。

HTTP通信を覗いてみる

$ caddy -conf Caddyfile.http

でサーバを立て

$ curl -v http://127.0.0.1:8080

で叩きます。

f:id:lightbulbcat:20180624040437p:plain

総パケット数は 14 でした。

サンプルプロジェクト

以上のような設定をまとめて GitHub に上げておきました。ご参考になれば幸いです。

『PKIハンドブック』覚え書き

2000年初版の『PKIハンドブック』が中古でお安かったので覚え書きを残していきます。

2015年出版の『プロフェッショナルSSL/TLS』と並行して読んでいるので気になる部分があれば抜き出してみようと思ったのですが...初心者的な視点から見ると特に目立った差異はありませんでした。 今後気をつけて読んでいきたいです。

SSL Ver3.0 からバージョンアップしたTLSを基に解説する」と本文にありますが、 普段から数年単位で要素技術や仕様がガラリと変わり得るフロントエンドの技術調査をすることが多い身からすると笑ってしまうくらい変わっていませんね。 それだけ学習量対効果に秀でた技術領域なのかな、という感触を受けています。 一度学んでおけば数十年単位で土台となる技術が身につくという。

この辺はHTTPも似たようなものですね。 そしてPKIと言えばSSLで、SSLと言えばHTTPSです。 フロントエンド側の人間でも Docker やデプロイ系の領域に手を伸ばし始めるとこの辺りの知識の有無が利いてきますね。 もしくはマッシュアップ方面の方がHTTPSには馴染みが深かったりするのでしょうか。

とにかく、日常で触れる機会も実は気にしてみると結構多かったりする領域なので、このあたりの仕組みや語彙はフロントエンドのトラブルシュートにも結構な係数で利いてくると思います。 という期待を込めて『PKIハンドブック』を読んでいきたいと思います。

本書を読むにあたり

18年前の本書を読むことについて

2018年現在、2000年初版の本書を読むことに対し、個人的に意義であると感じていることです。

  • 『プロフェッショナルSSL/TSL』とは別視点の本を読むことで概要把握の正確性の一助とする
  • (フロントエンド技術と比較して)息の長い技術がこの期間でどの程度変化したかに素朴に興味がある
  • 素朴に歴史、隔世の感を感じたい

勉強半分、趣味半分といったところです。

どんな技術にも起こり、流行り、廃りの流れがあり、そしてその流れを追いきれなかった現実のシステムは恐らく大量に残されていて、この先自分もどこかでそれに出くわすだろうと。 スナップショットでない、時間幅を持った知識や経験って、もしかしてそういうところで活きてくるんじゃないかなと。 「昔の本を読む」という単なる追体験、真似事ですが、それでも年表を追う以上の何かが得られたらいいなと思っております。

現在の興味領域に照らし合わせ、PKIの仕組みから運用のかじりについて触れられている第8章までを読んでいくつもりです。

SSL/TLS簡易年表

SSL TLS 備考
1994 2.0 - Netscape
1995 3.0 - Netscape
1995 (3.1) 1.0
2006 (3.2) 1.1
2008 (3.3) 1.2
2018 (3.4) 1.3

1. PKI の基礎知識

  • 脅威の種類
    • 盗聴、なりすまし、改ざん、事後否認
    • 事後否認は初耳でした、情報の発信者側から内容が改ざんされていると主張することですね
  • 共通鍵暗号方式
    • 公開鍵暗号方式と比べて高速であるため大量のデータを暗号化するのに向いている
      • これ、ハンドシェイク後のTLSがマスターシークレットで暗号化通信しているところに関わってきますね
    • ブロック暗号方式のDESを3段階組み合わせるトリプルDESというものがある
  • 公開鍵暗号方式(非対称鍵暗号方式)
    • 暗号用の鍵を公開できるので共通鍵暗号に比べて鍵の管理が簡単となる *1
  • RSA(1978)
    • 十分に大きな数の素因数分解の困難性を利用した公開鍵暗号方式
    • 公開鍵で暗号化し秘密鍵で復号化すると秘密鍵保持側への一方向の機密通信が行える
    • 逆に秘密鍵で暗号化し公開鍵で復号化することもでき、電子署名に利用される
      • つまり「秘密鍵を保持した情報発信者側だけが作成でき得るデータ」を作成できる
  • その他の暗号方式・署名方式
    • DH(1976): 鍵交換の鍵配送方式
    • DSH(Digital Signature Algorithm): 離散対数問題の困難性を利用した署名方式
    • 楕円暗号(DCDSA): 楕円曲線状の離散対数問題を利用した公開鍵暗号方式
      • 一部の楕円曲線暗号には攻撃法が存在しているため適切なパラメータが必要 *2
  • 一方向性ハッシュアルゴリズム
    • SHA-1(Secure Hash Standard の Update One, 1995): 160bit のハッシュを生成する
    • MD5(Message Digest 5, 1991): 128bit のハッシュを生成する
    • ここでハッシュアルゴリズムが説明されるのは次の完全性保証で利用されるためですね
  • メッセージ認証(完全性保証)
    • 以下のMICとHMACは秘密情報と一方向ハッシュを利用したもの*3
    • MIC(Message Integrity Checksum)
    • HMAC(Keyed-Hashing for Message Authentication)
  • デジタル署名(完全性保証)
  • 相手認証
    • 秘密鍵を必ず本人が持つという前提を利用すると相手認証にも利用可能 *4
    • 秘密鍵で署名し、公開鍵で検証」という完全性の検証は悪意のある第三者が作成した鍵ペアでも行える(なりすまし)
    • なりすましを防ぐには公開鍵の所属情報を証明する何らかの仕組みが必要になり、それがTTPやCAを利用した仕組みである *5
    • 用語
      • TTP(Trusted Third Party, 信頼できる第三者): 鍵利用者に対し信頼され、かつ秘密鍵を保持しているということを公開鍵に署名し証明する
      • CA(Certificate Authority): TTPのひとつ
      • 証明書: 公開鍵に(主にCAの秘密鍵で)署名がなされたもの
  • 鍵配送

2. 公開鍵基盤

  • PKIの要素と役割
    • 認証局: CA(Certification Authority)
      • 鍵ペアの所持者に対し公開鍵証明書を発行する
    • 登録局: RA(Registration Authority)
      • 公開鍵証明書を発行する所持者の資格審査を行う
      • RAの機能をCAが担うこともある
    • ディレクト
      • 公開鍵証明書を保管・開示する手段
    • 公開鍵証明書
    • 失効リスト: CRL(Certification Revocation List)
    • 証明書有効性検証機関: VA(Validation Authority)
    • 証明書利用者: End Entity
      • 個人やサーバアプリケーションなど

3. 公開鍵証明書と失効リスト(CRL)

読み進め次第追記するつもりです... ˘ω˘

*1:つまり共通鍵暗号公開鍵暗号には「計算量」と「鍵の管理の手間」の間にトレードオフがあると考えられるのでしょうか

*2:「離散対数問題」が利用されている手法が多いので掘り進めてみたいですね。他に ElGamal の方式もその応用例として挙げられていました。

*3:完全性の検証はどう行うのか、秘密情報を共有していること前提か。つまり「メッセージ認証は共通鍵的なものでデジタル署名は公開鍵暗号方式を利用したもの」という認識でいいのでしょうか。

*4:つまり秘密鍵の漏洩はこの前提を覆し、その「本人」に対する相手認証が全て機能しなくなるということになりそう。

*5:この信頼できる第三者の存在を前提とした「信頼モデル」と呼べるものは初見ではどこか情報工学っぽくない感じもしますが、実際の社会の「信頼」という概念も結局はこんなところなのでしょうね。現実世界の反映と考えると次第に慣れていきます。

Protocol Buffer と gRPC を Go で使うときのリポジトリを整理する

(=˘ ꒳ ˘=) googlegolang がぱっと見ややこしい...

Protocol Buffer と gRPC を Go で利用しようとすると色んなリポジトリからツールを落としてくる必要がありますがどれも微妙に字面が似ているので混乱します。それらを整理するために org/repo の形式で一覧できるようにまとめていきたいと思います。

まず Protocol Buffer のコアなツールが含まれるリポジトリ

  • google/protobuf
    • C++ 製の Protocol Buffer のコア
    • 含まれるツール: protoc
    • 日付型などの well-known 型の .proto 定義も含まれる

ですね。Go の場合はこれに加えて Protocol Buffer と gRPC の Go 実装のためのパッケージが必要になります。 .proto 定義からコードを生成したり、そのコードから import されるパッケージが以下のリポジトリに含まれます。

C++PHPなど Go 以外の言語だと grpc のメインのリポジトリでその辺が間に合ってしまいそうです。

上に書いた通り grpc_cli は便利なので Go でもこのリポジトリの一部機能は利用する、という感じです。

...ややこしいですね。

まだ書き出しただけで、プラグインやら well-known 型の定義や実装がどこにあるかやらが整理できているとは言い難いですが、使っているうちに慣れるのでしょうか...

gRPC で日付型を利用する

(=˘ ꒳ ˘=) gRPC の import 周りを整理したい...

という記事で go-proto-validators と grpc_cli をうまく組み合わせられないことに対して試行錯誤してました。

その問題の切り分けがてら、今回はもう少し基本的な日付型の利用を通して gRPC の import 周りを整理していきたいと思います。

hello.proto をベースに日付型をレスポンスのタイムスタンプとして追加しています。

syntax = "proto3";
package hello;

import "google/protobuf/timestamp.proto";

service GreetingService {
  rpc Hello(GreetingRequest) returns (GreetingResponse);
}

message GreetingRequest {
  string name = 1;
}

message GreetingResponse {
  string message = 1;
  google.protobuf.Timestamp date = 2;
}

注意点としては Timestamp ではなくて google.protobuf.Timestamp と指定するところくらいです。

サーバ側の実装は今回も Go で、日付型の変換に https://godoc.org/github.com/golang/protobuf/ptypes#TimestampProto を利用しています。 Go の time パッケージの日付型はそのままだと gRPC 用に吐き出されたコードには利用できません。

詳しい実装は冒頭のコミットのリンクをご参照ください。

で、リフレクションサービスは組み込み済みで肝心の grpc_cli の動作確認ですが...

$ grpc ls -l localhost:10000
filename: grpc_reflection_v1alpha/reflection.proto
package: grpc.reflection.v1alpha;
service ServerReflection {
  rpc ServerReflectionInfo(stream grpc.reflection.v1alpha.ServerReflectionRequest) returns (stream grpc.reflection.v1alpha.ServerReflectionResponse) {}
}

filename: api/hello.proto
package: hello;
service GreetingService {
  rpc Hello(hello.GreetingRequest) returns (hello.GreetingResponse) {}
}

$ grpc call localhost:10000 Hello "name: 'asa-taka'"
connecting to localhost:10000
message: "Hello, asa-taka."
date {
  seconds: 1527964860
  nanos: 432266000
}

Rpc succeeded with OK status

なんか普通に動いてしまって拍子抜けです。

import パス周り、意外と単純なのか根が深いのか... gRPC と Protocol Buffer 難しい...

gRPC で go-proto-validators を .proto に import したら grpc_cli がうまく使えない

(=˘ ꒳ ˘=) 最近 gRPC を始めたけどパス解決周りが Protocol Buffer 層も相まって複雑で混乱する...

hello.proto に簡単なバリデーションを組み込んで Go で吐き出して grpc_cli で動作確認しようとしたらハマって、そしてそのまま解決していない件になります。バリデーション処理ではなく主に Protocol Buffer の import 周りの試行錯誤のお話になります。

素朴に go-proto-validators を import したところ...

今回対象にする hello.proto は以下のようなものです。 go-proto-validators/validator.protoimport しています。

syntax = "proto3";
package hello;

import "github.com/mwitkow/go-proto-validators/validator.proto";

service GreetingService {
  rpc Hello(GreetingRequest) returns (GreetingResponse);
}

message GreetingRequest {
  string name = 1 [(validator.field) = {string_not_empty: true}];
}

message GreetingResponse {
  string message = 1 [(validator.field) = {string_not_empty: true}];
}

これを protoc して Go ライブラリを吐き出してサーバを実装して grpc_cli で叩いたところ、症状としては以下のようになりました。

  • grpc_cli ls は動く
  • grpc_cli ls -l は動かない
  • grpc_cli call ... も動かない
$ grpc_cli ls localhost:10000
grpc.reflection.v1alpha.ServerReflection
hello.GreetingService

$ grpc_cli ls -l localhost:10000
[libprotobuf ERROR google/protobuf/descriptor.cc:3592] Invalid proto descriptor for file "api/hello.proto":
[libprotobuf ERROR google/protobuf/descriptor.cc:3595]   api/hello.proto: Import "github.com/mwitkow/go-proto-validators/validator.proto" was not found or had errors.
filename: grpc_reflection_v1alpha/reflection.proto
package: grpc.reflection.v1alpha;
service ServerReflection {
  rpc ServerReflectionInfo(stream grpc.reflection.v1alpha.ServerReflectionRequest) returns (stream grpc.reflection.v1alpha.ServerReflectionResponse) {}
}

$ grpc_cli call localhost:10000 Hello "name: 'test'"
[libprotobuf ERROR google/protobuf/descriptor.cc:3592] Invalid proto descriptor for file "api/hello.proto":
[libprotobuf ERROR google/protobuf/descriptor.cc:3595]   api/hello.proto: Import "github.com/mwitkow/go-proto-validators/validator.proto" was not found or had errors.
Method name not found

どれも github.com/mwitkow/go-proto-validators/validator.proto が見つからないと言われていますね。

gRPC や Protocol Buffer 周りのパス解決をよく理解しておらず、さらにリフレクション経由というローカルとはいえネットワークを噛ませたパス解決がどうなるかも相まって二重三重で混乱します。

とりあえずリフレクションを無効化して試行錯誤する

問題を簡略化したいので、とりあえずリフレクションはコメントアウトして grcp_cli --protofile を直接指定するやり方で実行してみます。

https://github.com/grpc/grpc/blob/master/doc/command_line_tool.md#call-a-remote-method の「User local proto file」のやり方です。

grpc_cli にも --proto_path を指定できるみたいですが protoc のように複数指定してもうまく行かず、結局 .proto のパスを同一起点から解決できればいいんだろうということで、プロジェクトルートから依存パッケージを辿れるような symlink を張ったら動くことには動きました。

$ echo $GOPATH
/Users/asa-taka

$ pwd
/Users/asa-taka/src/github.com/asa-taka/hello-validated-grpc

$ tree
.
├── Makefile
├── api
│   ├── hello.pb.go
│   ├── hello.proto
│   └── hello.validator.pb.go
├── github.com -> /Users/asa-taka/src/github.com/
├── google -> /Users/asa-taka/src/github.com/google/protobuf/src/google
└── server.go

$ grpc call localhost:10000 Hello "name: 'test'" --protofiles=api/hello.proto connecting to localhost:10000
message: "Hello, test."

Rpc succeeded with OK status

流石に不便なのでもっといい方法が用意されているか、何かしら自分が間違えているのを期待しています。

一応どの symlink を張ったか解説しておくと

ちなみに grpc_cli ls は動作しませんでした。リフレクション専用のコマンドみたいですね。

$ grpc ls -l localhost:10000 --protofiles=api/hello.proto
Received an error when querying services endpoint.

この状態からリフレクションのコメントアウトを外してみます。初めの状態と特に症状は変わりませんでした。依然として github.com/mwitkow/go-proto-validators/validator.proto が見つからないと言われています。

$ grpc ls localhost:10000
grpc.reflection.v1alpha.ServerReflection
hello.GreetingService

$ grpc ls -l localhost:10000
[libprotobuf ERROR google/protobuf/descriptor.cc:3592] Invalid proto descriptor for file "api/hello.proto":
[libprotobuf ERROR google/protobuf/descriptor.cc:3595]   api/hello.proto: Import "github.com/mwitkow/go-proto-validators/validator.proto" was not found or had errors.
filename: grpc_reflection_v1alpha/reflection.proto
package: grpc.reflection.v1alpha;
service ServerReflection {
  rpc ServerReflectionInfo(stream grpc.reflection.v1alpha.ServerReflectionRequest) returns (stream grpc.reflection.v1alpha.ServerReflectionResponse) {}
}

$ grpc call localhost:10000 Hello "name: 'test'"
[libprotobuf ERROR google/protobuf/descriptor.cc:3592] Invalid proto descriptor for file "api/hello.proto":
[libprotobuf ERROR google/protobuf/descriptor.cc:3595]   api/hello.proto: Import "github.com/mwitkow/go-proto-validators/validator.proto" was not found or had errors.
Method name not found

苦し紛れに --proto_path=. を指定してみても改善せず。

$ grpc ls -l localhost:10000 --proto_path=.
[libprotobuf ERROR google/protobuf/descriptor.cc:3592] Invalid proto descriptor for file "api/hello.proto":
[libprotobuf ERROR google/protobuf/descriptor.cc:3595]   api/hello.proto: Import "github.com/mwitkow/go-proto-validators/validator.proto" was not found or had errors.
filename: grpc_reflection_v1alpha/reflection.proto
package: grpc.reflection.v1alpha;
service ServerReflection {
  rpc ServerReflectionInfo(stream grpc.reflection.v1alpha.ServerReflectionRequest) returns (stream grpc.reflection.v1alpha.ServerReflectionResponse) {}
}

$ grpc call localhost:10000 Hello "name: 'test'" --proto_path=.
[libprotobuf ERROR google/protobuf/descriptor.cc:3592] Invalid proto descriptor for file "api/hello.proto":
[libprotobuf ERROR google/protobuf/descriptor.cc:3595]   api/hello.proto: Import "github.com/mwitkow/go-proto-validators/validator.proto" was not found or had errors.
Method name not found

リフレクションサービスは動いているけれど、import が解決できず GreetingService は動かないという...

リフレクション経由で .proto の import を解決する方法ってないんでしょうか。今のところ symlink を張るくらいの解決策しか見つかっておらず、このままだとちょっと不便なんですよね...何かあるはず、というかみんなどうやってるのか...

Issue を漁ってみる...

コマンドのヘルプもドキュメントもあまり充実してはいないので、諦めて Issue を辿っていきます。

ざっと見たところ google.protobuf.Timestamp というよく使われる type/message を使った時も面倒なことになっているらしいですが、詳しいことは読み取る気力がわきませんでした。こちらの方が事象としてはよりシンプルな気もするので、こちら側から攻めてみてもいいかもしれませんね。どうせ日付型も使うことになるでしょうし。

...で、別記事で日付型の import を試してみたところ普通に動いてしまったというわけで、本件に関しては継続して探っていきたいと思います...

それにしても Issue を辿っていると protobuf と grpc と grpc-go をたらい回しになって、なんか、その、疲れます...

GraphQL のため息

GraphQL とは一体何だったのか、半年ほど触れ続けていまだ掴みあぐねています。

やりたいことは分かる、が、どこに使えばいいのかわからない。

サービスに導入するとして、GraphQL で実装したい場所が見つからない。

夢は見せてくれたが、壮大な社会実験だった気がしなくはない、そんな不安。

GraphQL は夢だけ見せて立ち去っていった。

いや、距離をとったのは自分の方だったのだけれど。

とりあえず、しばらくは別の何かを追いかけてみたい。