ジンジャー研究室

長めのつぶやき。難しいことは書きません。

問題を解決したい話

なんとなく良い方法を提案されることがある。

「こっちの UI の方が良いと思う」
「新しいデザインにしましょう」
「あれもやった方がより良さそう」

感覚的になんとなくその方が良さそうというのはあるが、根拠が「そっちの方がいいから」であるうちは賛同できない。例えばデザインの話で言うと、良かれと思ってやった変更が不評なこともあるし、実は意図的にそうなっているのを知らずに壊してしまうこともある。あるいは、良くなるかもしれないが既に満足度が高くて必要のない変更かもしれない。

限りあるリソースを無駄にしないために「問題を解決する」ことにフォーカスして考えたい。 「そっちの方が良い」のであれば現状の問題になっている点は何か?ホームページに「明るい雰囲気の画像を置きたい」のは「暗い雰囲気を感じる」からであり、例えば採用に応募しにくいなどの実害が生じるのが問題だということになる。できれば本当にそうなのかを A/B テストなどで計測できれば良いが、難しい場合は仮説でも構わない。
問題が解決するならば、その分だけ確実に前に進むとわかる。かっこ悪い UI でも実際に問題になっていないのであれば放置でいい。逆に今は大した問題になっていないが問題が起きた時に甚大な被害を及ぼすなら優先度を上げて対応するといった判断もできる。フィーリングで「もっと良くしましょう」だと本当に意味のある仕事か分からないし、提案者の好みの問題で手を動かさないといけないのはモチベーションも下がってしまう。「良くしたい」と思うのは、提案者が無意識に問題だと感じていることがあるのだろう。だが、その問題は言語化してみると実は大した問題ではなかったり的外れであることも多い。

ことをややこしくするのが、「漠然とした問題」に対する「複数の問題を同時に解決するツール(方法論)」の存在だ。漠然とした問題は A, B, C に分解され、ツールが解決する問題は B, C, D, E, F だ。大抵は分解するところまでいかず「なんとなく不満を抱えている現状よりは良くなるんじゃないか」ということで導入を検討するが、意外と大変で頓挫するか、導入されたがどうもしっくりこないとモヤモヤを抱えるかになる。問題が分解できていれば、 A, B, C それぞれを解決するミニマムなツールを導入することもできるし、ツールの機能を部分的に導入した上で A だけは運用でカバーということもできる。

と、ここまでは問題を分析してピンポイントで解決することでコスパを良くしたい話。一方で、問題と一対一対応しないがとにかく手段を使ってみた方がいい場合がある。見えていない問題が発掘される可能性が高い場合や、手段が提供するメリットが見えていない場合だ。それらが世の中に広く浸透しているノウハウであれば、現在地が「守破離」の「守」である場合、と言い換えることもできる。
例えば、 SVN を使っている現場に Git を導入するとする。Git を使いこなす人々は「ブランチが手軽に切れるのがメリットだ」と言うが、 SVN しか使ったことのない人には何のことか良く分からない。ここで現場の人は「今の SVN の運用で何も問題は起きていない」と提案をつっぱねることもできるし、「問題を丁寧に分析した結果、3つの問題があり、 Git はその1つしか解決してくれない」と言うこともできる。が、同時に今見えていない問題を認識していないこともあるし、提案者の語らない Git のメリットもあるかもしれない。つまり、体験や学びが得られる期待値が高い場合は、試してみた方が長い目で見て得になることがある。

前半で「問題解決」にフォーカスすること、後半でそれに対しての反例を挙げたが、両立する話ではあると思う。リソースの少ない中で行き当たりばったりな方法を試す余裕はないが、一方で学びを目的として中長期的な戦略を取るのはアリ。「学びが得られず組織が硬直する」というのも問題の一つなので、それを解決することに対して意識的であれば、行き当たりばったりな解決とは違うし、仮説・検証もできる。

話が大きくなってしまったが、まず問題を定義してから解決したいし、言語化されていない問題を「なんとなく良くなるであろう方法」で解決するのを避けたい、という話でした。

紙にタスクを書くのが便利

抱えているタスクが増えてパンク寸前だったので、紙に書き出して PC の横に置いておいたら神ツールだった。紙だけに。

タスク管理に便利なツールは色々存在していて、専用のツールもあるし、開発する機能やバグであれば GitHub の Issue にすればいいし、複数のリポジトリを跨がる場合はプロジェクト機能もある。Slack でプライベートなチャンネルを作っておいてそこに書き留めておくこともできる。あとは Spread Sheet でもいいし、他にもタスクを管理できるツールは山ほどあるのだが、このようなデジタルなソリューションには共通して「アプリを開いて見に行かないといけない」という弱点があり、これが地味にめんどくさい。 何か作業をして、確認して、また作業に戻り、また確認してを繰り返すと、ウインドウを行ったり来たりするだけで消耗してしまう。ディスプレイを一台増やしてタスク管理専用画面にするのでもまあ良いとは思うが、常に電源が入っていて場所も移動しないという縛りがある。色々試して最終的にもっともアナログな紙に行き着いた。紙に書いて隣に置いておけば、画面に何が表示されていようとすぐに確認できる。

