早くこれになりたい。本当にそう思う。
SaaSは最終的には業界特有のビジネスロジック満載のAPI群とそれを駆動するDSLを駆使したプラグインの塊みたいになって、全体アーキテクチャが破綻しないかだけ注意深く日々パトロールしつつ、あとはBiz側の要望に合わせてプラグインを鼻歌混じりに作るだけみたいな状態を目指さないといけない
— 最速配信研究会山崎大輔 制約理論及び待ち行列理論による技術経営コンサルとエンジニア起業相談やってます (@yamaz) 2022年7月28日
ビジネスロジックのAPI群とそれを駆動するDSLを駆使したプラグインの塊というのは、こういう感じのYAMLが作られて、DSLで呼び出し順やパラメーターを指定すると、ビジネスロジック自体が生成され、あとはそれを適宜順番に流すみたいなやつをイメージしている。
func: print args: # argsは配列として記述 - Hello, World! - Goodbye!
import yaml # DSLから呼び出し可能な関数を列挙 func_dict = {'print': print} with open('hello1.yml') as yaml_file: dsl = yaml.load(yaml_file) if 'func' in dsl and 'args' in dsl: func_name = dsl['func'] if func_name in func_dict: func = func_dict[func_name] func(*dsl['args'])
見積を登録するという処理があったとすると、単純なDBへのUPSERT(明細型UIの場合、変更時に変更前の明細行が消えることがあるので、DELETE→INSERT)だけが関数として定義されているのがサーバーサイドの基本。ここで内部で色んなテーブルのUPDATEが走ってしまうとキツイので、イミュータブルなデータモデルにDB設計を可能な限り行う。状態の変更はテーブルのINSERTとDELETEで賄う。DB書き込みは単純なのが一番だ。在庫だけはどうしようもない。引当と出荷の変更が入ったら変えざるを得ない。
データを登録してから、色んな要望が出てくることは予想される。Slackに飛ばしたい、ワークフローを回したい、PDFを出力したい、送料を算出したい、Cubic Meterを元に総重量を出したい、任意のExcelで出力して委託倉庫にデータ投げたい、KintoneのようなPaaSのAPIを叩きたい等。これら一つ一つが 関数として定義されていて、多分それがビジネスロジックのAPI群のこと。モノの輸出入をする場合、運賃のベースレートとなるCBMが必要になることが多い。タンカーで運ぶ賃料が変わるので。
そのAPIを叩くタスクランナーとしてのDSLがあって、beforeUpsert
afterUpSert
みたいなタスクを定義して実行できると強そう。このタスクランナーを作るAPIが別途あって、それがFirestoreあたりにしれっと保存されている感じ。顧客サイドは管理画面でチェックをポチポチ、行を追加するだけでこの辺がカスタマイズできるとベストだな。
version: '3' tasks: beforeUpsert: calc_shipping_charge: - {{.ZIPCODE}} - {{.WEIGHT}} afterUpsert: webhook: - {{.WEBHOOK_URL}}
全テナントに共通でもつデータと、顧客属性に応じてカスタマイズして持つデータがある。設計としては以下のようになる。共通属性と可変属性、可変属性は属性のキーとタイプ、中身は属性情報に持つ。WordPressでよく見た構成だな。弱点としては、属性情報を保存するテーブルのカラムは文字列にしかできない点かな。1:1のJOIN。
TypeScriptであれば、必須情報と属性情報を型演算で和集合してそいつをPrismaに食わせることができるとコードはスッキリするが。
まぁ初回としてはこんなもんかな。1年かかるなこれ作り上げるのに、今の仕事を抱えながらだと...