Sounds Around (My Life) has released!

まずこちらをお聞きください。つるえさんというボーカリストの方に楽曲提供をさせていただきました。ぼくは作詞・作曲・編曲・コーラス・ギター・ベース・打ち込みを担当しています。

soundcloud.com

つるえさんと知り合ったのは荻窪にあるアルカフェというアコースティックライブバーで、初めてお会いした時にその歌のうまさに衝撃を受けたのをとてもよく覚えています(この音源も、ボーカル補正なしですよ。めっちゃうまくない?)。

歌がうまい、というのには、いくつかの要素があるとぼくは思っています。まず、ピッチが正確であること。自分の歌を棚に上げて言うと、これが大前提。そこから先は個性や好みの話が関わって来て、たとえば一聴してそのひとの歌だとわかる強い個性、あるいはクセを持ったボーカル、というのがひとつあると思います。日本のポップシンガーで言うと、たとえば山崎まさよしさんとか奥田民生さんをイメージしていただくとわかりやすいのではないでしょうか。

実は、つるえさんの歌唱にはそういう「一聴してこのひとだとわかるクセや個性」はあまりありません。ただ、誤解して欲しくないのは、ここで言っているのは、アーティキュレーションのクセや発音のクセの話であって、声そのものの話ではないです。つるえさんの声は、地の声に芯があり、その芯の周りにツヤのある響きを纏わせていて、とても魅力的な個性があると感じます。そして、おそらく意図的に、歌唱法で「ここはこういう表情」「ここはこういう表情」というのを非常に幅広く、自覚的に使い分けています。アーティキュレーションや発音に、強烈な個性がないからこそ、とても幅広く表情をつけていて、変幻自在ですごい。

そして、そういうボーカリストに出会ってしまった、自分自身は歌が下手なコンポーザーが思うことと言ったらひとつしかないですよね。「このボーカリストに歌ってもらう曲を書きたいなあ」。その夢がかないました。書きました。歌ってもらっちゃいました。それが冒頭に貼った「Sounds Around (My Life)」という曲です。

このコラボレーションは、スタジオ録音などをしているわけではなく、リモートでコラボしていて、なんとボーカル録りは「iPhoneのボイスメモ」でやっていただくという荒業を見せています。このあたりにもっとリソース使えれば、もっともっとダイレクトにつるえさんの歌の素晴らしさを音源に残すことができたのですが、それができなかったことだけがとても残念です(ていうか、その録音環境でこの歌のクオリティなの、いい意味でヤバすぎませんか?大事なことだから二回言うけど補正もほとんどしてないんですよこれ)。

そんな心残りはあれど、ぼくが思うつるえさんのボーカルの「美味しいところ」のためにメロディを作り、つるえさんの声の魅力の邪魔しないように控えめな、しかし丁寧な編曲を心がけて、つるえさんの声で聴いたらとても綺麗にイメージが届くであろう歌詞を頑張って書いて、つるえさんの歌が主役になるようにミックスをしました。ソングライター、アレンジャー、DTMerとしての「このボーカリストに歌ってもらいたい」というエゴにめちゃめちゃに素直になった結果、全ての要素がつるえさんのボーカルに奉仕するようなつくりになっています。これでつるえさんの歌の魅力が伝わらなかったとしたら、それはもう完全にぼくの力不足以外のなにものでもありません。ぜひ多くの方に聴いていただきたいと思います。よろしくどうぞ。

2019年のwebAPIの設計を取り巻く問題と技術シリーズ そのに 「ビジネスロジック」は誰が持つべき?

前回の記事の続きです。

前回は、「時代が変わるとサーバーアプリケーションの役割も変わるよね。そうすると必要な要素技術も変わっていくよね」という話でした。今回は、じゃあ「サーバーアプリケーションがJSON喋るマンになって、クライアントアプリケーションとの協働でユーザー体験が実現されるようになってきた今、"ビジネスロジック"はだれが持つべきなの?」って話をしたいと思います。

基本的にはサーバーでもってあげたほうが楽

さて、サーバーサイドでなんでもやる牧歌的な時代は過ぎ去り、クライアントサイドとサーバーサイドがコラボレーションしてひとつの体験を提供するようになった昨今、「そのアプリケーションの体験を成り立たせるための"ロジック"をどっちに書くのか」という問題が立ち上がってきます。わたしの私見ですが、これはなるべくならサーバーサイドで請け負ってあげるのがよいのではないでしょうか。その理由は、クライアントサイドにはクライアントサイド特有の複雑な問題を抱えているため、そのほかの問題はサーバーサイドで抱えてあげたほうが全体の複雑さが減るからです。

