管理ツール(CMS)を作る際にエンジニアとして心がけていること

Webサイトを開発する場合、大抵は**裏側で顧客やスタッフがコンテンツを入稿・管理するバックエンド管理ツール (CMS)の開発**を伴います。
Webサイトを作る際、UIはUIのプロやデザイナーに任せる必要がありますが、管理ツールは**UIも含めてエンジニア側で自由に作れる**ことも多くて、結構好きな開発分野の1つです。
長年にわたり色々なサービスの管理ツールを作ってきて、顧客からよくあるフィードバックを元に普段から意識していることをいくつかまとめてみます。(心がけているけど達成はまだまだです)

# 1. 説明書の要らないサイト作りを目指す

管理サイトを使いこなすのに説明書とにらめっこしないといけないのは導入のハードルが上がってしまいます。そこで、できる限り**説明書を見なくても使いこなせるサイト作り**を目指します。

* 「**この画面は何をするためのものなのか**」の説明を**長文になり過ぎない範囲で**きっちり書く。
* 手順が複雑なものや最初の導入部分のとっかかりが分かりにくいものは**ウィザードを用意**する。
* ほぼ全ての入力項目やボタンにそれを設定する/押下するとどうなるのかが分かる**ツールチップを表示**する。
* ユーザー目線で、完了までに何をして次に何をすれば良いのか、**全行程が見通しやすい画面構成**を考える。
* **怖くてボタンが押せない**、もしくは逆に**気軽にボタンを押してしまう**のを回避するため、この操作は**後で取り消せるのか**、**変更できるのか**、**最悪どうなってしまうのか**などの警告を表示する。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416295/c477cf5a-ffed-932b-172a-b9037a4b5454.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416295/34d05975-27e4-abc9-74f9-fc74001b2614.png)

# 2. 初心者と上級者両方に配慮する

初心者を意識してサイトを作ると色々と**冗長な作り**になって上級者にとっては億劫になってしまったり、**高度な設定ができなく**なってしまったりします。
一方で上級者を意識しすぎると、初心者には**とっかかりにくいサイト**になってしまいます。
基本的には両者はトレードオフになりやすいので両立するのは難しいのですが、できる限り**両方に配慮**した作りを心がけます。

初心者は大量の入力項目があったりすると面食らってしまいますが、

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416295/5a0a7211-7647-86fc-610a-03b40a3cd19a.png)

こんな感じで、高度な設定は別枠としてまとめたり、場合によってはアコーディオンUIにして隠したりして、「最低限品名とかの基本的なことだけ設定すればとりあえず簡単なデータ登録は行えるよ、後は追々必要になったら設定していけばいいよ」というのをアピールするなど、**初心者には基本的な部分しか目に入らないようにし**て、慣れてきたら「あ、こんな設定もあるんだ」と**徐々に色々な機能に自然に気づいていける**ような画面構成を意識すると良い気がします。

それと、上級者になればなるほど、「編集はエクセルとかでやるから一括ダウンロード、一括アップロード機能を用意して欲しい」と思うようになるので、そういう機能をあらかじめ用意しておくとかなり活用してくれます。
他、上級者向けには**キーボードショートカットや一括設定機能、一度覚えれば楽できる裏技**を充実させていきたいです。

# 3. 事前にUIポリシーを決めておいてブレないようにする

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416295/54c3f279-a55a-6883-2354-e1c2c8dbd59a.png)
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416295/6b188309-04ae-7666-0585-41e3ad935d43.png)

追加ボタンは「＋」アイコンで青、削除ボタンは「ゴミ箱」アイコンで赤。
UIデザイナーなら当たり前のことかもしれないですが、エンジニアなりに、ボタンの色やアイコン・文言の使い方など、最初に**自分の中でUIの統一的なポリシーを定め**ておいて極力ブレないようにし、利用者が迷いにくいように心がけています。

