LoginSignup
26
10

More than 1 year has passed since last update.

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

Last updated at Posted at 2021-12-07

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

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

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

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

1.png
2.png

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

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

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

7.png

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

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

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

5.png
6.png

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

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

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

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

8.png

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

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

提案例

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

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

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

3.png

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

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

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

4.png

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

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

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

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

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

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

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

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

8. 常に変動する値は設定させない

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

9. セキュリティはちゃんとする

セキュリティは手を抜かないようにします。長くなりますが、過去に別記事でまとめてあります。
Webサイト開発・構築時のセキュリティチェック事項

10. その他細かいこと

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

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

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

26
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
10