なんとなく最近いくつかのWebサービスを触って「あ、こういう作りしちゃうとしんどいんだな・・・」というのが少しだけ分かってきたので、ほんとになんとなくメモっておく。
「下書き」「公開」をstatus=draft/publishedとかpublished=true/falseで表現してはいけない
class Article < ApplicationRecord belongs_to :user scope :draft, ->{ where(published: false) } scope :published, -> { where(published: true) } def publish! update!(published: true) end
こういうモデルを作ってしまうと
- 下書きと公開後で「見ることができる人」が異なるべきなんだけど、ふとした拍子に
Article.find(params[:id])
とか書いて(.published
を付け忘れて)事故る - 下書きはそんなに厳密なバリデーションなく保存したいが、公開時にはちゃんとバリデーションしていてほしい。そうすると
if: :published?
unless: :published?
がたくさん... - 公開時にプッシュ通知を送りたい、というのをやるにも「初めて公開状態になったタイミング」の取得が難しい
などなどの理由で「事故りやすい」コードになってしまう。
「下書き」は素直にモデルを分けよう
class ArticleDraft < ApplicationRecord befongs_to :user def publish! Article.create!( user_id: self.user_id, body: self.body ) end
class Article < ApplicationRecord befongs_to :user
下書き状態をフラグではなくすことにより、
Article.find(params[id])
とかを不用意に呼んでしまっても、見えてはいけない下書きが混ざることはもうない。- バリデーションも独立で定義できる
- 初めて公開状態になったタイミングはArticlewのcreateのタイミング。
のように、構造的に少し事故りにくくできる。
通知の処理はべた書きしない
class ArticlesController < ApplicationController def create if @article = current_user.articles.create(params.require(:article).require(:body)) NotificationMailer.notify_article_created(@article) else render :new end
これは以前に書いたことそのものなんだけど、通知は結構いろんな種類があるのでコントローラにべた書きなんてやってしまうと
- アプリ作るからプッシュ通知もやりたいな
- アプリのAPIから通知したお知らせ一覧を見れるようにしたいな
みたいな要件があとづけでやってきたときに詰む。
通知は「きっかけとなったイベント」と「通知履歴」で表現する
に書いたこと。
コア機能を「とりあえずWebViewで画面つくる」のは絶対にやめたほうがいい
「Railsのコードで画面が作れるし、多少の仕様変更があってもアプリ側にアップデートしてもらわずに変更できるし、フォー最高!」みたいなかんじでWebViewが採用されることが稀によくある。
しかし、以下のような理由でWebViewを採用する場合には、REST API+ネイティブ実装が本当にダメなのかを再考すべき。
- iOSとAndroidの両方の画面をメンテするよりは、HTML+CSSでそれっぽい画面が作れる
- 仕様が変わったときにアプリ側の変更無く反映ができる
- Railsのコード書けるエンジニアはたくさんいるけど、アプリのコード書けるエンジニアは数人しかいないので、Railsのコードに近いほうがメンテ楽そう
WebViewは
- 特定のページにJSを注入する
- 特定のURLをブラウズしようとしたときに処理を横取りしてネイティブ側に処理を戻す
- カスタムヘッダーをつける
など、ブラウザでは簡単にできないことが自由にできる。
その半面、これらを使ってしまうとブラウザでコンテンツ試験困難になり、iOSとAndroidのアプリ両方と結合動作確認しないといけない。そうすると気づく。「まったくラクできてないぞ?!」と。
WebViewじゃなくて素直にブラウザを使ったほうがいい
WebViewは基本的に使わないほうがラクだが、
- 認証が不要
- Web側で機能が完結している(○○のリンクを踏んだときはネイティブ側の画面を表示する、みたいなのが無い)
- ユーザがブラウザに保存している個人情報(パスワードとか氏名・住所とか)の補完やクッキー情報を利用したい
のような場合には、ネイティブじゃなくてWebViewを採用したいなというのはアリ。ただ、それならWebViewではなく素直にブラウザを使ってWebページを表示したほうがいい。
Yahooの認証画面とかがいい例で、認証時はブラウザで専用の認証ページに飛ばされて、認証が終わったらカスタムスキームのURLでアプリに戻ってくる、という作りをしている。
素直にブラウザで表示すると何がいいかというと
- ダサい
- コア機能をWebViewで済ませちゃおうという気が失せる
- 試験がしやすい
が大きな理由。「コア機能は自然とネイティブ化したくなる」ってのは本当に大きな理由。
WebViewは意外とメンテが大変なので、REST API+ネイティブ実装したほうが結果的にはラクなことが多い
WebViewは、実運用においては
①思ったほど更新されず →②メンテされず →③いつの間にか壊れて →④意図したとおりの使われ方がされず →⑤結局ネイティブに置き換えられる or 単純に捨てられる
みたいなライフサイクルをたどることが多い。
REST APIであればrequest specで自動試験しやすく、どこかの誰かがモデル構成を変えて壊れそうになっても事前検知ができる。しかしWebViewのように画面を返すものはRailsでも試験を書くのが格段に面倒だ。雑に試験を書かないでいると、どこかでモデル構成がいつの間にか変わっててWebViewだけいつの間にか壊れる、みたいな状態になる。
また、そもそもWebViewで作る画面は、Railsのコード書く人にとっては「アプリの画面」として敬遠されがちだし、アプリのコード書く人にとっては「CSSとかちゃんとわかってないといじれない画面」として敬遠される。
ヘルプページとか、OSSライセンス表示みたいに、見る人/見るシーンが限られている機能であればWebでいいのだけど、少なからずユーザに使ってほしいコア機能であれば、最初からネイティブ実装したほうが、ちゃんとメンテもされるし継続的に利用されるだろう。
「一度しか表示しない」ものは極力なくそう
個人的にはなんで存在しているのか全くわからないんだけど、ウォークスルーみたいな機能って割とたくさんのアプリで実装されている。
ウォークスルーは
- 「読まない取説を無理やり読まされてる」ものなので、大抵の人は読まずにスキップする
- 最初の1回しか表示されないので、ユーザの印象には全く残らない
- 画面のスクリーンショットが貼られていたりすると、画面が変わるたびに画像差し替えが必要になって、デザイナもエンジニアも対応が必要
という、この上なくコスパが悪い機能だ。
説明のためのウォークスルーを実装するくらいなら、コア機能を説明なしで使えるようにUI改善したほうがいい
「説明をしないと使ってもらえない」という不安をウォークスルーとか説明のポップアップみたいなもので払拭するのがそもそもの間違いで、説明しなくてもいい状態を作り出すことがユーザにとっても開発者にとっても良い状態だ。
もっというと、「説明を必要とする機能であれば作らないほうがいい」という判断もアリだ。説明が必要というのは「ユーザが必要としていないものを作っている」ということなのかもしれないと疑ったほうが、シンプルに仕上がる。
ユーザが求めているのは紙芝居のウォークスルーではなく、セットアップウィザード
「iPhone買ったときだって、最初の1回だけ表示される機能があるじゃない?」
そう、あれはウォークスルーではなく、セットアップウィザードだ。「セットアップしないとちゃんと使えないので、一緒にセットアップして行きましょうね!」という目的のセットアップウィザードは、ウォークスルーとは似て非なるもの。
Wantedly Syncが昔、シンクマっていうキャラクターとのチャットを通じて使い方を説明していく面白い仕組みをつくっていた。
会話履歴のない人がアプリを立ち上げると、いきなりボットに話しかけられて
他のメンバーの招待の仕方やメンションの仕方を教わる、というもの。
こういうインタラクティブにセットアップ/使い方の習得をしていくのが、おそらくユーザが求めているものだ。
まとめ
複雑なものは、メンテされずに忘れられて壊れて、置き換えられるか捨てられる。
シンプルにいこう。