- 開発者ツールは、コンピュータが実行するロジックだけでなく、他の人が理解して使うためのメンタルモデルまで設計しなければならないため、より難しい
- 迅速なオンボーディングは付加機能ではなく、製品そのものに近く、設定・APIトークン・初回実行時の摩擦を減らして、数分以内にノートPC上で試せるようにすべき
- ユーザーは長いコア概念の説明よりも、動くサンプルを変更しながらパターンを学び、解決したい問題に近い出発点が多いほど成功しやすい
- エラーメッセージ、概念の数、命名、設定方法、デフォルト値、マジック、シンタックスシュガーはいずれもユーザーの成功経路を変えるため、読みやすくカスタマイズ可能な設計が必要
- 良い開発者体験とは、機能を単に削ることではなく、作れる範囲を維持しながら、知る必要のある複雑さを大きく下げること
人間のためのコードはメンタルモデルまで扱う
- コンピュータのためのコードは、大きなビジネス目標を論理的な文に分解し、コンピュータが従えるようにする作業
- フレームワーク、ライブラリ、API、SDK、DSL、埋め込みDSL、プログラミング言語のように人が直接扱うコードは、実行可能であるだけでは不十分
- こうしたコードはコンピュータに指示を与えると同時に、ユーザーがそのコードをどう読み、どう理解するかも一緒に扱う必要がある
- 開発者ツールの設計には、コンピュータサイエンスだけでなく、ユーザーの推論の仕方を考慮する心理的理解が必要
始める体験こそが製品
- 開発者ツールへのフィードバックは、たいてい製品を頻繁に使うパワーユーザーから多く寄せられる
- 始める段階で詰まったユーザーはフィードバックを残さないため、生存者バイアスが生じる
- コンシューマー向け製品がオンボーディングファネルを最適化するように、開発者ツールも初回実行までの過程を製品の中核と見なすべき
- 迅速なオンボーディングのためには、製品構造そのものを変える価値がある
- 必須設定をなくす
- APIトークン設定を非常に簡単にする
- 初期摩擦を減らす
- ユーザーが数分以内に自分のノートPCで製品を試せるようにする
- 開発者ツールが多すぎる環境では、ユーザーが特定のLRU cache NPMパッケージの違いを深く理解するだけのエネルギーや忍耐を持ちにくい
サンプルはコア概念より速く教える
- 人は、厳密な命令に従うコンピュータと違って、パターンマッチングが得意
- 多くの開発者ツールのドキュメントは、コアデータモデル、関係、原子的な概念、設定、実行方法から説明し始めるが、人は動く例を変更して結果を見ながらのほうがよく学べる
- 5,000語の“core concepts”説明より、複数のサンプルのほうが役立つことがある
- ユーザーはサンプルを見ながらツールの動作パターンを身につける
- 解決したい問題を持つ人は、十分に近い出発点を見つけられる
- 出発点が多いほど、必要なものに近いサンプルに出会える可能性が高まる
ユーザーを成功の落とし穴に押し込む
- プログラミングの基本状態は、ある種のエラーをひたすら修正し続けることに近い
- ユーザーはツールを使う時間の大半を、「何が動いていないのか」を把握することに費やしかねない
- 開発者がより早く成功すればそのツールを好きになるが、エラーに何度も阻まれるとツールのせいにしがち
- あらゆるエラーは、ユーザーをハッピーパスに戻す機会
- 例外メッセージにコードスニペットを入れる
- ユーザーが変なことをしそうなときに有用な警告を出す
- ユーザーが成功するために必要な対処を提示する
概念の過負荷を減らす
- ツールを使う前に理解しなければならない新しい概念は、それぞれが摩擦点になる
- 2〜3個の概念なら受け入れられても、8個の新概念を学ぼうとするユーザーは多くない
- Kubernetesは始める時点ですべての概念が必要なわけではないが、新しい概念が増えるほど負担は大きくなる
- 強力でありながら3〜5個の概念しか持たないフレームワークには優雅さがある
- Reactを初めて使うとき、1〜2時間後に概念的な坂を越えると、少数のシンプルなビルディングブロックで大きな構造を作れるという感覚を与えられる
- 目標は単に概念の数を減らすことではなく、作れる範囲を保ちながら、ユーザーが知る必要のある概念を減らすこと
- 優れたツールは、能力を保ったまま複雑さを90%減らせる
- 複雑さを90%減らし、能力を10%しか減らさないツールも悪くない
概念的ダック原則
- フレームワーク内に値を受け取って新しい値を計算する要素があるなら、“compute node”、“valuator”、“frobniscator”のような新しい名前より、functionと呼ぶほうがよい
- アヒルのように歩き、アヒルのように鳴くならアヒルである可能性が高い、という原則は概念設計にも適用できる
- 微妙な違いがあったり値がキャッシュされたりしても、functionに十分近いならfunctionと呼べる
- 既存の用語を使えば、ユーザーがすでに持っているメンタルモデルにつながるため、説明すべき量を大きく減らせる
プログラム可能にする
- ユーザーはコードベースで予想外のことを行い、フレームワーク要素をfor-loopの中、関数の中、別の構造の中に入れられる
- だからフレームワークのほぼすべてはプログラム可能であるべき
- 関連する設計の方向性は互いにつながっている
- CLIを介さず、コードから直接呼び出せるようにする
- 設定ファイルを減らし、SDKやAPIに置き換える
- 1つしか作れないようにせず、パラメータ化してn個作れるようにする
- こうした設計は、ユーザーが新しいユースケースを発見するきっかけになりうる
- フレームワークの上で「ハック」したい欲求を活用すれば、多少の混乱があっても予想外の発見につながることがある
マジック、デフォルト値、シンタックスシュガーは慎重に扱うべき
- クラウドでJupyter notebookを実行する
run_notebook関数があり、ユーザーがどのコンテナイメージを使うか指定しなければならないとする
- ありうる選択肢はいくつかある
image=...引数を常に必須にする
- 大半のデータサイエンスライブラリが入ったデフォルトイメージを用意し、ユーザーがオーバーライドできるようにする
- セル内のコードを調べ、必要な依存関係に応じて「マジック」方式でイメージを選ぶ
- マジック方式に加えて、ユーザーが特定のイメージを選べるようにする
- 入力量を減らし、最も広いユースケースを支えるには、最後の選択肢がよさそうに見えるかもしれない
- しかし、最初の選択肢を除けば問題が残る
- マジックはいくつかの状況で壊れる
- デフォルト値に依存したコードを読むユーザーは、カスタマイズ可能性に気づかないかもしれない
- デフォルト値が97%以上当てはまり、マジックが99%以上正しく機能するレベルでないなら、非常に慎重であるべき
- コーディングはゴルフではなく、ツール提供者の仕事はユーザーが書くコード量を最小化することだけではない
- Perlは短いコードに強く最適化されていたが、プログラムが特殊文字の羅列のように見えることがあり、Pythonはコードが50%長くても読みやすく理解しやすかった
- 人はコードを書くより10倍多く読むので、読みやすさが重要
- シンタックスシュガーも同じ基準で見るべき
- よくあるユースケースのために特別な構文を入れたくなることはある
- しかし一貫性を損ね、カスタマイズ方法をわかりにくくすることがある
- シンタックスシュガーが99%以上当てはまらないなら、導入しないほうがよいかもしれない
初めて使う人のための設計原則
- 人間のためのコードを書くには、なお多くの設計課題が残っている
- ほとんどは不変であるべきだが、すべてではない
- スキャフォールディング、つまりコード生成を避ける
- フィードバックループを非常に速くする
- ユーザーが廃止予定機能に簡単に対応できるようにする
- ドキュメントやサンプル内のコードスニペットに自動テストを使う
- 最初のユーザー体験を設計する仕事は、ポップソングを作ることに似ている
- プロデューサーは曲を千回聴いても、999回目に、初めて聴く人にはどう聞こえるかを想像しなければならない
- 開発者ツールでも、繰り返し作ってきた人が初めて使うユーザーの体験を想像するのは非常に難しい
1件のコメント
Hacker News の意見
学び方は人によって違う。私は例に入る前に、まず核心となる概念が必要だ。核心となる概念がごく単純でない場合はなおさらだ
多くのチュートリアルは、手取り足取りレゴを組み立てるやり方に似ている。「ここにレゴのピースがあるので、私がおもちゃのプロジェクトを作るのについてくれば、一日の終わりにはレゴができるようになる」という具合だ
私にはこのやり方はあまり合わない。判断がどのように、なぜ下されるのかを知りたいし、著者の視点から見たい。レゴのピース一つひとつがどんな感触なのか、互いにどうつながるのか、特定の設計にどうたどり着くのかを知りたい
最低限の高レベルな概念説明なしにチュートリアルについていくのは、本来そうする必要がないはずのものをリバースエンジニアリングしているように感じる。新しいライブラリやフレームワークを見るときは、紹介記事を読み、「始め方」のコード例は飛ばすことが多い。たいてい「上級」セクションのほうが概念の議論が多いのでそこから見て、次に API リファレンスで重要なインターフェースを把握し、最後にチュートリアル序盤の基本的なコード例に戻る
最近は、とにかく飛び込んで例にすぐ取り組むことがずっと多くなり、生産性も高くなったと感じている。ある程度は信頼の問題だ。質の高いソフトウェアを作った人たちは、一般的なユースケースでは内部を深く掘り下げなくてもインターフェースを理解しやすくするよう、十分に考えているはずだと信じることだ
もちろん、より深く入らざるを得ない障害物にはよく出会う。だが、表面的な印象だけでもうまく乗り越えられた別の10件があったからこそ、そういう状況が生じる。だから実際に深掘りするときも、たいてい時間の無駄ではないと考えている
こうしたツールは、特定のフォルダ構成、テンプレートファイル、事前設定済みのツール群を作り出す。生成されたファイルが何をしているのか、なぜそう作られたのかを高いレベルですぐに理解できなければ、理解できない魔法が多すぎて落ち着かない
新しいものが入ってくるたびに、すでに知っている概念と結びつけてその目的を説明してくれる高レベルな紹介が必要だ。少なくとも、そのブラックボックスの主なインターフェースを大まかにでも理解するまでは、魔法のようなブラックボックスを扱うのは気が進まない。たとえば create-react-app を最初から学ぶなら、すぐに Babel や ESLint のように、それが設定したツールの目的を調べ始めていただろう
数年後、実用的で良い例をたくさん見てから、ようやく概念が何を言っているのか理解できた。その気づきの後で、学習方法を磨いた
まず核心となる概念をざっと見て、その概念がなぜ必要なのか理解できるまで複数の例を試し、その後、素朴な例から抜け落ちている境界ケースをなくすために、核心となる概念を念入りに読む
ただし、例から始めるやり方は、良い API 設計の助けになると思う。API を「核心となる概念優先」で設計すると、結局その核心となる概念を理解してからでないと使えない API になりがちで、たまにしか使わないユーザーにはよくない
ハッカー流らしく、引用はなかった。教育学は少ししか見ていないが、デューイとピアジェの経験心理学から現代の原理を引き出してきた、巨大で成熟した学問分野だ。ブログ記事一本どころか、ブログ記事の一節で扱える範囲をはるかに超えて語るべきことがある
最大の問題は、指摘されているように人によって違うということだ。次に大きな問題は、その違いがなぜ生じるのか、時間が経ってもどれほど安定しているのかさえ、確実には分かっていないことにある。記事自体はよく書けており、特定の教育戦略の実用性をうまく掘り下げているが、もう少し謙虚さがあればと思う
2週間もしないうちに似たような記事があった: https://news.ycombinator.com/item?id=41566097
人のために文章を書くことは、結局のところ2つのスキル、共感と文章力に集約される。
少しコードを書くことと、アプリケーションやプロダクトを書くことの間には大きな違いがある。この記事も、少し露骨でないだけで結局その話をしている。共感が重要なのは、自己中心性と外部志向性の違いを生むからだ。
自己中心的な開発者は主に、簡単さ、便利さ、コード上の虚栄、その他の主観的な基準に関心を持つ。結局、自分の伝達努力だけを考える。外部志向の開発者は、主にアーキテクチャとドキュメント化に関心を持つ。成功は、他の人々が自分の成果物をどう受け取るかにかかっていると考えるからだ。
単純さは簡単さより重要だ。外部志向の開発者は他人の心を読めず、何を簡単だと感じるかは分からないが、手順の数を減らし、コードを小さく保つ方法は分かるからだ。
プロダクト全体の観点でアプリケーションを書くことは、脳の中ではエッセイ、記事、本を書くことと変わらない。核心は組織化と機能だ。コードは後から来るもので、ページ上の言葉のようなものだ。コード片だけを書く人は、すべてを1つにまとめる高次の組織化スキルを身につけられない。
だからフレームワークがとても嫌いだ。フレームワークは、開発者が独創的なソフトウェアを書くために必要な練習を奪い、その結果、組織化スキルを伸ばせなくする。当人には見えないが、見える人にはものすごく明白な大きな隔たりだ。
しかし他の人たちは今度は彼らの抽象化を学ばなければならず、その分、土台となる概念から遠ざかる。すると、フレームワークを超えるために必要な中核スキルを身につけるのがより難しくなり得る。Railsを学んだときにそう感じたし、結局、あまりに多くのことを隠していると気づいて捨て、最初からやってみることになった。
これがまったく別のスキルだという点は、目を開かれる気づきだ。いわば今や「既知の未知」になった。
上司に首を絞められている状況、あるいは午前2時に運用問題を直している人に、このコードはどう見えるだろうか? その答えが実際に必要になるまでは、それがどれほど価値があるかは分からない。そして必要になった瞬間、その答えに大金を払うことになる。そういうことができる人を見つけられるなら、の話だ。そういう人はまれだ。
「人間は中核概念ではなく例から学ぶ」という言葉には同意しない。揚げ足取りかもしれないが、すべての人間がそのように機能するわけではない。
一般から具体へ向かう方向を好む人たちは、すでに初等・中等教育でおおむね無視され、高等教育に行ってようやく合うようになり始めることがある。すでに十分疎外されているのだから、存在そのものまで否定する必要はない。
いつ何をすべきかのニュアンス、何は完全に同時に行うべきで、何はすぐ後に続けるべきなのかが理解できなかった。そのとき彼女の父親が、クラッチが実際に何をしているのか、車輪とエンジンの接続が両側にどんな影響を与えるのかを短く説明してくれた。
その瞬間すぐに理解でき、特定の状況で何をすべきか指示を聞く必要もなくなった。20分ほど後には、マニュアル車で最も難しいと言われる、後ろに傾いた坂道でハンドブレーキを使って発進し、車を走らせることができた。ある人たちにとっては、第一原理から仕組みを理解するほうがはるかに有用で、ソフトウェアエンジニアの中にはそういう「ある人たち」がかなり多いと思う。
例の中に驚く部分があれば、自分のモデルがまだ完全ではないという意味だ。あるいは例のほうが間違っているか。
「私たちが達成しようとしているのはこれで、これはこう動作し、私たちはこうする」ではなく、実務者に見えるのはいつも「私たちはこうする」だけだ。ほんの少し違うだけで、推論し、調整し、問題を解決できなくなる。
よく行われる作業にはある程度ドキュメントがあるにはあるが、たいてい古いか不完全だ。Wikiではないので誰でもいつでも直せるわけではなく、ドキュメントを直すには面倒な手続きを通らなければならないため、結局更新されない。考えてみると、軍隊にいた頃とかなり似ている。
今もDrizzle ORMを学ぼうと時間を取っていて、そういうことを経験している。最初に見つけた資料は全部「クエリ例6つ」で、なぜその構文を使うのか、他の選択肢は何なのかが分からずもどかしくなった。そういう資料は閉じて、ドキュメントの全ページを読んでから何かをする自分のやり方のほうがずっと楽だ。
今でもリアルタイムでできるかどうかは分からない。この方法はかなり多くの思考サイクルを使うので、今は文章を読んだり動画を止めたりして処理する速度のほうが合っている。
まだ理解していない人たちを、その場で教えることがしばしばあった。システムについての理論があれば、単純暗記をかろうじて超えた同級生では答えられない質問にも答えられる。
Code Complete の一文:「プログラミング作業の小さな部分は、コンピューターが読めるようにプログラムを書くことであり、より大きな部分は、ほかの人間が読めるように書くことだ。」733ページ
ほぼ 20年 にわたって記憶に残っている
Abelson と Sussman の Structure and Interpretation of Computer Programs 初版の序文に出てくる言葉で、Code Complete より10年先行している
自分が守ろうとしている格言だが、雇用主たちは不思議なことに、コンピューターが実行する部分にいつもこだわるようだ
少し脇道にそれるけれど、数日前に Unity のゲームを作っていて、IDE はこの10〜20年で本当にあまり進歩していないのではないかと思った
基本的な IntelliSense は確かにかなり良くなったが、それ以外のいくつかの細かな点を除けば、コーディングという概念全体は昔とほとんど同じに見える
最大の肯定的な変化はエディタの外にある。ライブラリやドキュメントにずっとアクセスしやすくなり、ユーザーの質問と回答が膨大に増え、ときどきそれらの回答を集めてもっともらしい答えを返す ChatGPT のような新しいツールも生まれた
しかし全体として、コードを書くという行為は停滞しているように思う。だから今はゲーム制作を少し止めて、いくつか実験している。新しい言語を作りたいわけではなく、可能な限りあらゆる雑務をコンピュータに渡して創作に集中したい
最初に試したいことは3つある。括弧や終端記号のような小さな言語仕様の細部を、なぜ自分が気にしなければならないのか、ツールが自動補完できないのか。private-public のアクセス連鎖や unsafe のような修飾子も、ツールが最も効率的な集合を自動で判断できないのか。相互に作用するメソッド5個ほどに集中しているとき、複数のウィンドウを開き、VS の水平・垂直スライダーと格闘せずに、すべてを1画面で見たい。HashSet を作ってから Dictionary や Tuple に変える必要があるなら、そのまま変えてくれて、判断が必要な箇所だけを見せて承認するか自分で直せるようにしてほしい。Unity では、メソッドやデータ集合をクリックして Burst Job とそれに付随する NativeData の集合へ変換するよう指示できてもよいと思う
だが結局はすべて抽象化であり、私たちは非常に愚かな機械にデータを計算させる命令を書いているだけだ
括弧や終端記号はツールが自動補完すればよいのではないかと言ったが、コンピュータは本当に単純なもので、プログラミング言語は頭の中の考えを伝える通路だ。そのような区切り記号は言語キーワードと同じくらい重要である。規則の一部だからだ。それらを自動補完するには、より多くの規則とより多くの区切り記号が必要になる
相互作用する複数のメソッドを1画面で見たいなら、Vim や Emacs、あるいは Pharo のような Smalltalk IDE がある
データ変換は Vim や Emacs のマクロでできる。だが真実は、データのエンコーディングが非常に重要だということだ。コンピュータにとってはすべてビットであり、私たちがそのビットに意味を与え、その意味に従って操作する規則を作ったのだ。ある規則集合から別の規則集合へ形を変えるには、さらに多くの規則が必要になる
ライブプログラミング環境を試してみることを勧める。Common Lisp の SLIME、Smalltalk の Pharo、JavaScript の Web インスペクタのようなものだ。陸地に船を置いて航海がどんな感じか想像するのではなく、海の真ん中にいる船の上で作業する感覚である
プログラミングで最も難しい部分は思考と学習だ。より速くタイプしても大きな助けにはならない
たとえば C プログラムを書くとき、「f」を「for (=; <=; ++) {;}」や好みのインデント形式に展開させることができた
現代のプログラミングエディタにも似たユーザー設定をサポートするものは多いが、残念ながら多くの場合、はるか昔より手順が複雑になっている
文法が冗長なプログラミング言語なら、エディタで最小限のキー入力でどんなプログラム構造でも素早く書けるテンプレートを、時間をかけて定義する必要があると思う
HashSet、Dictionary、Tuple のどれを使うかといった問題には性能への影響があり、抽象的にどれを使うべきかが常に明確とは限らない。Java のような明示的な言語、おそらく C# も同様に、メソッド呼び出しが別の型を受け取るようリファクタリングすることはできるだろう。そうすればメソッドを1つ変更し、その呼び出しをすべてリファクタリングすればよい
Gemini pro と ChatGPT o1 を試してみたが、どちらも Python と JavaScript のコーディングが本当に苦手だった。バグのあるコードを書き、1つのバグを直そうとして別のバグを入れることがよくある。どちらも要件を考えるより、答えを急いでいる感じだ。私たちが望む形で「心を読む」ことや、何が重要で何が重要でないかを理解するツールには、まだ少し距離があると思う
さらに悪くなり得る点は学習データだ。コードの大半は平均以下から平均程度のコーダーが作るため、こうしたツールは平均的なコーダーの思考パターンを採用することになる。最高品質のコードだけで学習させたとしても、大半のコーダーが正しくプロンプトを与えられるかは明確ではない。だから10〜20年コーディングしてきたなら、即席の魔法を期待する限り、ツールには常に少し失望する可能性がかなり高い
それでも非AIの静的解析ツールは昔から優れており、さらに良くなるだろう。そこに AI を加えれば、さらに改善できるかもしれない。ツールを、仕様を投げればまともな結果を返してくれる芸術家ではなく、自分が芸術家になるのを助けるものだと考えれば、素晴らしい体験ができると思う
エディタにもっとやってほしいことを AI に伝え、設定を手伝ってもらう実験も面白いかもしれない。プラグインには非AIツールが多い。生活スタイルに合うプラグインを選ぶのに大規模言語モデルを使うのが最も効率的かもしれない
https://haystackeditor.com/
自分ではまだ使っていないが、試してみるつもりだ
記事タイトルには議論の余地がある。コードは人間のためにだけ書かれるからだ。コンピュータには「コード」は必要なく、特に高水準コードはなおさら必要ない。コンピュータは機械語命令だけで十分だ
私たちがコードを書く理由は、機械語命令が人間にとって書くには難しすぎ、読むのはさらに難しいからだ
コードをコンピュータと相互作用する方法だと考えてはいけない。コードとは、人間が考えを形式化し、機械でさえ従えるほど曖昧さをなくすための方法である
先週書いて共有したブログ記事を利他的に宣伝する
Move Fast & Document Things [1]
哲学的な文章を書こうとしたのではなく、私たちの小さなチーム [2] が、自動化やAIではなく、深く難しいレビューを通じて、自分たちと互いのためのコードを書く文化をどう強制しているのか、その実践的なコツを共有しようとしたもの
他の組織でエンジニアリングリーダーをしている個人的な友人たちは皆、「うちもまったく同じことをしているが、君はそれを実際に文章にした」と言っていた。価値があったなら推薦をお願いしたい
[1] https://olshansky.substack.com/p/move-fast-and-document-thin...
[2] https://github.com/pokt-network/poktroll/graphs/contributors
「あまりに多くのプログラミング本やチュートリアルは『最初からレンガを1つずつ積んで家を建ててみよう』という式だが、私が欲しいのは『ここに動く家があるので、何かを変えて何が起きるか見てみよう』というもの」
私はそういうやり方でプログラミングを独学した。小さくて単純で、少し出来の悪いプログラムをうまく使うことに何年も費やした
後になって、より良いソフトウェア開発の仕事には向いていないことが分かった。ソフトウェア設計、プログラミング言語、コンピュータに関する基礎知識がまったくなかったからだ。退屈なやり方で学ばなかったために、自分がどれほど多くを知らないかを面接会場を出ながら思い知らされたのは、謙虚にさせられる経験だった
常にマニュアル全体を読み、常に基礎を学ぶべき
私のコードはすべて人間のために書いている
その人間が自分であれ、数年後に私の意図を読み取らなければならない気の毒な誰かであれ同じだ
コードを書くこと自体は難しくないと思う。問題を包括的に推論し、他のステークホルダーと協力して最善の道を見つけて彼らを導き、新しい数学や業界慣習のような専門技術を学び、効率的なアルゴリズムを考案し、プログラムの構造とパターンが明確で優雅な境界を持つように伝える部分にこそ才能が表れる
結局のところ、多くはコミュニケーションと明確さにかかっている
この記事の大きな部分はドキュメント化に関するもので、4docモデルを参照していれば大いに役立ったはず: https://docs.divio.com/documentation-system/
基本的には、リファレンスドキュメントだけを提供するのではなく、使い方のドキュメントも提供せよ、ということだ。そしてそれはユーザーが通常、ドキュメント全体の中で最初に見たい部分なので、それを前面に出せという意味でもある
もちろん一般論としてそうであり、私はリファレンス資料へ直接行くほうだが、常にそうとは限らない
4docが万能の解決策や自然法則だという意味ではない。Hillel Wayneもここでその問題点をうまく扱っている: https://www.hillelwayne.com/post/problems-with-the-4doc-mode...