用意するのは A4 用紙1枚。1つのタスクは平均 10 文字くらい。詳細は書かない。詳細はオンラインで他人とも共有した方がいいし、手で文字を書くのは時間がかかる。 書くのはあくまで「直近で取り掛かっているタスク」のみ。1年後に直すかもしれないバグ修正とかを書き始めると数百単位になってしまうので、そういうのは GitHub の Issue にでも書いておけばいい。あくまで解決したいのは「今やっていることを記憶したい」という問題なので、まあ 20 個くらい。1日のうちに並行して取り掛かれるタスクはせいぜい2、3個なのだが、他の人に投げていたりブロックされているタスクを含めると、そこそこの数になる。仕様策定中の機能が5つ、次に実装する機能が2つ、すぐに修正すべきバグが2つ、WIP な PR が3つ、依頼されたレビューが2つ、他の人に振っているタスクが3つ、キャッチアップすべき課題が1つ、回答待ちの質問が1つ、 Qiita への返信が1つ、次のミーティングで共有すべき情報が1つ、事務作業が1つ...。紙に書いておくだけで、今何をしていたか思い出せる。

という、今更ながらの気付き。無理してデジタルで完結する必要はなかった。 まあ多忙な社会人はやってるだろうと思って調べたけど、意外と紙1枚でやっている人は少なそう。あとカレンダーに1日のタスクを書くというのも出てきたけど全然ピンと来ないので職種が違うのかもしれない。

ミスマッチ

仕事で使う技術 X がある。

技術 X を習得したいが、そこまで興味もなくプライベートで学習するのが辛い。

とはいえ実際に手を動かしてみないと習得するには至らないだろう。

そうだ、モチベーションを高めるために技術 X を使ってアプリ A を作ろう。

もちろんお題となるアプリ A はプライベートで作れる程度の簡単なものだ。

ところが、アプリ A を作るのに最適な手段は技術 X よりももっと簡単な技術 Y だ。

ああ、技術 Y を使ってアプリ A が作りたい。

すごいコード

OSS とかのコードを巡っていると、時々「すごいコード」に出会うことがある。 もちろん「すごい」と言っても色々な凄さがあって、「読みやすくメンテしやすいコード」とか「技術的に凄いことをしている」とか「最新のライブラリを上手く使っているコード」はもちろんそうなのだが、それ以上に「圧倒される」コードがある。

凡人の発想と違うことがあり、一見して読みにくく取っつきにくいこともあるが、そういう感想はすぐに吹き飛んでしまう。

その特徴を思いつくままに列挙してみる。

  • 癖があるが終始一貫した書き方
  • 世に出回っているベストプラクティスに則っていない
  • フォーマッターを使っていない
  • 細かいユーティリティ関数がない
  • 初手で完璧に近い
  • 静的型でないコードも多い
  • 可読性のためにパフォーマンスを犠牲にしない
  • とにかく無駄がない
  • テストがないこともある

別に型やテストがないのは見習うべき点ではない。一方で、これは絶対に真似できないなーと思う。

もし「独りよがりな書き方してんな!俺がマトモにしてやる!」とリファクタリングを始めたとしたら、しばらく経ってたちまち鬱になるのが目に見える。 3 行のコードが 20 行にフォーマットされ、共通化はしたものの良く分からない名前の変数や関数が増え、たまに共通化したコードを使い忘れている箇所があり、やたら型が増え、宣言的なのに簡潔でなく、無駄にメモリを食い、後になって「ここは共通化すべきじゃなかった」と言って戻す。

じゃあなんで彼らはそういうコードが書けるのかという仮説、あくまで仮説を立ててみる。

  • 圧倒的な経験量。こういう時はこう書くというパターンが予め頭に入っているために迷いがない。迷いがないからコードの書き方に関して雑念がなく、本質的な部分に集中できる。昔から書いていたのでスタイルは古いが、メモリを食いにくい書き方が常に意識されている。細かいアルゴリズムは頭に入っているのでユーティリティ関数を使わなくてもすぐに書けるし、逆に書かれたパターンからアルゴリズムを瞬時に読み取ることができる。
  • 圧倒的な知識量。技術的に十分な知識を持っていれば、予め何が出来て何が出来ないかが把握できるので適切な設計ができ、行き当たりばったりにならない。セキュリティ的に考慮すべき点は最初から網羅できる。仕様書を読めば実際に試さなくても何が起こるか把握できる。
  • 上記2つを効率良く高速で摂取する頭の良さ。