* アクション名は**体言止め**にする/しないを決めておく。
* どういうときに**どのレベル (Info, Warning, Danger)のアラート**を表示するかを決めておく。
* どういうときに**タブペイン**を採用するかを決めておく。
* 一覧画面、詳細画面、編集画面などにおいて、**絞り込み入力の配置、追加/編集/削除ボタンの配置など**おおよそのレイアウトを決めておく。
* サイトの構成はツリー状になるようにし、どの画面からでも**パンくずリストから確実にトップに向かって辿れる**ようにする。
* 「ボタンを押したら処理中のぐるぐるが出る」など、**ユーザーの操作に対してすぐに何らかの反応**があるようにする。

などなど。
※**色覚多様性などに配慮しきれていない**ので今後アクセシビリティーは勉強していきます。。

# 4. DBの設計に合わない複雑な改修要望は妥協点を探る

![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416295/307d47e6-ccf1-7dbe-0f34-fb0aba9da64c.png)

利用者からの要望で、「こういうページ構成にしたい」とか「こういう更新手順にしたい」という要望をいただくことがあります。さすがに利用者からの要望だけあって、**利用者目線では正しい**ことが多いのですが、そのまま受け入れてしまうと**DBのテーブル構造などとうまく噛み合わず、ものすごく複雑なプログラムに**なってしまうことがあります。プログラム的には、**1テーブル＝1画面**という画面構成に近づけるのがやはりシンプルです。

要望にお応えしていくことは大事なのですが、応え過ぎた結果、**弾力性が低くなり、スパゲティになって結果的にバグが多くなったり改修が困難になったりして却って要望に応えられなくなっていく**こともありますので、「代わりにこうするのはどうでしょう」と**妥協点を探り**ます。
(要望を安易に受け入れないように、という意味ではないです。むしろ**真摯に向き合う**ことは大事)

**提案例**

* 複雑な入力項目を用意する代わりに、まずは一旦**自由度の高いWYSIWYG入力項目を1つ用意**する形でどうでしょうか。
* 一旦このフローは**手動運用で回避**する形でどうでしょうか。

# 5. 本番に影響を与えず裏で仕込み作業ができるようにする

例えば商品を管理するツールでは品を追加したり更新したり削除したりできますが、「作業した内容を翌月の1日0時0分に一気に本番反映したい、**1個1個の商品の更新の度に本番に中途半端に反映されると困る**」と言われることがよくあります。そういう可能性が容易に想定できるものは最初からそれを見越した作りにしておかないと後で拡張するのがやや難しくなります。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416295/e3567244-e124-f13c-89fa-9ad777154627.png)

例えばこんなデータ構造にしておくと本番の商品情報はそのままで、裏で商品情報の仕込み作業をし、本番反映ボタンを押したら編集中のショップ断面を複製して本番ショップ断面IDの向き先をそちらに切り替えれば、一気に編集内容を本番に反映することができます。
また、「間違ってしまったので過去の断面に戻したい」とか「20XX年X月当時、どういう断面状態だったか調査して欲しい」などと言われることがよくありますがそれにも応えることができます。
あと大事なのは、**編集中の断面をプレビューすることができる**ことです。これに限らず、本番と全く同じ見た目を再現できるプレビュー機能は実装すると結構好評いただくことが多いです。

# 6. ユーザーのロールは柔軟に設定できるようにする

一般に管理ツールはログインするユーザーによって操作権限をコントールするのが普通でしょう。
ツールによって色々な権限の考え方がありますが大きく分けると以下の2種類になると思います。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416295/8c2069ef-622c-10d0-51fa-1338fc937009.png)

ツールによるので一概には言えないですが、自分は極力**横型ロールの考え方を採用**しています。
何故なら、長くツールを運用しているうちに、「この人は一般ユーザーだけど特別に記事管理権限も振りたい」といった例外的な要望が大抵上がってくるためです。

# 7. ログイン履歴、編集履歴は全て記録しておく