HTTPというのは基本的にステートレスなプロトコルです。そのため、基本的にはサーバーサイドの状態は1リクエストごとに閉じています。リクエストを受け付ける時にはまっさらな状態で、レスポンスを返すまでには様々な状態をもちそれらに対して様々な計算をして、レスポンスをかえします。このとき状態は一度破棄され(あるいはRDBなどの外部に書き出され)、次のリクエストのときにはまたまっさらの状態でそのリクエストを処理し始めます。

一方、クライアントサイドでは、ブラウザSPAアプリならばブラウザをリロードするか別のサービスに遷移するまで、メモリ上に状態を持ってしまいます。とうぜん、これはネイティブアプリでも事情は同じです。やったことのあるひとにはわかると思いますが、この状態の管理は、それだけでけっこうめんどくさいものです。

また、その「状態」から複雑な画面を構築しなければいけないというめんどくさい問題も、クライアントサイドは抱えています。画面作るのほんとに面倒で、そこにユーザーインタラクションがからむともっともっと面倒です。そういうめんどくさい問題を抱えているのに、さらに複雑なビジネスロジックまで押し付けられるのはあまりに大変ですので、困難を分割するためにも、サーバが出来る限り複雑さを引き受けてあげるのがよいのではないかと思います。

また、サーバーサイドに複雑なロジックを持っておくことで、複数のプラットフォームでのアプリ展開がやりやすくなる、という面もあります。たとえばiOSアプリもAndroidアプリもwebアプリも作る、というような場合に、クライアントサイドにビジネスロジックを持っている場合、それぞれのアプリで毎度実装する必要が出て来ますが、サーバーサイドでロジックをもってあげればサーバーサイド一回の実装ですみます。

また、クライアントサイドで一生懸命複雑なことをやったとしても、サーバーにとってリクエストは「だれから送られてきたかわからないもの」なので、結局サーバーサイドでデータの不整合が起こらないように検証はしなくてはいけません。そういった検証はまさにビジネスロジックの一部であり、クライアントサイドでビジネスロジックを持った場合、サーバーサイドでも重複したロジックを書かなければならない、というようなことは容易に起こり得ます。

ファーストパーティに閉じたサービスとサードパーティに開かれたプラットフォームの違い

しかし、これらの状況は、そのサービスが、ファーストパーティに閉じたサービスなのか、それともサードパーティに対して開かれたプラットフォームを目指すのかによって、事情が変わってきます。

ファーストパーティに閉じたサービスの場合、APIは「このアプリ専用」に作ることができます。いわゆる「顧客-供給者の関係」ですね。アプリ側の都合に合わせてAPIを作ることで、「複雑なビジネスロジック」をサーバー側が引き受けることになります。

一方で、サードパーティに開かれたプラットフォームの場合、不特定多数のクライアントに対して応答する必要があります。そのときに、サーバーサイドは、あるクライアントが解こうとしている問題に特化したAPIを提供するわけにはいきません。そんなことをしたら、クライアントの数だけAPIの種類が増えてしまいます。そのため、サードパーティに開かれたプラットフォームでは、サーバーサイド側になるべくロジックをもってあげることが難しくなります。プラットフォーム側の「ビジネスロジック」は薄くなる傾向があるでしょう。

しかしこれは、考えてみると当然のことです。というのも、プラットフォームというのは、「ぼくたちのデータや資源を使って、きみたちの問題を解決してね」というサービスなわけで、そうなってくるとどうしても問題を解く主体は、プラットフォームではなくてそのユーザーとなるでしょう。つまり、ユーザーは、ユーザーごとに異なる問題と向き合うことになるわけです。そのときに「ドメインロジック」がクライアント側にもたれるようになることは、ある意味当然となります。もちろん、このときプラットフォームにとっての「クライアント」が、webブラウザであるとは限りません。プラットフォームのユーザの選択によっては、webブラウザだけで完結するかもしれませんが、あるいはプラットフォーム利用者が自前でサーバーを立てて、そのサーバーサイドアプリケーションがプラットフォームにとってのクライアントとなるかもしれません。しかし、プラットフォーマーが持つサーバーアプリケーションは、特定の問題のための「ビジネスロジック」を持たない、ということには変わりがないでしょう。

まとめ

