【第2回】TypeScriptもウェブも仕様や原理から楽しむ
2022年4月に著書『プロを目指す人のためのTypeScript入門』が発売された鈴木僚太さん(https://twitter.com/uhyo_)。QiitaやTwitterでは「うひょ(uhyo)」さんとして、TypeScriptやフロントエンドの話題を中心にウェブ技術に対する踏み込んだ解説でも知られています。
著書ではあえて触れられなかったという「TypeScriptでウェブアプリケーションをどう書くか」という観点へのヒント、なぜそれを書かなかったのか、そして仕様や原理に立ち返って自ら考えることの楽しさについて、株式会社一休CTOの伊藤直也さん(https://twitter.com/naoya_ito)が聞き出します。
目次
・伊藤 直也さん / 株式会社 一休 執行役員 CTO
新卒入社したニフティ株式会社でブログサービス「ココログ」を立ち上げ、CTOを務めた株式会社はてなでは「はてなブックマーク」などの開発を主導。グリー株式会社では統括部長としてSNSを担当した。2016年4月、一休に入社し執行役員CTOに就任。
・鈴木僚太(uhyo)さん / 株式会社バベル プリンシパルエンジニア
東京大学大学院情報理工学系研究科を修士で卒業後、新卒でLINE株式会社に入社。LINE証券のフロントエンド開発を担当。2018年からECMAScript・TypeScript・Reactを中心としたフロントエンド領域で活動。
『プロを目指す人のためのTypeScript入門』(技術評論社、2022)著者。
Twitter:@uhyo_
学園祭のシステムがTypeScriptとの出会い
伊藤さん:uhyoさんといえば、「ブルーベリー本」の愛称で親しまれている『プロを目指す人のためのTypeScript入門』の執筆者です。
私はTypeScriptを始めたとき、少し難しく感じていたのですが、この本のおかげで「なるほどそういうことか」と納得できた面が多々ありました。
なので、今日はこのブルーベリー本やTypeScriptについてuhyoさんにいろいろ聞けるとうれしいです。
そもそもuhyoさんがTypeScriptを使い始めたきっかけは何だったのでしょうか?
uhyoさん:大学の学園祭の実行委員会に入っていて、そのときに出店申請システムを作るのに使ったのが最初でした。
500くらいの団体から「食べ物を売りたい」といった出店に関する申請をしてもらう必要があって、紙で提出してもらっている大学が多かったと思うんですが、うちの大学では昔からWebサイトで申請できるようにしていたんです。
伊藤さん:学園祭で実行委員をやるような学生だったというのは、昨今のuhyoさんからは少し想像がつかないですね。それは何年くらい前の話ですか?
uhyoさん:10年前です。大学1年生とか2年生のときなので、2013年とか2014年ごろですね。
伊藤さん:そのころだと、TypeScriptが今のようにデファクトになるよりもずっと前ですよね。
uhyoさん:はい、TypeScriptの最初のリリースが2012年10月とかなので、出てすぐくらい。
伊藤さん:界隈ではまだCoffeeScriptを書いていたような頃ですね。
uhyoさん:私もちょうどCoffeeScriptからTypeScriptに乗り換えたころでした。
伊藤さん:そういえばuhyoさんは、CoffeeScriptで人狼サーバを開発されていましたね。
uhyoさん:はい、あれの最初のリリースが2011年です。
何万行っていうCoffeeScriptで、今となっては正の遺産なのか負の遺産なのかわからないんですけど、今でもたまにCoffeeScriptを書いてアップデートかけてます。
伊藤さん:そんな時代に、登場して間もないTypeScriptを学園祭向けの出店申請システムで使おうと思ったわけですか。
uhyoさん:もともと学園祭では、Pythonで書かれたシステムが使われていたんです。
でも、自分はその前に何年もJavaScriptを書いていたのでNode.jsで新しく書き直そうと思い、それでTypeScriptを選んだのでした。
伊藤さん:大学1年の時点でJavaScript歴が何年もあるというと、いったいプログラミングを始めたのはいつだったんでしょうか?
uhyoさん:10才のときなので、2005年ですね。
最初はHTMLを書いてJavaScriptを添えるといったところから入りました。
そのうちサーバーにデータを保存したくなったので、PerlでCGIのプログラムを書いたりもしていました。
伊藤さん:10才! かなり早いですね。
そして2005年というと、私がはてなブックマークを作っていたころなので、まさにPerlが全盛だった時代ですね…。
バックエンドの業務もTypeScriptで
伊藤さん:uhyoさんはTypeScriptを仕事でも使われているんですよね。
uhyoさん:はい、新卒で入ったLINEではフロントエンドエンジニアだったので、そこでTypeScriptとかReactを使っていました。
2022年10月に転職して、いまは株式会社バベルにいますが、ここでもTypeScriptを使っています。
ただ、バベルではLINEのときと違い、サーバーサイドばっかり触っています。
伊藤さん:バベルさんはバックエンドもTypeScriptなんですね。
もしかして、バックエンドもTypeScriptだったのがバベルさんに転職された理由だったりするんでしょうか?
uhyoさん:そういうわけでもなくて、私としては「フロントエンドが得意です」という触れ込みで入ったら、たまたまバックエンドもTypeScriptだったという感じです。
会社としても、特定の言語に詳しいかどうかよりは、設計力のような部分を見込んでくれたようです。
とはいえ、私の経歴などから「TypeScriptが得意なんだろうな」と知っていたとは思いますし、その意味ではバックエンドに対してもある程度の期待はあったと思います。
実際、入社して数週間はサーバーサイドばっかり触っていました。
結局、短期的な問題解決はサーバーサイドのほうがクリティカルになることが多いんですよね。
伊藤さん:お仕事ではバリバリにフロントエンドをやっていると思っていたので、意外です。
uhyoさん:今の会社のチーム構成としても、本当のフロントエンド部分、つまりReactについては自分以外にもできる方がいるので、私はがっつりやらなくても済むんですよね。
一方、GraphQLのバックエンドはまだまだ発展途上と言いますか…。
伊藤さん:GraphQLなんですね。
uhyoさん:はい。フロントエンドとの疎通にはGraphQLを使っています。
LINEでは基本的にREST APIだったのでGraphQLを仕事で使ったことはなく、副業でフロントエンド側をちょっと触ったことがある程度だったんですが、今ではフロントエンドとサーバーサイドの両側でGraphQLを扱うことになっています。
「プロダクションではこういうふうにGraphQLを使うのか」という感じで、だんだん慣れていっているところです。
伊藤さん:REST APIと違うと感じるところはありますか?
uhyoさん:今のところ、そこまで違う感じはありません。
が、それは実は我々のチームのGraphQLの使い方がまだあまり良くないという理由もあると思っています。
具体的には、GraphQLを「スキーマを扱いやすいREST API」みたいな感じでしか使えていないんですよね。
1画面=1リゾルバという状況で、あんまりリゾルバをネストさせない設計になっているので、「Graph」といえるような要素があまりないというか。
伊藤さん:そっちが整わないと、GraphQLを使っている利点があまり得られなそうですものね。
1ユースケース=1リゾルバだと、言ってみれば「ステータスコードが全部200で返ってくるREST API」みたいなものなので、かえって使いづらいかもしれない。
uhyoさん:そうですね、今のところあまりGraphQLの利点は出せていないんですよ、悲しいことに。
意図してそうなっているわけではないと思うので、これからもうちょっとGraphQLらしい設計にしていきたいと考えています。
ただ、コードの自動生成とかは現状でもけっこう頑張れていると思います。
以前、REST APIでやろうとしたときは、スキーマの管理がすごく大変で諦めたことがあるので。
伊藤さん:そうすると、しばらくはバックエンド開発をやることになりそうですね。
uhyo:はい。もうちょっとログも整備しないといけないですし、その辺りでやることが多そうです。
アンダースさんが面白かった
伊藤さん:学園祭の実行委員のシステム開発でTypeScriptを使い始めた、とのことですが、uhyoさんは大学の研究でもコンピュータサイエンスをされていたんですよね。
uhyoさん:はい、大学の研究では静的解析をやっていました。いわゆる形式手法の基礎になるものです。
コードの安全性なんかを、コードを動かして確かめるテストとは対照的に、コードを動かさずに検証したり保証したりしようという分野です。
伊藤さん:TypeScriptの「型」も、まさにそういう話ですね。
uhyoさん:はい。研究レベルだともう少しややこしい話もあるのですが、型システムは広く普及した形式手法のひとつですね。
伊藤さん:そうした研究では、OCamlやHaskellのようなプログラミング言語を使うことが多いと思うんですが、同じ静的型付き言語とはいえ、TypeScriptはそれらとだいぶ感覚が違いますよね。
それこそ型システムとしても、OCamlとかHaskellで採用されているもののほうが理論的にもかっちりしていると思います。いまだとRustなどもそっちよりの言語ですよね。
uhyoさん:そうですね。Rustについては大学生のときに興味をもって、研究で使うOCamlのプログラムを移植してみたりしたことはありました。
それでも、静的型付き言語をきちんと勉強したのは何だったかというと、やっぱりTypeScriptだったと思います。
伊藤さん:そこが面白いところですね。
研究でより厳格な型システムを持つ言語を使うようになっても、学園祭という一種の課外活動で使い始めたTypeScriptへの関心を持ち続けて、ついには本を執筆するほどまでになってしまったわけですよね。
ブラウザで動くという実用性が前提にあるJavaScriptがベースにある以上、TypeScriptはどうしても実用指向で設計されている言語だと思うんです。
もっと厳密だったり仕様がコンパクトでシンプルだけど表現力がすごく高かったりする言語よりも、そういう実用指向の言語に魅力を感じる理由は何だったのか、そこにすごく興味があります。
uhyoさん:そう言われると不思議ですね。実はあんまり深い理由はないような気もします。
単純に、もともとJavaScriptに慣れ親しんでいたのと、JavaScriptやTypeScriptは言語として何でもできるから、最初のうちは積極的な理由はなかったんですよね。
特に離れる理由がなかっただけかも。
とはいえ、そのうちTypeScriptにどんどん合理性がある機能や良い意味で変な機能が追加されていったので、今では積極的に推せる言語です。
そういう意味だと、アンダースさんが面白かった、という面がわりと大きいかもしれません。
伊藤さん:アンダースさん?
uhyoさん:はい、アンダース・ヘルスバーグ(Anders Hejlsberg)さん。マイクロソフトでTypeScriptチームのリーダーだった人です。
TypeScriptの特徴的な言語機能って、大体はアンダースさんが考えたものだと言っていいくらいなんですよ。
そのアンダースさんの考え方に魅力を感じたというのが、TypeScriptに興味を持ち続けた理由としては大きいように思います。
伊藤さん:アンダースさんの言語設計に対する考え方は、どこかで読めたりするんでしょうか?
uhyoさん:ご本人が書いたブログとかインタビューみたいなものは、私も知りません。
自分がアンダースさんの考え方を知るのは、TypeScriptに実装された言語機能を見て、そこから逆算というか、「こういう言語機能を作るのか、アンダースさんは」みたいに読み解く感じです。
あと、アンダースさんはPull Requestに機能の説明を丁寧に書いてくれる方なので、その辺りに目を通すことでも彼の考え方がわかります。
伊藤さん:アンダースさんがTypeScriptに入れた特徴的な機能として、特に印象的だったものは何ですか?
uhyoさん:やっぱり、TypeScript 2.8で実装されたConditional Type(条件型)ですかね。
簡単に言うと、型に対して条件分岐を書けるっていう機能。私から見るとアンダースさんの傑作のひとつです。
伊藤さん:なるほど。Conditional Typeを使っていると、確かにシンプルな1つの機能でいろいろなユースケースを書けるので、自分もあれは面白いと感じます。
uhyoさん:ただ、1つの機能にいろいろな考え方が詰め込まれているので、わかりにくくはあるんですよね。
「型に対して条件分岐します」というだけなので、一見すると単純な気がするんですが、その裏がめちゃくちゃ複雑というか。
でも、それにより本当に小さくてプリミティブな機能により多くのユースケースをカバーしてしまうのは、アンダースさんのやり方の特長でもあります。
その辺にすごく魅力を感じます。
ブルーベリー本の執筆には2年かかった
伊藤さん:アンダースさんを追いかけて、ついにはTypeScriptに関する本を執筆するに至るわけですが、この本は技術評論社から刊行されています。
技術評論社では、この本を書く前に、Software Design誌で記事を寄稿されていたんですよね。
uhyoさん:はい。たしか最初はJavaScriptに関する記事を書きました。
伊藤さん:そのJavaScriptの記事は、どういう経緯で書くことになったんですか?
uhyoさん:「Qiitaの記事を見ました」という感じで、雑誌の編集者さんから声がかかりました。
たぶん、JavaScriptについて何か書けそうな人を探されていたのだと思います。
私は当時、JavaScriptの言語仕様に関する記事をQiitaで公開していたので、それが目に留まったのでしょう。
伊藤さん:スカウトされたってことですね。
uhyoさん:そうなりますね。びっくりしました。
伊藤さん:私も雑誌の記事を書くことがあるんですが、最初は知人からの紹介だったんですよ。
RSSの記事を宮川達彦さんが書くことになって、「一人だと大変だから分担しよう」と誘われたんです。
で、それを書いたら「次もお願いします」と依頼がくるようになりました。
当時、自分もブログは書いていたけれど、それを見た雑誌編集者から執筆の依頼がくるなんて思ってもいなかった。
今はQiitaとかZennで一生懸命に記事を書いていると、それが編集者の目に留まって雑誌記事デビューできるかもしれない時代なんですね。さらに紙の本も出せるかもしれない。
uhyoさん:それは本当にそう思います。
雑誌記事の後で同じ編集者さんから「本を書きませんか?」という話になり、こうして本として出版できました。
伊藤さん:ただ、さすがに本が出るまでにはかなり時間はかかっていますよね。
uhyoさん:書き始めたのが2019年末だったので、そこから原稿を書き上げるまでに2年くらいかかっていることになります。
伊藤さん:コンピュータ技術書だと、2年も経つと最初のほうに書いた情報がかなり変わっていたりしますよね。TypeScriptも2年の間にだいぶ仕様が変わっていますが…。
uhyoさん:そうなんですよ。仕様が変わるたびに更新はかけていたんですが、やっぱり微妙に整合性が取れていないところも残っていて…。
伊藤さん:この本、情報量がすごいので、書いている本人でも気付けないような部分がありそうです。
uhyoさん:執筆中の仕様変更への追随で難儀した箇所として覚えているのは、インデックスシグネチャに関するコラムですね。
「インデックスシグネチャは危険だから使うな」という趣旨のことを書いたんですが、TypeScript 4.1でその危険を回避するオプションが追加されたので、コラムの意味がなくなってしまった。
でも書籍の進行がかなり進んでいたので、もうコラムごと削除できるタイミングではなく、仕方がないのでコラムの末尾に「危険だって言ったけどこのオプションを付ければ安全だよ」といった一文を付け足したんです。
かなり無理矢理なところがありました。
プログラムの設計やアーキテクチャは言語と独立には語れない
伊藤さん:ブルーベリー本については、uhyoさんにぜひ聞きたいと思っていたことが1つあるんです。
この本では、仕様や機能については網羅的に解説されている一方、「TypeScriptはこういうスタイルで書くべき」といった話にほとんど言及していませんよね。
それは意図があって言及しなかったのか、それとも気づいたらそうなっていたのか、どちらなんでしょうか?
uhyoさん:ある程度は意図的でした。
というのも、この本には「教科書」という言葉が似合うような本になってほしかったんです。
言語仕様や定義といった部分については綿密に説明していますが、その一方で、表面的な使い方については「仕様や定義をとおして理解する」という読み方ができる本を目指していました。
伊藤さん:やはり意図があったんですね。
uhyoさん:もちろん、「こういう機能はあまり使わないほうが良い」といった説明はしています。
たとえば、「デフォルトエクスポートは避けたほうがよい」とか。
伊藤さん:「anyはあんまり使わないほうが良い」とかもちゃんと書かれていますね。
uhyoさん:はい。そのレベルのことは書いています。
でも、「プログラムをどういう設計にするとよいか」みたいな話は書いていません。
なので、「どういうスタイルで書くべき」といった主張を読み取れないのはもっともだと思います。
伊藤さん:本に書かれているのはイディオムのレイヤーまで、と言うのがよさそうですね。
「interfaceとtypeはどう違うか」みたいな説明はあるけれど、「クラスを使ってオブジェクト指向的に書いたほうが良い」とか、「いや、そうじゃない書き方のほうが良い」とか、そういうことは書いていない。
uhyoさん:普段、そういう話をまったく避けているというわけでもないんですけどね。
ちょこちょこ断片的に発言はしているつもりですが、まだ自分の頭の中でまとまりきっていない部分もあって、本や記事として書けるまでには至っていない感じです。
あと、本になぜ書かなかったのかで言うと、自分がわりと「仕様で何を言っているかは教えるから、それをどう使うのかはそれぞれで考えてほしい」というタイプだからだと思います。
伊藤さん:筋のいい道具は用意するから、あとは道具の使い手に任せる、というスタンスですね。
それこそTypeScriptのスタンスにも近いかもしれない。
uhyoさん:そうですね。最近よく言っているんですが、やっぱりプログラミングで何よりも重要なのは自分で考えることですよね。
スタイルとか設計も、そういうものだと思っています。
伊藤さん:耳が痛いです。
uhyoさん:人それぞれで論点がまったく違うから、まったく同じ結論にはそうそう至らないはずなんですよ。
だからこそ自分で考えてほしい。
それに、「だれそれがこう言っていたから、これは良いものなんだ」を繰り返しているだけだと、まだ誰も言ってない良いものは発見できませんよね。最近、それをすごく感じるんです。
伊藤さん:おっしゃるとおりです。
と言いつつも、まさに自分がそうなんですが、「自分で考えた最強のアーキテクチャ」みたいなものを振り回して総スカンを喰らうという経験を何度かした結果、「世の中のトレンドとかデファクトを知ったうえで行動しなければ」という戒めのようなものを持っているエンジニアも少なくないと思うんですよね。
だから、新しい言語を使い始めるときなんかには、どうしても「みんなはどう言っているんだろう」も気になってしまう…。
uhyoさん:ベストプラクティスが知りたいみたいなのはあるかもしれません。
とはいえ、Reactなんかを触っていて感じるんですが、最近はベストプラクティスもころころ変わりますし。
伊藤さん:Reactについては、まだ大きな変更が入ることもよくありますね。少し前はフックの導入、比較的最近ではSuspenseなどプログラム設計に影響を与える変更が入ったのが印象的です。
そういう新しいものをどう使っていくのがベストなのか、世の中の人たちの解釈が気になったりしますね。
さらに、たとえばRustやTypeScriptなどの新しい言語が普及した結果として、「特性の違う言語を使うならアプリケーションの書き方のスタイルも従来とは違うほうがよいかもしれない」といった議論もあると思っているんです。
たとえば、Ruby on Railsが登場してRubyが普及した当時も、「その前のJavaがスタンダードだった時代に広まったGoFのデザインパターンの一部は動的型付き言語では不要になる」といった話がけっこうありました。
つまり、プログラミング言語の持つ特性が何かしらその開発手法に影響を与えるということではないかと思います。
それとも、一般には「プログラム設計は特定の言語機能に依存しないものだ」という認識のほうが強いのかな。もしかしたら、プログラミング言語の表現力と設計みたいなものは独立だと思われているかもしれない。
けれど、実はそうではなくて、言語の持つ性格とか性質によってそれまで必要とされていたものが不要になるっていう傾向は少なからずあると思うんですよ。
uhyoさん:私もまさにそういうふうに思っています。プログラムの設計というのは、その言語にどういう言語機能があるかといった観点を前提にすべきかと。
伊藤さん:よかった。
虎の威を借る狐みたいだけど、uhyoさんもそう言っているなら、やっぱりそうなんだろう。
こういうことを識者の人に聞いてみたい、確認したいという心情は少なからずありますね。
TypeScriptのunion型をもっと使いこなしてほしい
伊藤さん:とはいえ話をTypeScriptに絞ると、uhyoさんが実際に仕事でTypeScriptを書くときのスタイルみたいなものは何かしらありますよね。
TypeScriptを使うのだから、この機能をうまく活用したい、みたいな。
uhyoさん:それに関しては、やっぱりunion型ですね。
伊藤さん:やっぱりそうなんですね。
自分も最近、ブルーベリー本を読んだり、実際にバックエンド開発でTypeScriptを使っていたりしていて「TypeScriptを使うならunion型を意識的に使うのが重要だな」と感じていたところでした。
uhyoさん:一方では、まだunion型をあまり使わずにTypeScriptを書いている人も多いと思うんです。
実際、コードレビューとかでも、「ここ、union型にできるよ」と言うことがけっこうあります。
伊藤さん:そうですね。普段からunion型を使っている人と、まだunion型を使うことに慣れていない人と、現状ではけっこうギャップがありますよね。
union型を使うことを念頭にアプリケーションを書いていると、そうでない人のコードレビューをするときに、たくさん指摘する必要がある。
uhyoさん:個人的には、これもまさにプログラミング言語の表現力が上がったって話と表裏一体なんだろうと考えています。
TypeScriptのunion型は「or」を表現できるんですよね。「または」という意味のロジック。
アプリケーションロジックでもドメインロジックでも、「または」という処理をデータとして表したい状況は発生すると思っていて、GoFのデザインパターンでも疑似的にそういうのがあるわけですが、これを型で表現できるのは本当に大きいです。
最近だとJavaにもSealedクラスとかがありますが…。
伊藤さん:そうですね、今のJavaとかKotlinにあるSealedクラスでも「or」を表現できますね。SwiftやRustのenumもそうです。
最近の新しい言語には「or」を表現できる機能が追加されてきている。
逆に言うと、昔自分たちが使っていた言語には、そういう機能がなかったってことでもあるんですよね。
uhyoさん:はい。典型的なのは、「外部からデータを取得する」という処理を書くときにデータとステータスを両方管理する必要がある、みたいな状況ですね。
取得が終わったらデータが存在してステータスは「done」とかでいいとして、じゃあローディング中のステータスのときデータは何にすればいいんだろう、と。
伊藤さん:unionが使えないと、そこにnullが入ってきてしまう。
uhyoさん:でも、そもそもローディング中にはデータっていう概念がいらないはずなんですよ。
「データ」と「ステータス」の2つの情報を並列にして扱う必要はなくて、「データがない状態」と「データがある状態」を表現できればいい。
それを的確に表現するには、union型のような機能があればいいわけです。
伊藤さん:まさにそういう考えなんですよね。
「ローディング中はnull」のような扱いは基本的に不要なはず。
そもそもnullには触りたくなくて、nullチェックもしないと危なくなるんだから、最初からnullを使わずに済むほうがいい。
値がない状態と値がある状態とを「or」で繋げて表現できる機能があれば、それが一番という。
uhyoさん:そういうふうに、とにかく余計な情報を持たないで済むようにできるのが、TypeScriptにunion型があることの利点ですよね。
TypeScriptに限らないんですが、コードで必要最低限のものだけを表現しようとしたら、union型のような機能がないと無理なんじゃないかなと、そんなふうに思います。
伊藤さん:実際、コードレビューなんかでも、「複数のパラメーターを受け取る関数を書いたときに、どれか1つをnullにしたい」みたいな状況で「そこはnullじゃなくてunion型で定義すればもっと堅牢になるよ」というケースが多いです。
でも、union型って、そこだけを切り取るとシンプルな話ですよね。
たとえば、「それまでPromiseに包むしかなかった非同期処理を、async/awaitによってJavaScriptでも手続き的に書けるようになりました」といった話などに比べると、すごく単純な変化だと思うんです。
一見、プログラミングスタイルを大きく変えるほどの話でもないように聞こえる。
実際、私も当初からunion型は確かに便利だなと感じていたけれど、そこまで自分のアプリケーション設計に大きな影響を与えるとは思っていなかったんですよね。
こういう認識が世の中でどれくらい共通になっているのかが、肌感覚としてよくわからない。
実はもう、みんな当たり前のようにやっているのかな。
uhyoさん:共通認識までにはなっていないと思います。
とはいえ、これはRustで顕著なんですが、そういう考え方もすでに広まりつつあるとは感じています。
と言うのも、union型のような仕組みですべての可能性をちゃんと定義するという書き方をしていると、いわゆるインターフェースの必要性がなくなっていくんですよ。
インターフェースは、いろんな可能性を抽象化する仕組みですが、可能性は無限になっちゃうことがある。
一方、Rustにはインターフェースがなく、抽象化の裏にある具体的な可能性が何個あるかをあまり隠さない言語設計だと言えます。
そのRustがすでにこれだけ受け入れられているのだから、そういう考え方も段々と広まってきてはいるのだろうなと。
伊藤さん:実際TypeScriptでも、union型を積極的に使うというスタイルでアプリケーションを書いていくと、それこそクラスを使う頻度が減っていきますね。
uhyoさん:私もクラスをあまり使いません。
クラスならではのいいところは、インターフェースを実装できる、継承できるといったところですからね。
伊藤さん:やはりそうなんですね。
これがライブラリを書く場合なら「インターフェースを同じ名前で呼びたい」みたいな場面もありそうだけど、そうじゃない場面では、私の場合、クラスをベースにした設計をほぼしなくなってしまった。
むしろオブジェクト指向のようにクラスにメソッド追加していく書き方だと、union型にするときにメソッドが一緒についてきちゃって、それで型が合わなくなったりする。
uhyoさん:それもありますね。TypeScriptのような言語で、データに振る舞いを持たせるために「オブジェクトにメソッドを生やす」と、union型によるやり方とは相性が悪いですね。
伊藤さん:結果としてクラスをあまり使わなくなってしまった。クラスを忌み嫌うようになったとかじゃないんですけど。
uhyoさん:クラスが便利な場面もありますからね。
たとえば、内部に状態を持つオブジェクトが書きやすいっていう話はあると思っています。この場合は外にはunion型が出ないですし。
伊藤さん:あとクラスが必要になりそうなのは、ポリモーフィズムを実現したいときですね。
uhyoさん:それはたしかにそうですね。
カリー=ハワード同型対応を意識すればコードの書き方も変わる
伊藤さん:TypeScriptを使うときのスタイルについてブルーベリー本には書かれていない、という話から始まって、そうはいってもuhyoさんはunion型を活用する書き方をしているし、でも一方でTypeScript自体はクラスに基づく従来のオブジェクト指向のスタイルでのプログラミングにも対応できるという話まで伺ってきました。
もしかすると、いくつものスタイルが選択可能なことは、チーム開発においてTypeScriptの欠点と感じる人もいるかもしれませんね。
uhyoさん:なるほど?
伊藤さん:自分とuhyoさんは、union型を多用した、型を中心に据えたアプリケーション実装を考えているし、トレンドとしてもそこに収斂しつつある気がしているんです。
でも、たくさんの人で一緒に開発をしようとなったら、クラス指向のオブジェクト指向で書きたい人はいるだろうし、手続き型で書くべきだという人もいますよね。
union型を多用する書き方は、どちらかというと関数プログラミングっぽいですが、一口に関数プログラミングって言ってもそれこそ多様で、大小様々なスタイルがありうる。
じゃあチームで開発するときにどこに着地させるのか、という部分が、TypeScriptという言語からは定まりづらいのかなと。
uhyoさん:そうですね。
ただ、そこはやはり「こういうふうに書くと良いんだよ」と本で明言するというよりは、仕様みたいなもっと原理的なことを知ってもらって、そこから使う目的に応じて考えてほしいなと。
伊藤さん:uhyoさんが以前、「TypeScriptをうまく書くには」という文脈で 「高階関数とかそう言うテクニックよりもカリーハワード同型について理解すれば上手になると思う」とTwitterでつぶやかれていたのを見ましたが、その辺の発言にもある意味で一貫したものを感じます。
カリー=ハワード同型対応って、TypeScriptとかHaskellのプログラムに出てくるような「型」が論理学における「命題」に対応している話ですよね。
それこそコーディングなんかよりずっと原理的な話なわけですが、それがどうしてTypeScriptをうまく書くことにつなげるのか、もう少しかみ砕いて説明してもらえるとうれしいです。
uhyoさん:はい。カリー=ハワード同型対応っていうのは、まさに今おっしゃられたとおり、
プログラムの世界における型は論理学における命題であり、さらにいうとプログラムは証明であるという対応関係のことです。
そういう「プログラムは証明なんだ」っていう理解があると、たとえば「Bという型の値を得たい。いま、A to Bっていう型の関数がある。それならAっていう型のデータをプログラマは用意すればよい」という感じで、目的から型に合わせた関数を使っていくような書き方になっていくと思うんです。
関数を、「パイプライン的な処理をするコード」としてでなく、「欲しいデータを得るための装置」として使うっていう考え方。
そういう書き方ができると、TypeScriptもうまく使ってもらえるようになるのではないかなと。
伊藤さん:確かに、型をきっちり詰めて書くと、型が合ってコンパイルが通るだけでプログラムとして動くみたいな体験をしますよね。
型がなかったり、厳密でない言語でプログラムを書くときは、実際に画面で動かしてみたり、ユニットテストを書いてみたりしないと、「プログラムがちゃんと動くかどうか」に確信を持てなかった。
理屈としてカリー=ハワード同型対応として論理との対応があり、その上で型システムとして言語にそれが機能として内包されていて…、という背景に意識的かどうかで、コードの書き方は変わりそうです。
uhyoさん:そうすると、それこそ「union型を積極的に使っていこう」と気づいてもらえるとも思うんですよ。
伊藤さん:union型を使わないと、より広い値を受け入れる型を何か用意しなきゃいけなくなって、その型で関数を定義してしまうと関数自体の型が緩くなって厳密性をそぐ、みたいな感じですかね。
実際、union型を意識して設計すればするほど、アプリケーションが堅牢になっていくのは感じています。
もはや「あれ、今までこれがなかったとき、どう書いてたっけ?」みたいな感じになっています。
さらに、TypeScriptの制御フロー解析の機能と合わせると、if文で型が合う可能性だけを残して定義するといったこともできる。
あれはなんか、プログラミング言語に対してプログラミングしているみたいな不思議な感覚に陥りますよね。
uhyoさん:はい。カリー=ハワード同型対応で論理の世界に持って行くと、union型は「論理和」、
つまり「または」に対応するわけです。
「または」という概念そのものは身近だと思うので、むしろ型で考えるよりわかりやすくなりますよね。
伊藤さん:なるほど。めちゃくちゃ面白いですね。
この話は、すごく大事な話だと私は思います。
だからこそというか、そういうプログラミングスタイルに言及しないのが不思議で、uhyoさんに今みたいな話を通して「TypeScriptはこう書くのが良い」と言ってもらいたいですね。
仕様を楽しむ
uhyoさん:その辺りをどう伝えるかとなると、やっぱり言語をこえた私の考え方として、「そもそもプログラミング言語を使う以上はちゃんと仕様を知ろうぜ」という話に戻りますね。
私も、TypeScript以前にJavaScriptのころからけっこう仕様を読み込んでいましたし。
伊藤さん:それはつまり、ECMAScriptが基本的にひと通り頭に入っているということですか?
uhyoさん:全部が頭に入っているかは怪しいですが、読み込んではいます。あと、昔はJavaScriptから直にDOM操作をやっていたので、DOMの仕様もひと通り読みました。
伊藤さん:すごい。
uhyoさん:実は、「仕様を読め」と教えてくれた師匠がいるんですよ。
伊藤さん:その師匠は何者なんですか?
uhyoさん:匿名掲示板にいたので、誰なのかわからないんですけど…。
伊藤さん:誰だかわからないけど、師匠なんですね。
uhyoさんは師匠だと思っているけど、ご本人は自分にこんな弟子がいるとは思っていないわけか。
uhyoさん:はい、私のことは知らないはずです。
伊藤さん:自分でも知らない弟子が、自分の言いつけ通りに仕様書を読み込んだ結果こんなすごい本を出すとは想像すらしてないでしょうね…!
uhyoさん:「TAG index」っていう、HTMLとかJavaScriptを解説しているサイトがあって、私が中学生くらいのときに質問掲示板があったんですよね。
そこでJavaScriptとかの質問をしたら、ちゃんと仕様を引っ張ってきて答えてくれる人がいまして。
「なるほど、仕様書っていうのがあるんだ」と、そこで知りました。
伊藤さん:でも、それで仕様書を見ても、別に面白いことが書かれているわけでもないし、中学生くらいだと退屈しませんか?
uhyoさん:それが、面白いと感じたんですよ。
伊藤さん:いい話だ。確かに、ソフトウェアエンジニアの中には仕様書を面白いと感じる人がけっこういるんでよね。
私自身は、リファレンスとかもあまり面白いと思いながらは読めないんだけど、同僚に何人かそういうエンジニアはいましたよ。
ECMAScriptの仕様書を隅から隅まで全部読んでいて、みんなJavaScriptで何か不可解な挙動に遭遇すると、その人のところに「これってどうなってるの?」と聞きに行くんです。
すると、「これはですね、ここにこういう仕様があって…」という具体に答えてくれるんです。
uhyoさん:まさに私も同じタイプで、「これはけっこう面白いな」と思ったんですよね。
伊藤さん:ブルーベリー本も、そういう人でないと書けない本だと思うので、納得できます。
uhyoさん:「この言語の機能はこういうふうに定義するのか」とか、「この部分はかなり無理矢理だな」とか思いながら読むと、けっこう楽しめます。
たとえばECMAScriptの仕様だと、英語、つまり自然言語で関数とかオペレータの動作がずらっとステップごとに書いてあるわけです。
ところが中には自然言語で動作を定義するのが難しいはずのものもある。
awaitがいい例なんですが、1回制御を止めて別の動作をすることになるので、自然言語でステップごとに動作を定義するのはかなり難しいはずなんですよね。
実際、ECMAScriptのawaitの仕様も、「前のステップを中断して、それが終わったら呼び出したステップの続きに戻る」みたいなことを自然言語でステップごとに書いてあるんです。
それを読んでも、「これでawaitの動作を定義したことになるのか?」と思ったりもするんですが…。
伊藤さん:曖昧さが残されているように感じる、ということですか?
uhyoさん:いや、曖昧さは少ないと思います。がんばって自然言語で記述しているけど、あんまり実装者の頼りになるものではないな、という感じですね。
ECMAScriptの仕様書って、あくまでもそういう感じに挙動が定義されているだけなんです。
挙動をどう実装するかは実装者のほうで考えてねっていう具合です。
伊藤さん:それを面白いと感じられるわけですね。自分にはない感性かもしれない…。
やっぱりその仕様にあたるというか、原点にあたるのを普段から自然にされているわけですね。
uhyoさん:そうですね。原点を知るっていうのは、本当に重要視しています。
伊藤さん:原点に行く前に力尽きるからなあ。
uhyoさん:フロントエンドとかJavaScripの界隈とかだと、原点ではないにしてもかなり参考になる情報を広く扱っているソースとしてMDNがありますが、最近はMDNでさえ信用ならんっていう話もありますからね。
実は書いている人個人の意見が色濃く出てしまっているエントリーがあるのではないかと疑問を呈する声を見かけました。
そこまでいくと私も「ひぇー」と思いますが。
伊藤さん:私もMDNには「正しいこと」が書いてあると思い込んでいますね…。
uhyoさん:MDNは一次情報ではないので、どうしても「それ主張入ってない?」っていう話は出てきますよね。
最近だと、英語版のMDNの<i>タグとか<b>タグの説明に出てくる例や言葉使いは妥当か、という話を耳にしました。
<i>タグとか<b>タグとかは、旧来のニュアンスをあまり変えないようにしつつ、今の仕様では新しい意味を与えられていますよね。
仕様にも、一見するとわかったようなわからないようなことが書いてあるわけです。
伊藤さん:HTMLタグのセマンティックについての議論、ありましたね。いまでもやってるんですね。
uhyoさん:今はもう、ふわっとした定義を推す形である程度は落ち着いたんですけど、でもその説明をMDNで書くときに執筆者の主張が入っているんじゃないか、と。
伊藤さん:MDNも信用できないのだから、HTMLも仕様書にあたろう、というわけですね。
HTMLの仕様も、一時はいろいろありましたが、今はどこになったんでしたっけ。
uhyoさん:いろいろありましたが、最終的にはWHATWGに統一されました。
伊藤さん:昔は「<b>は太字」くらいの話だったHTMLが、いまやそれであらゆるアプリケーションのインターフェースを書いているわけで、まさかこんな時代になるとはって思うこともあるんですよね。
uhyoさん:わかります。
その話でいくと、Webにおける「後方互換性を壊さない原則」というか、20年前に作られたWebサイトがちゃんと表示できるのはすごいことで、フロントエンドでWebアプリを作るときにその原則にいつの間にか乗っかっていたわけですが、一方では「これに乗っかる必要があったのだろうか」という思うこともある。
伊藤さん:いやそうなんですよ。私もそれをずっと思ってるんですよ。
でも、アプリケーションとしては、Webと地続きになっているというメリットがあまりにも大きすぎるんでしょうね。
uhyoさん:ブラウザというプラットフォームがもう巨大すぎますからね。ブラウザがすべてやってくれますから。
この記事では、鈴木僚太(uhyo)さんと伊藤直也さんによる対談をお届けしました。
ウェブ技術を学ぶというと、次々に登場する各種のフレームワークやAPIの使い方を知ることに気が向きがちですが、仕様や計算機科学の源流に立ち返って自分で考えることの重要さ、そして何よりもそれを楽しむ姿勢が伺えたのではないでしょうか。
伊藤直也さんがCTOを勤める株式会社一休の採用情報はこちら。
興味を持たれた方は、ぜひ一度無料相談を利用してみてください。
編集協力:鹿野桂一郎(ラムダノート株式会社)
撮影協力:フォーシーズンズホテル東京大手町
東京都千代田区大手町1丁目2−1
あわせて読みたい関連記事
この記事を読んでいる人におすすめの記事