Posted at

RubyでECを作ろうとしている

More than 1 year has passed since last update.


言いたいこと


  • 既存のECのプラットフォームが微妙。

  • 自分で作ったほうがコスト安そう


    • というよりMagento2とか学習コスト高い

    • あとからくる人間に学ばせるのも大変



  • せっかくだからいろいろ思うところを実装したい

  • 作りたいから作る(使ってないけどActiveRecordとかでできるってことは聞かない


  • https://github.com/S2/ec で作っているけれどリポジトリ名とか適当で変わることあり。


動機

既存のECプラットフォームは割と微妙。

対象に考えているのは

* Magento2

* EC-CUBE

の二つ。

嫌な点は、いろいろだけども、それらのプロダクトがダメということだけでなく、もともと立て付けの起因するものも多い。

EC-Cubeはあんまり使ってないので不当なFUDになりそうなので控えて、Magento2の嫌なところを書いていきたい


立て付けもあって仕方ないかなと思うところ


  • PHP

  • EAVの絡みで大変バックアップがとりづらい。EAVテーブルの主キーをキー名ではなく、AUTO_INCREMENTな数値で持っているため、本体のデプロイを変更する(例えばモジュールの読み込み順を変える)などしたときに、EAVのIDが変わって大変なことになる。

  • 画像類のバックアップ、移行などが大変

  • DDL書くのにPHPで書かされる。全体的にSQLを知らない人を対象にしている風がある。


プロダクトの問題


  • プロダクト全体が大きい


    • デザインパターンとかを駆使して、コードの統一をしようとしているのはわかる。

    • 実際のクエリがどこで作られてどんなものが実行されているか、などが隠蔽されていて追いづらい

    • XMLも同様に何が読まれていて、今どのXML要素が実行されているのかわかりづらい

    • DIは便利ではある。遅いけど。



  • XMLで書くのが煩雑な上にXMLで書かれたものの解釈が狭く自由度が低い

  • 1+n問題が置きまくっていて重い。管理画面もフロントも。

  • アプリケーションレイヤーで重い問題を改善しないでVarnishを推奨してくる

  • eav_attributeっていうアンチパターンの権化みたいなやつが幅を利かせてる

  • テーブル定義にまとまりがない。外部キーが貼ってあったりなかったり、あとカラム名にも統一感がない。

  • XMLとかEAVとかプロダクトの大きさとかで学習コストがすごく高い。それなりにできるエンジニアで一月くらいはかかりそう(てきとう

といったところ。


新しく作るものと要件

EC、コア部分は本来小さく作れる感触がある。

商品、顧客、カート、受注管理、配送管理などを作れればよいかと思う。

速度的なチューニング類は売り上げに直結するので行いたいところ。

アプリケーション側ではある程度適切なクエリを書くようにしておく。

それ以上のチューニングはNginxとかCroudfrontで行えるのではないかと思う。


取り入れたい機構


  • Rubyで作る


    • 書いてたら楽しくなった

    • 割と読み書きできる人が多いし平易

    • 本当はClojureとかでやりたかったけどハードル高い…



  • テーブル定義を書いたら大体アプリケーションサーバは出来上がってほしい

  • テーブル定義だけでは例えばバリデーションルールとか、列の和名などは作れないのでそういうテーブルは作る必要はありそう

  • 設定類は変にYAMLとかに出すよりDB持たせる方針


    • フロント側を書いていないけど、YAMLとかになる感じもちょっとある



  • サーバサイドレンダリングとフロントJSを合わせて頑張る、という方針よりも、JS、CSS、HTMLを統合的に扱えるのでフロントに任せたほうがシンプルになりそう

  • SPAではないので各種ページは必要。


テーブル定義からアプリケーションサーバ

構想の域はまだ出ていないが、考えはある。

いわゆるモデル的な層のみを考えている。

またDBに起因しないモデルみたいなもの、Redis等のRDBMS以外のDBは想定していない。


テーブル定義上のパターンについて

RDBMSなのでテーブル間の関係性というものを考える必要があるが、それらはいくつかのパターンに分けられるかと思う。

ここで書く内容は、自分のテーブルが他のテーブルに依存しているか、ということに焦点を当てて書いていて、依存されているかどうかは考えていない。


  • 単独のテーブル

  • 一つのテーブルを親に持ち、親にたいして複数のレコードを持ち、列ごとに固有のIDを持つテーブル(一般的な1:多かと思う)

  • 一つのテーブルを親に持ち、親にたいして複数のレコードを持ち、列ごとに固有のIDを持たないテーブル(1:多なのだけども、個々の列を操作しない、ということ)

  • 一つのテーブルを親に持ち、親にたいしてふくすう単数のレコードを持ち、親への外部キーがPrimaryKeyになる(1:0もしくは1:1)

  • 複数のテーブルを親に持ち、そのうちのいくつか一つ以上の親テーブルのくみあわせでPrimaryKeyになるテーブル

  • 複数のテーブルを親に持ち、独自にAUTO_INCREMENTなPrimaryKeyに持つテーブル

親への依存についてはこの程度のパターンではないかと思う。まあ増えればその際にまた処理を書けばよい。


入力処理

思うに単独のテーブルへの入力のみで足りることはないかと思う。

例えば顧客と複数ある顧客の配送住所、みたいなものを考えたときに、


  • 顧客情報のみを入力して、配送住所は入れない

  • 顧客情報を入力して、合わせて配送住所も入力する

  • 顧客情報は入っているので、配送住所のみを入れる

    といったパターンが考えられる。

    一番目と三番目はそれぞれのテーブルへのINSERT文を実行すればよいが、二番目はセットで処理が行われないといけない。

    その処理は


  • 顧客テーブルへINSERT


  • 顧客テーブルの主キーを取得して、それを持たせた状態で子テーブルのINSERT処理を実行させる

    といった形になる。

    このあたりを抽象化すると、それぞれのテーブルへの適切な入力ルール(これは上記のテーブルパターンによって決まる)を作ることと、親テーブルは子テーブルへの参照を保持する必要があるということになる。

    子のテーブルは孫への参照を保持しておけばよくて、再帰構造で作れば問題なく実装できるイメージがある。



出力

上記で子テーブル、孫テーブルへの方向は再帰的に持っているので、問題なさそう。要はSELECT文を発行して、子方向にも同様に発行させて、結果を決まったフォーマットでオブジェクト化すればよい。


更新

そのうち書く。


削除

ログとかではなくて、子になる要素はそこまで多くはならないはずなのでON DELETE CASCADEで対応しておけば良さそう。

問題になってから考えよう。


フロントよりの話

ディスパッチャは面倒なのでもう決まった処理をさせて、あとはフロントで頑張る方針。まだ手も付けていないのでその辺は追々…