というわけで、まとめると、

  • 基本的には複雑なビジネスロジックはサーバーにもってあげるのが筋がよいと思う
  • 一方で、サードパーティに広く開かれたプラットフォームの場合はクライアント側にビジネスロジックを持ってもらい、サーバーはファンダメンタルな操作を提供するほうがよい

という感じになります。

前者の場合、最近だとリソース指向なAPI(いわゆるRESTfulなAPI)よりも「ユースケース指向」なAPIが増えてきていると感じます。ユースケースと1:1になるようなエンドポイントが生えてるようなAPIですね。

一方で後者の場合はユースケースはクライアントに依るので、mutationに関してはリソース指向のAPIがマッチしそうです。一方、リソースの取得についてはクライアントによってほしいデータが違うという問題があり、そのあたりにはGraphQLの恩恵がききやすいのではないか、という理解をわたしはしています。

次回書く気になれば、次回は

  • サーバーサイドに寄せられた、複雑なロジックやミドルウェアとのやり取りと向き合うための技術
  • クライアントサイドに残された「状態管理」と「複雑な画面」と「ユーザーインタラクション」と向き合うための技術

あたりを書けたらいいなと思います。が、もしかしたらtwitterでバーっと書いて満足してしまうかも……。

2019年のwebAPIの設計を取り巻く問題と技術シリーズ そのいち 導入

最近、2019年のwebAPIの設計まわりの問題について考えていて、問題とその周辺技術の整理を自分の頭の中でしています。 で、その内容をたぶん何回かに分けて書きますが、初回の今日はちょっと導入として浅めの部分を整理してみようと思います。

昨今、サーバーサイドの仕事はもっぱらJSONなどをしゃべることに終始して、エンドユーザーが触る画面をサーバーがレンダリングする事例は減ってきているのではないでしょうか。これはぼくが考えるに不可逆な事態で、今後もユーザーが使うインターネットにつながるデバイスは多様化していくし、それぞれがそれぞれにネイティブな環境を持ち、それらがHTTPSを喋ってインターネットとつながる、という世界はしばらく変わらないでしょう。言葉を変えれば、サーバーサイドでHTTPをしゃべるお客さんが、エンドユーザーからクライアントアプリケーションというプログラムに移行してきている、ということです。

その結果、サーバーサイドからは「複雑な画面を作る」という責務が奪われます。その結果がサーバーサイドアプリケーションになにをもたらすのかを考えてみたいと思います。

まず、Railsなどでよく使われる文脈でいう「decorator」は、昨今においてはその存在感を少しづつ失っていくでしょう(Pythonとかのデコレータとは文脈が違うので注意)。そもそも、この文脈におけるdecoratorは、「画面が要求する様々な"ちょっとした計算"」というプレゼンテーションの関心がモデル(ここでいう「モデル」というのはRailsの文脈でいうような「モデル」です)に混じってしまうことを避けるためのソリューションでした。しかし、昨今ではサーバーサイドアプリケーションがそのような複雑な画面をレンダリングすることはなく、jsonをペロッと吐けばいいだけです。そこには「画面が要求する様々な"ちょっとした計算"」は必要なく、むしろそれは画面を構築するクライアントサイドのプログラムでやってもらうべき仕事となるでしょう。

この「デコレータいらなくなったよね」という話は、牧歌的な「サーバーで全部やります」な時代が終わり、解くべき問題が変化した結果、必要な要素技術が変化していく1例として考えられるのではないでしょうか。ここで確認したかったのは、「デコレータがいらない」という話ではなく、 むしろ「問題がかわったら必要な技術が変化する」ということです。

さて、サーバーサイドからは「複雑な画面を作る」という責務が奪われたわけですが、昨今新たに出てきた新しい問題として、「じゃあサーバーとクライアントの間でどういう責務分割をするべきなの?」「サーバー側はサーバー側で昔と比べて複雑さ増してきてるよね?それをどうする?」というものがあります。次回以降、そのあたりの問題を整理しながら、どういう問題に対してどういう技術が効いてくるのかを書いていこうと思います。