優れたプログラマは頭の中で全てを組み立て、手を動かし始めたら一気に頭の中にあるものを吐き出すだけ、と良く言われる。 翻って凡人プログラマである自分は逆に何をしているのかというと、とにかく常に迷い、試行錯誤している。

まず知識量の不足から仕様書を確信を持って読むのがとにかく難しい。簡潔に書かれているそれらは、おそらく背景知識があれば自明なのだろうが、一部が抜け落ちていると理解が困難になる。そして「分からん!とにかくサンプルをくれ!」となる。サンプルを通してやっと「あれはこういうことが言いたかったんだろうな」と理解した気になる。試行錯誤しなければ分からないとなると、大きな時間のロスになる。一つ確かめるのに20分かけてデプロイしたら、3回で1時間。なかなか進まない。また、サンプルにないパターンを自分で組み立てるのは不可能なので、「とにかく自分のやりたいことと似たことをやっているコードがないかググって探す」ことに時間を費やすことになる。まるで何か未解明の自然現象に触れるかのように「あれをしたらこんなことが起きた」を繰り返すのだが、実際にはブラックボックスでもなんでもなく仕様はちゃんと書かれている。

試しながら書いているととにかく書いている時間が長いので、書き始めた時と書き終わる頃で気分が変わって一貫性がなくなっていく。ある時は関数を上に書き、ある時は下に書く。その時々で「これで行こう」と判断した形跡が、ミクロにもマクロにもある。タイピングも遅いので同じコードを何度も書いているとだるくなってきてユーティリティ関数を作ったりする。が、関数を一つ作るということは名前を一つ考えるということでもあり、名前こそその時々の気分が反映される。行き当たりばったりで生み出した謎概念を、拙い英語(しかし簡潔に表現しようとして短くして情報が不足している)で表現しているのだからタチが悪い。

すごいコードはそうした凡人プログラマの苦悩を微塵も感じさせないので、すごい。

賞味期限が1年

このブログもまあ長いことやってるんだけど、これだけダラダラやっててもちょいちょい「○○さんが『△△』をブックマークしました」って通知が来たりする。でも、正直古い記事だと「それもう賞味期限切れてるよなー」って思うことがあって苦い気持ちになったりする。

自分の感覚としては1年経ったら大体も主張も色あせてきて、振り返ると「何々はなんとかすべきである」とか何を偉そうにのたまっとんじゃ〜という気持ちになる。いやもちろん正しいことも言ってるし、将来考えが変わることを予想して予防線を張っていたりはするんだけど。何かを主張している系の記事はどんどん気が変わってしまう。

CSS はもう全部インラインでいいだろ」 「いや、なんやかんや言って普通に CSS ファイル使うのがやりやすいわ」 「CSS ファイル膨れ上がりすぎるし書く場所を移動するのめんどい。やっぱインラインで書けばいいんじゃないか」 「CSS フレームワーク要らね」 「要らないとは言ったけど、結局は代わりに自前で似たような仕組み作らざるを得ないわ」 「View は Model の関数だよね、状態持つとか以ての外だよね」 「あーバケツリレーめんどい、状態持たせろ」 「人間は DOM から離れては生きていけないのじゃ」 「関数型最高、イミュータブル最高、手続きなんて捨ててしまえばいいね!」 「どーでもいいわ。こんなの手続きでちょろっと書けば終わりなのに何でわざわざ難しいことしてるの」 「class 普通に使うでしょ、わざわざ用意されてる便利な道具を使わない理由なんてある?」 「ボイラープレートは必要悪だ、同じことを何度も書いてもシンプルで見通しが良けりゃいいんだ」 「そこ共通化できないの最早プログラミングじゃないだろ、マクロ使わせろ」 「これが世間のベストプラクティス、みんな従うべき!」 「世間のベスプラが正解とは限らないし、守る必要なんてないでしょ」

こういうのを何度も何度も繰り返していくうちに、段々めんどくさくなってきて「適当にみんな好きなようにやればいいんじゃないの、知らんけど」になったり、「要はバランス」とでも言いたくなったりする。その場で思いついた適当なことを周囲に撒き散らしながら、自分だけは「こういう場合はこうだよね」という言語化されないバランス感覚が身につくので、まあ迷惑なやつだ。