サイト管理で事故ったときなどに、「いつ誰がどういう操作をしたか時系列で調べてほしい」という依頼は頻繁にあります。下手したら**犯罪調査で必要になる可能性も**あるかも(?)しれません。以下の**ちょっとしたコードの追加で割とお手軽にログイン履歴、編集履歴を1つのテーブルに記録しておける**ので、記録しておくと色々と有用だと思います。

**履歴記録用のテーブルを準備**
`URI`、`HTTPメソッド`、`リクエストパラメーター`、`IPアドレス`、`操作ユーザー`、`登録日時`のカラムを持つようにしておく。

```python
def build_from_request(request, user_id = None, mask_keys = ('password', 'repassword', 'new_password', 'new_repassword')):
	"""
	request: HTTPリクエスト内容
	user_id: 操作ユーザーID
	mask_keys: マスキングするパラメーター名
	"""	
	history = HistoryTable()
	if user_id is not None:
		history.user_id = user_id
	history.uri        = request.path
	history.method     = request.method
	history.params     = request.json if request.json is not None else {} if request.form is None else request.form
	history.ip_address = request.environ['REMOTE_ADDR']

	for key in mask_keys:
		if key in history.params:
			history.params[key] = '********'
	history.params = json.dumps(history.params, ensure_ascii = False)
	return history
```

こんなメソッドを用意しておいて、

```python
テーブルにINSERTするメソッド(HistoryTable.build_from_request(request, self.user['id'])))
```

こんな感じで各種ログイン・編集処理の際に1行おまじないで書くようにすれば良いと思います。もしくは個別に書かなくても親クラスで勝手にやるようにするのも悪くないかもしれません。
注意点として**パスワード情報は絶対に記録しない**ようにします。上記コードではそこは考慮しています。

# 8. 常に変動する値は設定させない
例えば、商品の**残り在庫数**を管理する機能を作るとします。
その際、残り在庫数を直接設定させてしまうと、**ユーザーがリアルタイムで購入していて在庫数が変動している**のに、それを無視する形で上書きしてしまいます。
このようなケースの場合は、例えば、**累計個数**を設定させ、残り在庫数は **累計個数 - 今までの購入数** で算出すると良いかもしれません。

# 9. セキュリティはちゃんとする
セキュリティは手を抜かないようにします。長くなりますが、過去に別記事でまとめてあります。
[Webサイト開発・構築時のセキュリティチェック事項](https://qiita.com/keichiro24/items/71728748753b1ec93ce9)

# 10. その他細かいこと

* 思ってる以上に色々な使い方をするユーザーがいるようですので、**自分の中で勝手にユーザー像を絞り込み過ぎない**ように心がけます。
* 管理ツールはSEOの考慮は不要ですし、今後は**SPAベースのインタラクティブなサイト**作りをしていくのが良さそうです。
* 色々なツールとの連携が当たり前になってきているので**Inbound/Outbound Webhook連携**など充実させていきたいです。
* どんなツールでも、**折れ線グラフや円グラフなどの集計機能**は作っておけば役に立つと思います (例えば購入数推移、商品ランキングなど)。大した工数でも無ければ先回りして作っておくと良いかもしれません。
* 一覧画面は**多様な絞り込み、自由なソート**ができるようにしておくと色々なニーズに応えられると思います。
* ログインに**IPアドレス制限機能を入れて欲しい**、**二段階認証を入れて欲しい**、というのはかなりよく言われます。

# 11. おまけ 超キビキビ動くサイトを目指したい

これはまだ全くできていないのですが、Gmailのウェブサービスってめちゃくちゃ反応速いですよね。
多分、**行った操作をローカルでスタックしておいて、遅延して順次オンラインに反映していっている**のだと思うのですが、同じようなことをできたらと思っています。
自分が作ったサイトは逐一Ajaxで通信し、完了後に次の操作ができるようになっており反応性がまだまだです。(単純に採用すると色々不整合が生じたり、通信失敗時のケアが難しそうで簡単には踏み切れない)