まだ詳細未定ですが、予告としては、

  • webAPIとクライアントのどちらに「ロジック」を寄せるべきかという問いを整理
    • ファーストパーティに閉じたサービスとサードパーティに開かれたプラットフォームでの違い
  • ファーストパーティに閉じた場合
    • サーバーサイドに寄せられた複雑なロジックやミドルウェアとのやり取りとどう向き合うか、その解決としての設計パターンとmicroservices
    • クライアントサイドに残された「状態管理」と「複雑な画面」と「ユーザーインタラクション」とどう向き合うか、そのための技術、その解決としてのFlux系技術
  • サードパーティに閉じた場合
    • クライアントサイドにさらに積まれる責務とどう向き合うか、そのための技術(「いわゆる」DDD的な手法)
    • 多種多様なクライアントに対してどのようにレスポンスを返すのか、そのための技術(GraphQLあたりの話につながる気がしている)
  • コネクションにぎりっぱなし問題
    • なんか書くことあるかな。2019年においてはもうそろそろ書くことなくなってきてる気はする。

あたりを書きたい。本当に書くのかは不明。@qsonaさんあたりとtwitterで喋ったら満足して書かない可能性もあります。

FizzBuzzを題材にユースケース層についてを考えるのはおそらく無意味な気がする

やんざむ先生のこのツイートを見て考えたことをまとめます。

結論を先に書くと、「これはそもそも問い自体が不適切である」(しかし強いて言えばEntity)という立場をわたしは取ります。以下、まじめにFizzBuzzを設計しながら考えてみます。

ひとまず、出発点は上にあるツイートの疑問から出発するとしましょう。

まず前提として、ユースケースってどういう役割か

まず前提として、ぼくはユースケースを「ドメインモデル(このツイートで言うところのEntity)やインフラストラクチャのオーケストレーションをする部分」だと思っています。

たとえば、「あるボタンをクリックされたら、複数のドメインモデルを利用して生まれた結果を、データベースに保存する」というのは、複数のドメインモデルとインフラストラクチャ層にあるリポジトリ組み合わせて 、システムのユーザーのアクションに1対1で対応する「ユースケース」を実現しています。

つまり、ユースケースというのは、

ものだ、と考えています。

FizzBuzzについて考えてみる

さて、翻って、FizzBuzzについて考えてみましょう。まず、FizzBuzzを無理やりアプリケーション層とドメイン層に分けて考えるとしましょう。その場合、

  • 3で割れる場合はFizz
  • 5で割れる場合はBuzz
  • 3でも5でも割れる場合はFizzBuzz
  • それ以外の場合は数字をそのまま表示する
  • これを1から指定の数字まで繰り返す

というのは、FizzBuzzという問題領域を定式化、つまりまさにモデル化したものだと言えるでしょう。なので、これをドメインレイヤーのものであると考えるのは妥当だとすることにそれほどの無理はないでしょう。

ドメインレイヤーでこの定式化された知識をどのように分割するか、という点では、いくつかの判断がありえます。ぼくがぱっと思いついたのは以下のような感じです。

  • 数をValueObjectとみなして、それを利用してDomainServiceがループで文字列を返す
  • もう全部DomainServiceに書いちゃう

前者の発想だと、以下のような実装になります。

case class FizzBuzzNum(i: Int) {
  def asFizzBuzzFormat = i match {
    case i if i % 15 == 0 => "FizzBuzz"
    case i if i % 5 == 0 => "Buzz"
    case i if i % 3 == 0 => "Fizz"
    case i => i.toString
  }
}

object FizzBuzzService{
  def doFizzBuzz(max: Int): Unit = {
    (1 to max)
      .map(i => FizzBuzzNum(i).asFizzBuzzFormat)
      .foreach(println)
  }
}

一方で後者の発想だと以下のような実装になります。

object FizzBuzzService{
  def doFizzBuzz(max: Int): Unit = {
    (1 to max)
      .map{
        case i if i % 15 == 0 => "FizzBuzz"
        case i if i % 5 == 0 => "Buzz"
        case i if i % 3 == 0 => "Fizz"
        case i => i.toString
      }
      .foreach(println)
  }
}

これは、どちらのほうが「良い設計」でしょうか。設計のレビューをするときに参考にすべきなのが各種設計原則です。そして、設計原則を適用した際の結果というのは、「問題がどのようなものか」に依存するのでした。このあたりの詳しい話は実況中継シリーズ 「開発現場で役立たせるための設計原則とパターン」 #builderscon 2018を参照してください。

さて、FizzBuzzについて、「どの部分に今後の変更がありえて、どの部分に今後の変更がないのか」を考えてみましょう。それを考えると、実は「FizzBuzzは完成された問題であり、今後の変更はない」という答えが見えてきます(!)。そうである以上、上のふたつの設計のどちらが正しいかなんてありません。問題が十分に小さいため、どちらのコードもそれなりに可読性があるし、あとはもう趣味の問題です。好きな方にすればいいと思います。

