「いまこれやって」を、画面ごと届ける
その場のお手伝いをタイトルだけで記録できる機能を作ったあと、使ってみて気づきました。いちばん多いのは「自分がやる用事」ではなく「子にやってほしい用事」だった。そこで親が担当者を指定できるようにしたのですが、機能はそこで終わりませんでした。通知を鳴らすだけでは始まらない。自動で開いた画面は閉じられなければならない。そして、結局やらなかった日の片づけ方まで作って、ようやく完成でした。この記事は、ひとつの小さな機能が「作り切る」までにどれだけ枝分かれするか、という記録です。
半分しか作っていなかった機能
RingiQuest には「いますぐやる」という機能があります。突発の用事をタイトルだけで記録して、その場で時間の計測を始められるものです。難しさも、かかる時間も、繰り返しの設定も聞きません。もらえるポイントは、終わったあとに保護者が決めます。
作った経緯は別の記事に書きました。ざっくり言えば「記録する手順が用事そのものより長いと、人は記録をやめる」という問題への答えです。
ところが、しばらく自分の家で使ってみて、妙なことに気づきました。私はこの機能をほとんど使っていなかった。
作れるのは「自分がやる用事」だけだった
理由ははっきりしていました。この機能で作られるお手伝いは、担当者が作成者自身に固定されていたのです。つまり、親が開くと「親がやる用事」しか作れない。
でも家庭で発生する突発の用事の大半は、そういう形をしていません。
- 「宅配来たから受け取っといて」
- 「洗濯物、雨降りそうだから取り込んで」
- 「下の子ちょっと見てて」
いずれも親が気づいて、子にやってほしい用事です。当たり前すぎて、作っているときは気づきませんでした。自分が使う場面を想像しながら実装していたので、「自分がやる用事を、自分で記録する」という形が自然に見えてしまっていたのです。
じゃあ通常のクエスト作成フォームから担当者を指定して作ればいいのでは、と思われるかもしれません。それはできます。できますが、それをやると即席クエストを作った意味がまるごと消えます。難しさも想定時間も繰り返しも入力させられ、しかも作ったあとで子が自分で「はじめる」を押すまで計測は始まりません。「いまゴミ出して」の一言に対して、手順が重すぎるという最初の問題に戻ってしまう。
設計の落とし穴 作り手が自分を利用者として想像すると、「自分のための機能」に無意識で寄る。家族向けのソフトでは、いちばん多い操作が「誰かのために誰かが操作する」形になることを、毎回わざわざ確認しないと見落とします。
通知を鳴らすだけでは、始まらない
というわけで、「いますぐやる」に担当者の選択を足しました。親が「たろう」を選んで「開始する」を押すと、たろうの担当としてお手伝いが作られ、その瞬間から計測が始まります。
ここで問題になるのが、子はそれをどうやって知るのかです。
通知は「届く前提」にできない
素直に考えれば通知です。実際、通知は送っています。ただ、通知だけを頼りにする設計にはしませんでした。理由は、通知が届かない条件が現実にいくつもあるからです。
- そもそも通知を許可していない(子ども用の端末では珍しくありません)
- iPhone や iPad は、ホーム画面に追加していないと Web の通知が動かない
- 音を切っている、画面を見ていない、通知を流し見して消してしまう
この話は前にも痛い目を見ています。以前、通知が一通も届いていない状態に数か月気づかなかったことがありました。原因は鍵の設定ミスで、しかも画面には「通知は有効です」と出たままだったので、誰も異常だと思わなかったのです。以来、「通知は届いているはず」を前提にした設計はしないことにしています。
だから、画面のほうを切り替える
そこで、通知とは別に担当の子のアプリ画面そのものを切り替えることにしました。アプリを開いていれば、親が「開始する」を押した数秒後に、その子の画面が集中モードの全画面に変わります。
集中モードというのは、いま取り組むお手伝いを1つだけ大きく表示する画面です。タイトルと、経過時間と、「おわった」「やめる」だけ。もともとは「あれこれ目に入ると気が散る」子のために作った画面でしたが、「これをやってね」を伝える場所としてちょうど良かったのです。
通知を見なくても、アプリを開いた時点で何をすればいいかが分かる。通知が届いていればもっと早く気づく。どちらか片方が効けば伝わるという形にしました。
ここは「急かし」にしないこと この全画面には、残り時間もカウントダウンも進捗バーも出していません。時間内に終わらせる圧をかけると、雑に終わらせる動機が生まれて、正確に記録するという目的を自分で壊すからです。理由はカウントダウンを付けなかった記事に詳しく書きました。今回もその判断には手を付けていません。
「自分で始めた」のか「振られた」のかを、記録に残す
実装で最初に手が止まったのはここでした。どのお手伝いのときに画面を勝手に切り替えてよいのか。
子が自分で「はじめる」を押した場合は、切り替えてはいけません。本人はすでに画面を見ていて、自分の意思で押しているからです。そこへ全画面が立ち上がったら、単なるお節介です。
切り替えてよいのは「自分では始めた覚えがないのに、計測が始まっているとき」だけ。つまり、親に振られたときだけです。
「誰が作ったか」からは判定できない
最初、既存の情報で判定できないかと考えました。お手伝いには「誰が作ったか」が記録されているので、作った人と取り組む人が違えば「振られた」と判定できそうに見えます。
これは間違いです。親が普通に作ったお手伝い——たとえば毎日の食器下げ——を子が自分で開始した場合も、作った人と取り組む人は違います。この判定だと、子が自分で「はじめる」を押した瞬間に全画面が立ち上がることになります。
必要だったのは「誰が作ったか」ではなく「誰が始めたか」でした。似ているようで別の情報で、しかも既存のデータからは復元できません。結局、計測の記録に「開始した人」を1つ足しました。データを1列足すのは軽い判断ではありませんが、推測で代用しようとすると必ずどこかで誤爆する種類の情報だと判断しました。
一度閉じたら、二度と開き直さない
ここが、今回いちばん気を遣ったところです。
アプリは定期的にサーバーへ状態を聞きに行きます。もし「振られた計測があるなら全画面を開く」とだけ書いたら、どうなるか。子が「とじる」を押しても、次に状態を聞きに行った瞬間にまた開きます。閉じる手段が事実上なくなる。
なので、「この計測については一度自動で開いた」という印を端末に残して、以後は本人が自分で開くまで自動では開かないようにしました。
前にも同じ間違いをしていた
実はこれ、少し前にまったく同じ形の失敗をしています。
通知の購読が何かの拍子に失われる問題があり、その復旧処理を入れたときのことです。「許可されているのに購読が無いなら、購読し直す」と書きました。一見正しそうですが、これだと利用者が設定画面で「通知を無効にする」を押しても、次にアプリを開いた瞬間に有効へ戻ります。
原因は、「許可されている=通知を受け取りたい状態」と読み替えてしまったことでした。ブラウザの許可は、購読をやめても許可のまま残ります。そこからは「本人が切ったのか」「事故で失われたのか」の区別が付きません。
自動化は、意思の修復であって、意思の生成ではない 壊れた状態を元に戻すのは親切ですが、利用者が下した決定を上書きするのは故障です。自動で何かをする処理を書くときは、必ず「これは本人がそうしたのか、事故でそうなったのか」を区別できる材料があるかを先に確認する。無いなら、材料を作るところからやる。
今回の全画面も、まったく同じ構図でした。「開いていないなら開く」は、「閉じた」という意思を毎回踏み潰します。前回の教訓が効いて、今回は最初から印を残す設計にできました。同じ形の間違いは、名前を付けておくと次に気づけます。
誰の時間を止めるのか
RingiQuest では、一人が同時に取り組めるお手伝いは1つだけです。2つ同時に計測すると、どちらの時間も正確でなくなるからです。
そのため、すでに別のお手伝いに取り組んでいる人に新しく振ろうとすると、確認が出ます。「たろうさんは『部屋の片づけ』に取り組み中です。中断して、こちらを始めますか?」
この確認、最初の実装では間違った相手を見ていました。「取り組み中かどうか」を、振られる子ではなく操作している親について調べていたのです。
結果、2つのおかしなことが起きます。
- 親が自分の用事を計測中というだけで、子への割り当てが弾かれる
- 逆に、子がすでに何かに取り組んでいても、確認なしに黙って中断される
とくに後者が良くありません。子から見れば「知らないうちに、さっきまで測っていた時間が消えた」という体験になります。原因が分からない消え方をするものは、それだけで信用を失います。
直し自体は一行の話です。ただ、この種の間違いは「操作している人」と「影響を受ける人」がずれる機能を作った瞬間から、あらゆる場所で起こりうると気づいたのが収穫でした。今回でいえば、通知の宛先、権限の確認、確認文に出す名前——全部それに当たります。
やらなかった日を、片づけられるようにする
ここからは、実際に家で使ってみて出てきた話です。
子にお手伝いを振りました。子はやりませんでした。それだけのことなのに、片づける手段がありませんでした。
計測を止められるのは本人だけ、という作りにしていたのが理由です。他人の計測を勝手に止められると困る、という考え方自体は妥当なのですが、その結果として親が振ったものを親が引っ込められない状態になっていました。
「取りやめる」を作った
そこで、保護者だけが使える「取りやめる」を足しました。押すと、計測の中断とお手伝いの片づけが同時に行われます。子の画面からは計測が消え、そのことを知らせる通知が届きます。
決めたことがいくつかあります。
- 実績としては記録しない。計測していた時間も、ポイントも残りません。これは「やらなかった」ことの整理であって、完了ではないからです。
- 通知の文面で責めない。「取りやめになりました」とだけ伝えます。やらなかったこと自体を、しくみが咎める必要はありません。
- 保護者だけの操作にする。他人の計測を止める操作だからです。子には従来どおり「やめる」(自分の計測を中断)と「取り下げる」(自分が作ったお手伝いを引っ込める)があり、その2つで同じところに着けます。
ポイントが動く操作ではないので、決裁用の暗証番号は求めていません。この線引き——お金が動く操作にだけ確認を挟む——は最初から通してあるルールで、今回もそれに従いました。
片づけたのに、終われない
「取りやめる」を作る過程で、もっと厄介な穴が見つかりました。
取り組み中のお手伝いを、そのまま片づけられてしまったのです。
一見、害がなさそうに読めます。実際に起きることを追うと、そうでもありません。片づけてもその子の計測は動いたままなので、子の画面には計測のバーが出続けます。ところがお手伝いのほうは一覧から消えているので、アプリは「何を計測しているのか」を引けなくなり、「おわった」のボタンが出せません。
つまり、始めたのに終われない計測が生まれます。子から見れば、画面の下に消えないバーが居座り、押せるのは「やめる」だけ。何が起きているのか説明もできない。
順序を、しくみの側で強制する
正しい順序は「取りやめる(中断)→ 片づける」です。これを注意書きではなく、しくみとして強制することにしました。取り組み中のお手伝いは、片づけようとしても受け付けません。画面のほうも、取り組み中はアーカイブのボタンを出さず、代わりに「取りやめる」を出します。
押せないボタンを、画面に出さない 同じ形の不具合を過去にも作っています。担当ではないお手伝いに「はじめる」ボタンが出ていて、押すとエラーになるだけ、というものでした。サーバーが断る操作のボタンは、そもそも画面に出してはいけない。禁止と非表示は必ず対で書く、というのが以来のルールです。
見せていない金額は、払わない
3つ目の指摘は、対価の見え方についてでした。
「いますぐやる」は、かかる時間を聞かずに作ります。それでも内部的には仮の金額を持っていました。「だいたい15分くらいだろう」という前提で計算した値です。そして、その数字がカードに表示されていました。
これは良くありません。子から見れば、画面に出ている数字は約束です。「18ポイントもらえるお手伝い」として受け取ったのに、終わってから親が別の金額を決めるなら、それは約束を破ったことになります。もともとこの機能は「対価は終わってから決める」と宣言しているのに、画面がそれと違うことを言っていたわけです。
数字を出すのをやめ、入力を必須にした
直し方は2つあります。
- 金額を表示しない。「完了後に決定」とだけ出します。カードにも、承認待ちの一覧にも、子の集中モードにも数字は出ません。
- 承認するときに、金額の入力を必須にする。空欄のままでは承認ボタンが押せません。サーバー側でも、金額のない承認は受け付けないようにしました。
2つ目が要点です。それまでは「金額を省略したら、仮の値で記帳する」という親切な作りになっていました。しかしその仮の値は、もう画面のどこにも出していない数字です。出していない数字を黙って支払うのは、親切ではなく事故です。後方互換をあえて捨てて、必ず入力させることにしました。
その代わり、承認画面には実際にかかった時間を大きく出しています。「18分かかりました」を見てから金額を決められるなら、事前の当てずっぽうよりずっと納得のいく値付けができます。むしろこれが、事後決裁という順番にした本来の利点でした。
それでも内部の仮の値は消していません 「表示しないなら 0 にすればいい」とはしませんでした。保護者がそのお手伝いの設定を編集して「承認を挟まない」に切り替えると、完了と同時にポイントが渡る経路に乗ります。そのときに払える妥当な値が残っていないと、今度は 0 ポイントが黙って支払われる。表示の都合でデータを壊すと、別の経路で壊れます。
テストは全部緑で、ボタンは押せなかった
最後に、作っている最中の話をひとつ。
担当者を指定して振る機能ができたので、実際にブラウザを2つ並べて試しました。親の画面で「開始する」を押す。子の画面が集中モードに変わる。ここまでは想定どおりです。
ところが、子の画面に「おわった」が出ていませんでした。あるのは「やめる」だけ。始まったのに終われない、さっきと同じ形です。
原因は、振られた側の端末にはそのお手伝いがまだ手元に無いことでした。アプリは起動したときに一覧を取ってきますが、この子がアプリを開いた時点では、そのお手伝いはまだ存在していません。計測の情報だけが後から届き、それが何のお手伝いなのか照合できないので、完了ボタンが出せない。
直しは「手元に無いものが計測されていたら、一覧を取り直す」の一行です。問題は、この不具合を自動テストが1つも捕まえていなかったことです。判定の関数も、サーバーとデータベースを通した試験も、全部緑でした。緑だったのは当然で、利用者がボタンを押す経路だけ、誰も通っていなかったのです。
これは今回に限った話ではなく、少し前に通知まわりで3回続けて踏んだのと同じ形でした。ある修正が次の不具合を生み、その修正がまた別の不具合を露わにする。共通していたのは、いつも「テストは通っていたが、その画面のそのボタンは押していなかった」ことです。
「直した」の確認は、直した経路を実際に通して行う テストが緑であることと、利用者の操作が通ることは別です。画面を伴う修正は、面倒でもブラウザでその画面を開き、そのボタンを押すところまでやる。ついでに修正前に戻すと本当に失敗するかまで確かめると、確認手段そのものが壊れていないことも一緒に分かります。
まとめ——機能は「やめ方」まで作って完成する
今回作ったのは、書き出すと一行で済む機能でした。「親が子にその場でお手伝いを振れるようにする」。
実際に必要だったのは、これだけありました。
- 振る(担当者を選ぶ)
- 知らせる(通知と、画面の切り替え)
- 切り替えた画面を、閉じられるようにする(そして開き直さない)
- すでに何かしている子の予定を、黙って壊さない
- やらなかった日に、片づけられるようにする
- 片づけたときに、始まったままの計測を残さない
- 見せていない金額を、黙って支払わない
前半3つが「機能を作る」話で、後半4つは全部後始末です。そして家で実際に使って気づいたのは、この後半のほうでした。
ソフトウェアを作っていると、うまくいく道筋を先に作って満足しがちです。けれど家庭で使うものは、うまくいかない日のほうが多い。頼んだのにやらなかった、途中でやめた、気が変わった。そういう日に、しくみが何も言ってくれなければ、そのしくみはだんだん使われなくなります。例外を扱えないルールは、例外が起きた日に壊れて、そのまま戻ってこないからです。
だからこの機能は、「頼めるようになった日」ではなく「頼んだのを取り消せるようになった日」に完成したと思っています。
「いまこれやって」を、そのまま記録に RingiQuest は、親子のためのタスク&ごほうび管理アプリです。その場の用事はタイトルだけで振れて、対価は終わってから決められます。完全無料で、アプリ本体には広告も第三者トラッカーも入れていません。
RingiQuest を無料ではじめる