ソフトウェアのインターフェースについて考える
レゴのたとえ
編み物とレゴ
どこで読んだっけこれmiyamonz.icon
ここだ
レゴのインターフェース
あの粒粒の面
あれさえ同じなら、任意のブロック同士が、その面で繋げられる
境界は面で、ブロックの形状は自由である
レゴ以外の似たもの
レゴインスパイアなブロックのおもちゃもいくつかあった
マインクラフトもそうっぽい
床に貼るタイルマット
規格化されたコンテナ?スタックできる容器
畳、ツーバイフォー
reducer
(state, action) -> state
state: 状態の変化を、関数で表現する
mutableなstateを、変化前と変化後を関数で表現する
actionによって、その変化のパターンを分岐する
jsの場合は、actions.reduce(reducer, initialStatus)このように書けたりする
トランスフォームにおける行列
translate, rotate, scaleといったものを行列として、単なる行列のスタックとして表現する
これは、型としてはreducerとほぼ一緒
群はその演算でfoldできるからreducerになるというだけか
群、すなわちいい感じの法則が成立する二項演算があるもの
二項演算ってのがよい A x A -> A
ただし、これは3次元の変換がそういう性質を持つよね、ということであり、
自ら設計して群を為す集合などを作れるかと言うとわからん
たとえばcosenseのページを、有向グラフとみなしてなにか数学的な性質から攻めることはできるだろうか?
vimのテキストオブジェクトとオペレータ
ciw
change、 inner word
動詞と範囲を入力して、編集する
操作、対象(対象の内外の補足 inner)といった指定
これはいいなとは思う
他の例と違って、対象と操作という非対称な命令になっているのは特徴的
ただ、他でこれの実践はあまり見ないか?
vscode であまりやらない。vimの拡張をいれるくらい
ファイル選択やテキスト選択に特殊な命令をするパターンがない気がする
blender
blenderの編集もややvim的な側面があると思う
adobeのレイヤーとマスク
レイヤーによって、複数のフレームを重ねて最終出力を作る
階層構造も取れる
マスクという概念を入れる
マスクはレイヤーの一種で、階層構造に入れることで、そのツリー内の範囲を狭めて親に結果を伝える
この階層内で、色調の調整などをする
↑ここらへんは、対象と操作、主語と述語、というペアのように見なせる
対象、というものがあるということは、対象全体は、なにか空間的な広がりがあるもので、その部分を対象と呼べる
テキストエディタならバッファとテキストの一部分
photoshopなら最終的な成果物の画像と、レイヤー
そもそも、概念がなんらかのcomposableなもの、とみなす、というところがある
photoshopの例だと、レイヤーというのは階層構造なので珍しくないが
マスクという概念が優れていた
マスク自体はシンプルだが、レイヤー概念と相性がよかった
宣言的UI
コンポーネントという単位
これは、htmlという階層構造、木構造を、コンポーネントの集合、結合で表現できるという視点がある
プログラムを関数で組み合わせてつくるという行為を、木構造でも同じようにそのまま実現できてる
関数オブジェクト
lispがやりはじめた、で合ってる?
関数自体をオブジェクトとして変数に持ってなんかやること
処理を抽象化したり、注入できる
pipe
標準入出力という行指向ストリーム
コマンドをパイプで繋げていく
A | B | C
なにか全体としてストリーム処理をする際、それを個別のコマンドに分ける
個別のコマンドもまたストリームである
個別のコマンドは、ストリームを流す以外のやりとりをしない
なんらかのデータは、行単位の集合であり、データの加工を行単位で行える場合に有効
スクリプト言語だと、mapとかfilterとか、配列に対する関数になる
関数型言語の知見を学ぶと良い
middleware
入力に対して出力を返すような概念
request と responseとか
2つのラインをまとめて、ミドルウェアという単位を作る
pipeと似ているが、処理の流れが折返している点が違う
→→→→↓
←←←←
ここまでの話をまとめると
作りたいものは、なんらかの部分の集合である、という前提がある
その部分を切断する方法、切断面という境界を見出す。(インターフェースは訳せば境界という意味だ)
切断された部分がどういう中身、形状?なのかを考える
その型を考えると、部分と部分の結合方法の演算が見えるはずだ
結合した結果も、同じ型になっているはず
数学で言うところの「演算について閉じている」というような性質になっていると良い
切断ができるということは、要素をプラガブルにできる
変更、修正したい箇所が、切断面を境界として、外部に影響しないで済む
パターンを分類すると
主語述語パターン
vim,
流れを分割するパターン
reducer
pipe
middleware
どちらにも入りそう
adobeのレイヤーとマスク
他のパターンがありそうだ
この2つも、厳密に言うと概念が直交してるわけではない
主語述語パターンも、その操作の組み合わせでスタックされ、reducerやpipe的な認識ができる
その操作が、ユーザ入力なのか、コンピュータ上のデータとして扱うのか、といったスコープや粒度の差かも
「流れ」というのは絶対に存在して、
主語述語パターンは、流れをゆっくりしたときの、流れの中の具体的な動作に焦点をしぼっている、と見れる
プラグイン的な話
event hook
さまざまなプラグインというのは、元のなんらかのフレームワークに対して、固有のイベントが有り、それにhookする形で処理を呼び出させる
rollupとか
そもそも、フレームワークがそういう仕組というパターンもある
これは、フレームワークのアーキテクチャ変更に弱い
凝集性を高めにくい、といった傾向を感じる
reactがclassをやめて関数コンポーネントに方針を変えたのもこれが理由だろう
が、めちゃ悪い概念というほどのものでもない
hooks
reactのhooks
これは、「レンダリング」というイベントを単一の特殊なイベントとみなした上でのevent hookのパターンの一種と言える
eventが単一なので、eventが複数あるがゆえのカオスは生じにくい
単一であるのでストリームとしてみなせて、メモ化したり、別のhookを呼んだり、composabilityが高い
ストリームとみなして、その内部では外部のことはあんまり気にしない点はpipeと似てる
ただし、callback関数などを露出してなんかしたりはするから、pipeのほうが簡素である
後で呼ぶべき処理を、setupの返り値として関数を渡す
subscribeとunsubscribeが同じオブジェクトから生えてるよりも、何かと良い
syntaxや型レベル等でやるもの
pythonのwith,
JSで新しく入ろうとしてるusing
RustのDropトレイト
c++のdestructor
goのdefer
スコープ等で区切られて、勝手に呼ぶので、呼び忘れがない分の安全性がある
ただし、cleanupタイミングがスコープレベルでない場合は、関数を返すのが適切だろう
useEffectとか
ここまでは、ソフトウェアのインターフェースについてだった
なにか大きなものを作るための、個別のモジュール、それらの結合方法
composableな筋の良いモジュールをどうやって捉えるか、という考えだったのかも
一般的にいうと、インターフェースはもうちょっと違う概念をさしてそうだ
スマホのインターフェースとか
ユーザインタフェースか
ユーザとソフトのインターフェースで、
ここは結合対象?が
モジュールとモジュールじゃなくて、
ユーザとソフトウェア
みたいな感じで考えた方がいい
なので、結合による演算が閉じるべき的な話が通じない
ユーザ、という存在が固定であるがゆえに、考えるべきことが少しfixされる
しかし、そこは、ユーザについて考えるというより、ユーザが作りたいもの、ユーザが触るべきものについて考えるべきか?
よくわからんくなってきた
組織のインターフェース?
そこらへんも考えたい
万物は流転する
常に変化し続けるものを、構造で捉えるのは難しい
不変、普遍なものを見つけると良い
螺旋のように変化するものもある
このときは、周期で区切る
時間軸という絶対的な、変化の軸がある
ここに周期性が見いだせると、その周期で切ることでインターフェースを見いだせるかもしれない