さて、ドメインレイヤーの設計が終わったところで、ユースケースのことを考えてみましょう。ユースケース

ものなのでした。しかし、今回の例に「複数のドメインモデルやインフラストラクチャ層のオブジェクトをオーケストレーション」する必要はあるでしょうか?「ない」というのがその答えではないでしょうか。そうなると、FizzBuzzという問題領域において、ユースケース層の役割は「無い」ということになります。プレゼンテーション層から直接このドメインサービスを叩くだけで良いでしょう。つまり、そもそもFizzBuzzを真面目に設計すると、多層からなる設計は不要というか、多層からなる設計をしようとしたら「役割のない層」が生まれてしまうという、考えてみれば当たり前のところに落ち着いてしまうわけです。

そして、ユースケース層の役割が「無い」ような問題領域を例にとって「ユースケースとはなにか?」を考えても、おそらく意味のある答えは期待できないでしょう。それを考えると、どうしても「これはそもそも問い自体が不適切である」という結論が出てきてしまうのです。

まとめ

このエントリの内容を要約すると、以下のようになります。

追記:

「当事者」になれないわたし

ぼくは空気を読むのが得意な方ではない。と書き始めて思ったけれど、そもそも、おそらく「自分は空気を読むのが得意で」などと自信を持って言えるひとはそうそういないかもしれない。頭ではそうわかっているのだけれど、感情の部分で「"空気を読むのが得意で"と自信を持って言えるひとはいいなあ」なんて思ってしまっている自分もいるのだ。

だって、「自分は空気を読むのが得意で」と自信を持って言えるようなひとは、逆説的なことだけれど、なんだかむしろ「自然体」で過ごしているような気がする。「空気を読む自分」と「その空気の中にいる自分」の間に1mmのズレもなく、「空気の当事者」であることに対して違和感を感じることなく過ごせる、そんな自然体。そんな明瞭な当事者でいられる強さ。「自分は空気を読むのが得意で」とてらいなく言えてしまうひとには、そんな強さを感じ取ってしまう。

翻って自分を見てみると、なんだか空気を読む自分とその空気の中にいる自分の間に、もやもやとしたズレがあるような気がする。べつに「空気を読んでしまった結果本当の自分を殺してしまっている!」なんて思っているわけではない。むしろ本当の自分なんてものがあるのであれば、きっともっと自然体で空気を読めるのではないか。本当の自分なんてものをしっかり持っていれば、本当の自分と「場に求められる自分」の間の距離をしっかりと測ることができる。だからこそ自然に空気に順応することができるのではないか。ぼくの場合、むしろ本当の自分みたいなものがなんだかふわふわしているから、自分と場の距離感を掴みそこねて、場の空気を読もうと変な力が入りすぎて空回りしたり、逆になんだか全然空気を読めなくて無礼な感じになってしまったりしているのではないか……。

しかも、そんな自分を、まるで他人のように、ズレた位置から眺めている自分。ぜんぜん当事者な感じがしない。当事者になれないままなんだかふわふわとプログラマの定年と言われる35歳を迎えようとしています。そのあとは不惑が待っている。ふわふわとしたまま不惑を待つ。けどまあ、きっとみんな大なり小なりそんなふわふわを抱えて生活してるのではないか。ふわふわしたまま大人になったっていいじゃない。だめ?

Template Method Patternがマッチする場合、マッチしない場合

リーダブルコードとハードバップコード

まずはこのおもしろツイートをご紹介させてください。

このツイートを某所で紹介したところ、「たしかに紛らわしい」「"よりよいChordを書くためのシンプルで実践的なテクニック"でもふつうに意味が通じるのがすごい」という声のほかに、「ワーオ,君の書くコードはまるでハードバップのようだ(喧嘩になります)」「 $_[++$_]->%* これとかハードバップ感ある」という声が上がったため、ハードバップのようなコードを書いて見ました。Perlで実行してみましょう。

s///;sub bop {


'$_[++$_]->%* is_a', +{ 'hard', 'bop' }, 'code'


} sub hard { print


$_[++$_]->%*


}

hard bop

このコードは、実行すると "hardbop" を出力します。わたし程度ではこのくらいのヒップさが限界ですが、もっとヒップにできそうな気がするので、ぜひあなたのバップも聴かせてください!ちなみに、このヒップなコード片( $_[++$_]->%* )を書いたのは id:moznion です。彼こそがヒップ。