適当なことを言ってるので適当に聞いてもらえれば良いんだけど、中には目を輝かせて聞いてくれる人が一定の割合でいて、「いやこんなの信用しなくて良いし1年後には全然違うこと言ってるよ?」という気分になってしまう。自分も web 界隈の強そうな人がなんか言うと「そうなんだ〜」ってなるけど、逆に「うるせー好きにやらせろ」って思うことも多々ある。そもそも web 界隈の平均的なプロジェクトの事情と自分の目の前にあるプロジェクトの抱える事情は違うわけで、「参考にはするけど内心は疑ってますよ」というスタンスで聞いてたりする。でも、自分がそうだからといって読者もそうとは限らないなと。ここのところはそういう主張モノを書くのはやめてしまって、なんか試しにやってみたっていう日記か、ただただ技術的に正しい事実を淡々と書いていく感じ。「あのブログにこれが良いって書いてあった」と言われると面倒だし。

じゃあ、そういう主張モノが害しかないかというと、そうは思っていなくて、みんなが色んな意見を言ってるのを聞いて上のように行ったり来たりしてるうちによりアイデアが洗練されてくるということはあるだろうし、言ってることも大体「一理ある」とは思う。誰も何も言わなくなったら、少なくともそういう考えを持った人がいるということを知る機会もなくなるし、それはそれで面白くない。

プロジェクトに採用するライブラリやアーキテクチャにしても「あの時はそれが良いと思ってたけど、試した結果イロイロ問題があることが分かったわ」みたいのがあって、「なんでこんな風になってるの?」と言っても本人も「なんでだろね、当時はそれがベストな方法と信じていたんだ」となったりする。

このアイデアの賞味期限というのは人によって違って、中には自ら 10 年前の主張をピックアップする人もいる。それだけ長い期間ブレない考察が得られるのは素直に尊敬する。真似できない。経験なのか知識なのか性格なのか、それは分からない。自分はコーディングも1分前にしていたと全く違う方法で書いてしまったりする。「さっきは関数を下にまとめるのがみやすいと思った。今は上かなと思ったから上に書いてる。」気分屋にもほどがある。でもブレないスタイルでずーっと書き続けられる人もいる。多分あれは「考えずに書くだけ」モードに入ってる。すごい。

世の中にはすごい人もいるけど自分には無理なので諦める。読者も諦めて欲しい。 ここに書くアイデアの賞味期限は1年です。

wasm ターゲットな言語を作って音を鳴らしてみた

前回、 Faust という言語を使って音を鳴らしてみたわけですが、AudioParam を使ったオートメーションに対応していないのでちょっと微妙だなと思いました。まあ Web が唯一のターゲットではないので仕方ない気はしますが。多分これができないと楽譜データからミックスダウンとかもできないはず。

じゃあということで次に試したのが EmscriptenC++ から出力するやつで、まあ動いたんですが、サイズがでかいとか、余計な JS コードがついてくるとか、バインディングを書くのが面倒くさいとか細かいところが色々気になったりしました。他にも Rust とか色々選択肢はあるんですが、どれにしても結局 AudioWorkletProcessor との接続部分は書かないといけないのが面倒で、ああ本当に面倒なのでそれ用の言語が作りたくなりました。

AssemblyScript を調べてたら binaryen.js という Binaryen のラッパーを使ってたので採用。この時点で LLVM が消えてターゲットが wasm のみに。脳みそが狐さん以下なので仕方ないですね。

作ったもの

名前はまだない。 github.com

こういう感じのコードを書くと、wasm モジュールとそれをラップした AudioWorkletProcessor が生成されます。デモはこちら

言語を作ったりするのは初心者もいいところなので、コスト削減のために大幅な割り切りをしています。

  • 動的なメモリの確保はできない
  • 型推論のような贅沢なものはもちろんない
  • 配列とループの長さは 128 決め打ち
  • 新しい型も作れない
  • if もねえ

逆に、あるもの

  • AudioParam 定義用の構文
  • VSCode 拡張

f:id:jinjor:20200415023948p:plain

エディタに色がつくと急にそれっぽい!

感想

wasm の特性なのかは不明ですが、 C っぽい言語が圧倒的に作りやすいというか、普通に普通の文法を動かすのが普通に大変で、それ以上の気の利いた文法とかはもう「動くんだから愚直に書けばいいでしょ」という気分になってきますね。 あと binaryen のレイヤーが高いのか、全然アセンブリ書いてる気がしないというか、結局アセンブリのこと何も分かってないかもしれない。うーん。

反省点としては、自作のパーサーコンビネーターがトークナイズしてないせいでホワイトスペースが至る所に出現してノイズが多いのと、VSCode 拡張(というか Language Server Protocol)で補間とか出そうとするとマメにコンテクストを管理しなきゃいけないなーっていうのに後で気づきました。直すの辛いけどやった方が良さそう。

まあとりあえず動いたので満足です。メンテナンスしたくないので広く公開することは多分ないけど。 早く FM 音源とか作りたい〜!