【個人開発】MySQLにCRUDできるノーコードアプリをRailsで作ってみた

個人開発で作ったサービス【[shareCRUD](https://sharecrud.com "shareCRUD")】を先日ベータ版にて公開しました。この記事は、個人開発でサービス作ってる・作りたいけど、事例を参考にしたい人向けに、開発したサービスのご紹介と、それを作るまでの経緯をまとめてみました。

# 作ったサービス【shareCRUD】

![sharecrud_demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172629/5ba8bf08-b9a8-f498-e65b-e259f8cdd492.gif)

**サイトはこちらです**→[https://sharecrud.com](https://sharecrud.com "shareCRUD")

アプリ化したいDB（MySQL）につなげて、必要な設定をすると、ブラウザからGUIでCRUD（登録・検索・更新・削除）できる機能が作れます。イメージとしては、phpMyAdminみたいな機能をノーコードで作れるサービスです。


## どんなシーンで役に立つか？

### 1. プロダクトの運営初期から「管理画面」が手に入る

例えば「toC向け」Webサービスの場合、初期の開発ではフロント向けに専念し、管理画面は作らず直接DBにつなげての運用も多いと思います。shareCRUDでDBを操作できるアプリを作れば、**開発コストをかけずに管理画面に似た機能が手に入るので、エンジニアでない方でもデータの管理が可能**になります。

### 2. 管理画面とshareCRUDの「二刀流」で、効率的に運用できる

ある程度成長したWebサービスでも、管理画面開発は運営上クリティカルな機能に限定し、一般的なデータの参照や更新はshareCRUDを使う「二刀流」にすることで、管理画面の開発コストを下げながら効率よくサービスを成長できます。

# アイデア出しから実装までの道のり
ここからは、個人開発ならではのエピソードも交えて、サービス開始までの経緯をまとめてみます。

## サービスの「管理画面」に感じていた課題

#### 開発途上のサービスの管理画面について

私は今回の開発以前にも、いくつかの個人開発をしてサービスを作ってきましたが、toC向けサービスはフロント向け機能のみ作り、管理画面は作らずDBを直接参照して対応していました。小規模のサービスでも、非エンジニアの方が運営するには、DB直接参照というわけにも行かないので、簡易な管理ツールを作るか、開発元のエンジニアにメンテを依頼もあると思われます。

過去にActiveAdminなどの利用もしましたが、導入にも環境構築にもそれなりにコストがかかり、私個人としてはあまり好みではありませんでした（一個人の意見です）

小規模で開発途上のサービスの場合、一定量は**管理画面がないのでは**と予想しています。

#### 成長したサービスの管理画面について

以前お世話になった自社サービスを運営している会社では、サービスは成長しているので管理画面も存在し、非エンジニアの方がオペレーションを担っています。しかし、管理画面ですべて対応はできておらず、ちょいちょいエンジニアに依頼が入ってデータメンテをしていました。**依頼にすぐ対応ができなかったり、作業が中断したりで、もどかしい**部分がありました。

## 普段の業務から得た着想

一方で、私は普段フリーで受託開発をしていて、業務システムや管理画面をRailsで作ることが多いです。業務・管理画面系のシステムは共通化できる部分が多いので、**自分なりにフレームワーク化**していました。モデリングした内容をフレームワークに落とし込むと、ベースとなるシステムができます。落とし込むと言っても、案件の都度、**決まった流れのコードを手動で書いてたので、これを自動化**できれば、管理画面に代替する機能をノーコードで作れるかもと考えました。

## ノーコードに対する不信感と向き合う

実は「ノーコード」のサービスにはあまり良いイメージがありませんでした。「エンジニアいらずで、なんでも簡単につくれる」といった謳い方をしているサービスが多いように感じ、違和感を感じました。これからノーコードを作ろうとしているくせに、ノーコードツールにあまりよいイメージがないのはなんとも矛盾していますね:sweat_smile:

そこで、自分がノーコードを作るのなら、この点にきちんと向き合おうと思いました。具体的には

- なんでもできそうなアプリではなく、**CRUDが主目的**なことを明確にする
- 基盤をエンジニアが設定をして、運営者がエンドユーザーになる使い方を想定

といった点です。以上から「**DBにCRUDできるアプリをノーコードで生成するプラットフォーム作り**」とのアイデアで実装を進めることとしました。

# 技術的な実現方法を検討

ここからは技術調査です。私には**ノーコードツールの開発経験は無かった**ので、まず実現方法から考えました。といっても、このタイミングで一から新たな技術を学ぶというより、その時点で自分ができることを応用できればと思いました。

## RailsのScaffoldから着想を得て、Thorを使うことにした

Railsには、コマンドから雛形となるソースコードを生成できる機能（**ジェネレータ**）があります。`scaffold`ではベースとなるソースコードを生成しているので、**この機能を応用してコードを自動生成**すれば、ノーコードのエンジンが作れると考えました。

Railsでジェネレータは普段から使っていましたが、具体的にどのような仕組みで実現しているか把握していませんでした。調査すると「Thor」というツールの上に成り立っていることを知りました。

https://github.com/rails/thor

以下のドキュメントに大変お世話になりました。

https://railsguides.jp/generators.html

また、Rails自体のGenerators部分のコードも大変参考になりました。

https://github.com/rails/rails/tree/main/railties/lib/rails/generators

## ソースコード生成までのフローをまとめる

Thorを使って生成する部分はイメージできたので、システムの具体的な設計をしました。以下のフローで実現を図りました。

#### ① DBの接続情報を入力して、テーブル定義などを読み取る

主に以下の情報を取得しています。

- テーブルとフィールド名、型の取得
- 主キーやNotNull、一意制約、AUTO INCREMENTなどの取得
- 他テーブルとの外部キー、など

#### ② 読み取ったテーブル定義をもとに、アプリの設定をする

画面から以下のような設定をしてもらいます。

- テーブルに対する設定
  - フィールドのlocale（和名）を設定
  - 表示フォーマットや単位の定義
  - バリデーションの追加（文字数や最大・最小値など）
  - enumなどの区分値に対する表示名の定義、など
- アプリに対する設定
  - 検索条件の定義
  - 一覧や詳細画面に表示するフィールド、表示順序
  - 登録フォームのパーツ選択（ラジオボタン or ドロップダウンなど）
  - リレーショナル（1:n）への、親・子データの扱い、など

#### ③ ②で登録した設定内容をもとに、ビルド処理でソースコードを生成する

Thorを使って各ファイルを作っていきます。一例ですが、モデルのファイルを生成する場合、以下のようにしています。
※説明用にアレンジしています。

```erb:model.rb.tt
<%-# このファイルをテンプレートにして、テーブルごとにmodelファイルを作成しています -%>
<%-# @modelは、上記①②で設定したテーブル情報を保持しています -%>

class <%= @model.name %> < SharecrudAppModelBase
  self.primary_key = '<%= @model.pk_column.name %>'
<%- @model.columns.select { |c| c.kind_enum? }.each do |column| -%>
  <%-# コードの文字列が返ってくるメソッドを定義してます-%>
  <%= column.enum_code -%>
  <%-# ↑例えば enum gender: { man: 1, woman: 2 } 的なコードが挿入されます -%>
<%- end -%>
<%- @model.columns.select{ |c| c.unique? }.each do |unique_column| -%>
  validates :<%= unique_column.name -%>, uniqueness: true
<%- end -%>
<%- @model.columns.select{ |c| c.kind_number? }.each do |c| -%>
  <%= c.number_validates_code -%>
<%- end -%>
  ...
end
```

```ruby:model_generator.rb
### 上記テンプレートを呼び出すgeneratorを定義します
module Sharecrud
  class ModelGenerator < Rails::Generators::NamedBase
    def setup
      @model = Model.includes(:columns).find(name.to_i)
    end
    
    def create_model_file
      base_path = "tmp/product/#{@model.project_code}/app/models"
      model_file_path = File.join(base_path, "#{@model.name.underscore}.rb")
      template "model.rb", model_file_path, encoding: :utf8
    end
    
    ...
  end
end
```

そして、ビルド処理の中で

```ruby
Rails::Generators.invoke('sharecrud:model',
                         [model.id.to_s],
                         destination_root: Rails.root)
```

といった形でGeneratorをキックして、テーブルごとにModelのファイルを生成しています。
同様な仕組みで、他にもアプリごとにViewやControllerなどを生成しています。

# ノーコード（自動化）の対象をどこまでとするか

ソースコードは前述の仕組みでノーコード化できそうですが、生成したコードを動かす「環境」について、自動化の対象に含めるか迷いました。当初は、新規ユーザーが利用する際は、まずお問い合わせをもらい、私が手動で環境を構築してから利用開始のフローを計画していました。個人開発でリソースも限られることから、まずはソースコード自動生成に重点を置き、その他は当面手動でもよいかなと。

しかし、企業が運営するプロダクトであればまだしも、**個人開発みたいなプロダクトに対して、機能を試すためにお問い合わせまで要するというのは、ユーザーにとって相当なハードル**となり、結果誰も使ってくれないサービスになると考えました。

そこで、アカウント登録したら、すぐにアプリを使えるフローを目指しました。開発に要する作業量はかなり増えましたが、この実現は必須だったと感じています。個人開発だからやらなくてよいことと、**個人開発だからこそやらなきゃいけないこと**、この切り分けは重要だと感じました。

## Dockerコンテナを使って環境構築を自動化

いくつかの実現方法を試し、最終的にはアプリごとにDockerコンテナをポコポコ立ち上げるようにしました。アプリのベースとなるイメージを一つ作成し、生成したソースコードをアプリ専有のコンテナに `COPY` してから起動し、リバースプロキシを窓口にしてサブドメインごとにコンテナに振り分けています。

また、気軽に試せるようにしたことで「少し試して終わる」アプリが増えることが予想されます。何も対策をしないと、使われなくなったアプリでサーバーのリソースを使い切ってしまうため、**一定期間リクエストが無いアプリは自動でコンテナを停止し、改めてリクエストが来た際にコンテナを自動起動**するようにしました。

::: note
一つのサーバー上にコンテナをたくさん立ち上げる方式のため、今後サービスがスケールしたら課題が残りますが、将来そんな嬉しい事象が見えてきたら、その時検討しようと思っています。
:::

## 最終的にRailsのプロジェクトは3つになった

以上の機能を実現するために、Railsのプロジェクトを3つにわけました。

- エンジン用プロジェクト
  - アプリの設定入力画面
  - ビルド・デプロイ機能
- アプリ用テンプレートプロジェクト
  - アプリの共通機能などを管理
  - プロジェクトをDockerイメージにして、アプリごとにコンテナを起動する
  - エンジン用プロジェクトで生成したソースコードをアタッチする
- リクエスト振り分け用プロジェクト
  - リクエストのサブドメインから、振り分け先のアプリコンテナを特定する
  - コンテナが停止していたら起動する
  - 一定期間リクエストがないコンテナを停止する

# ドキュメントとチュートリアル用のコンテンツ作成

サービス運営に向けて、LPとドキュメント用サイトを作りました。LPは多くの個人開発でも作ると思いますが、ツール系のサービスなので、ドキュメントサイトも必要だと考えました。せっかく興味をもってくれたのに、使い方がわからずに離脱してしまうユーザーを少しでも減らせたらと思います。まだまだコンテンツ量が少ないですが、今後拡充させていければと思っています。

[**https://docs.sharecrud.com**](https://docs.sharecrud.com)

このドキュメントには、チュートリアルとサンプルDBも用意しました。サービスの特性上、ユーザーのDBに接続する必要がありますが、仮に試用であっても、初見のサービスを自分のDBにつなげることには抵抗があると予想します。そこで、チュートリアルでサンプルDBも公開し、そこに接続して試した後であれば、自分のDBに接続するハードルを下げられるのではないかと考えています。

## ドキュメントサイトにはVuePress + AWS Amplifyを採用

ドキュメントサイトを作る際、以下の条件にマッチするサービス／ツールを探しました。

- マークダウンで記述できる
- ドキュメントとして使えるUI
- 動作環境も簡単に作れる

当初は WordPress や [GitBook](https://www.gitbook.com/) なども検討しましたが、[VuePress](https://vuepress.vuejs.org/) が今回のニーズに一番あってると判断しました。また、環境構築は [AWS Amplify](https://aws.amazon.com/jp/amplify/) で速攻ででき、感動しました。このあたりは後日別記事でまとめられたらと思います。

# ベータ版の開始 〜 サービスの今後

以上の紆余曲折を経て、先日やっとベータ版として公開することができました。文章にまとめるとスムーズに行ったような雰囲気がありますが、実際は苦難の連続でした。本業が忙しいために個人開発に時間を割けない時期もあったとはいえ、当初の着想からトータルで1年くらい要してしまいました。ずいぶんと時間がかかってしまい、リーン開発でいう「MVPを作ってすぐに検証」の定石からは道を外しまくってます。途中何度も辞めようと思いました。

ベータ版で少しでも多くの方にお試しいただき、目処が立ったタイミングで正式リリースの流れを計画しています。これからは、このサービスのプロモーションにも力を入れていこうと思っています。

# おまけ - 周りの意見を聞くために、Zoomインタビューをしてみた

個人開発は孤独です。一人で思考していると、どんどん煮詰まって悪循環に陥るときがあります。そんな時に、一人で考えていては単なる想像の世界を抜け出せないと思い、**他のエンジニアの方の意見を聞いてみたい**と感じました。

そこでクラウドソーシングの「ランサーズ」を使って、エンジニアの方にお声掛けし、有償でインタビューをさせてもらいました。私自身インタビューの経験はなかったのですが、コロナ禍の影響で「Zoomを使ってミーティングする」ことが当たり前になっていたので、検索したエンジニアの方に依頼すると、結構な確率で快諾してくれました（このときインタビューさせてもらったエンジニアの方々には大変感謝しております。）

もちろんインタビューをして、それだけですぐに答えが見つかるほど甘くはありません。ましてや私みたいな素人では、インタビューしても何も引き出せないのではと懸念しましたが、他の方と話すことで、以下のメリットがありました。

- 思考を整理できたので、気持ちが前向きになった
- 会話の流れで、見落としていた発想を得られた

Zoom等でインタビューして、他の人に話したり意見を聞くことは、手軽に大きな効果を得られる場合もありそうです。個人開発では一つの有効な手段かもしれません。

# おわりに

長文にお付き合いいただき、ありがとうございました！

現状の反省点としては、個人開発なのに選択したテーマが重く、開発に時間がかかりすぎてしまった点です。個人開発では、アイデアもさることながら、実現に要するボリュームも見極める必要がありそうです。長くても数ヶ月でリリースまでたどり着くほうが、精神的にも健全です。

この記事を見て、個人開発の参考やモチベーション維持に少しでも貢献できたらとても嬉しいです。
最後に、shareCRUDを是非お試しください！