Skip to content

Latest commit

 

History

History
128 lines (75 loc) · 22.3 KB

chap-makesmallappforme.md

File metadata and controls

128 lines (75 loc) · 22.3 KB

自分の業務で使う小規模アプリを作ってみよう

アプリ開発、あるいはプログラミングをやってみようと思った時に、一番良いのはやはり小さいアプリを作ってみることだと思います。しかもそれは自分の必要に合致している方が絶対的に良いです。興味ドリブンの開発も悪くはないですが、目標地点がはっきりしないきらいがあります。それに対して「業務や日常で少し困っていることを具体化する・簡単にする」ようなアプリを作ることは、まず目標地点がはっきりするという大きなメリットがあります。それとともに、自分というユーザーが確実に存在しかつ随時フィードバックがなされるため、自分にぴったりフィットするアプリを的確に作成することができるでしょう。

日常アプリとは

日常の業務や生活で使うちょっとしたアプリを想定しています。日常業務でエクセルコピペを毎日のようにやっているとか、画像のリサイズをして貼り付けるとか、ちょっとしたファイルの加工をするなどが想定されます。あるいは、「朝、家を出る前に今日の天気予報をチェックする」など、習慣になっていることを少しスマートにする・自動化するようなアプリを考えてもよいかもしれません。

もちろんそういったツールは大抵世の中にあるでしょう。そしてそれはあなた自身が作るよりも洗練されていたり、高機能だったりするかもしれません。しかし、洗練されているからといって使いやすいとは限らないですし、作ってみる、開発してみることで見えてくるものもあるかもしれません。

画像のリサイズの話であれば、リサイズするツールは当然たくさん存在するでしょう。天気予報のチェックもアプリはあります。なんなら何もしないでも定刻にスマホにPush通知してくれたり、自動で現在地に紐づけてくれたり、天気と気温以外の風向きや明日の天気まで自動で通知してくれる多機能なツールがすでにあるかもしれません。いえ、探せばきっとあるでしょう。

それでもあえて自分で作ることで、以下のようなメリットがあります。

  • 自分にとって必要十分なツールが作れる
  • 必要に応じて改造可能
  • 直ちにフィードバックできるし、効果が見えやすい
  • 自分がやりたいことなので、要件定義が明確(明確にしやすい)

アプリの要件定義

要件定義では、どんなアプリを作るのかを機能や画面に落とし込んでより具体的に考えるプロセスです。必要な機能やユーザインターフェイスについて分解して実装を考える手順です。1。自分で実装する場合は要件定義を元に自分で実装しますし、外注として他の人に作ってもらう場合にも整理した要件定義をもとに説明をし、理解してもらう必要があるので非常に重要なプロセスでありドキュメントです。むしろ実際のコーディングよりよっぽど重要でしょう。

改めて述べますが、たいていのツールは世の中にさまざま存在するので、アプリは自分で作るばかりが能ではないとも言えます。自分でやる時間とツールを作るのにかかる時間を比較するとともに、得られる成果を最大化することがツールを作る目的ですから、必要十分なツールがすぐに見つかればそれを使っても良いでしょう。自分で作ったツールを用いることで省力化される時間やマンパワーがツールを作るのにかかる時間や得られる効果に対して大きいのか、という観点でも考えると良いでしょう。 (ですが、本書はアプリ開発の本であるので、「きっとすでにあるから作らないで探そう」を結論にしては話が進まないのでアプリを作る方向で話を進めることにします。)

以下、例として「画像のリサイズを一括実施するソフト」を作ることを想定しながら、設計の考え方を考えてみることにしましょう。

まずはソフトの中でやりたいことを出来るだけ細かく分解します。この例である画像のリサイズを一括で行う場合、最初のステップでは「指定フォルダ内の画像ファイルを読み込んで、リサイズして、保存する」といった処理の流れに分解することができます。

リサイズプログラムであれば、このように箇条書き的に展開していくのが良いと思います。

  • 指定フォルダ内の画像ファイルを読み込む
  • リサイズする
  • リネームして保存する

一旦一通り展開したら、それぞれのステップをさらに分解します。ファイル読み込みにおいては複数ファイルなのかフォルダ単位なのかを考えることでより具体的にできるでしょう。両方実装するももちろんありですが、とりあえずは片方だけ実装して一旦完成させるというのが良いでしょう。

次のステップは、

  • 指定フォルダ内の画像ファイルを読み込む
    • パスを指定する
    • ファイルにフィルタをかける
    • 複数ファイルを選択する
  • リサイズする
    • 縦サイズを指定する(画面の設定値から読み込む)
    • 横サイズを指定する(設定値から読み込む)
    • アスペクト比を保持するか縦横に合わせるか選ぶ
  • リネームして保存する
    • ファイル名を生成する
    • フォルダを指定する
    • 保存する
  • ループを回す

というふうに第二段階に向けて展開していきます。その過程で、追加する内容が加わることがありますが、それは全く問題ありません。もやっとしていた仕様が明確化されたのです。また、順序も適宜変更して良いです。

なお、一連の流れを意識しつつ、分解するレベルをおおよそ同じレベルで展開していくことをお勧めします。逆に局所的のみに掘り下げるというのは一旦あまりお勧めしません。やることが多くなりすぎて全体感が見えづらくなってしまうためです。

  • 指定フォルダ内の画像ファイルを読み込む
  • リサイズする
    • 縦サイズを指定する
      • 今の画素数と変更後の画素数の比率を計算する
        • 処理の式
  • リネームして保存する

一箇所だけを掘る例を示します。もちろん場合によっては必要になることもありますが、あまりに深くなりそうであれば、上位レベルで分割するとかレベル整理をするなどで全体を見直する方が良い場合が多いと考えます。重要な部分であったり肝になる部分だから分量が増えるのはわかりますし、自分の得意な部分ではついに局所的に掘ってしまいますが、全体構成を常に考えるようにして、全体を一定スピードで展開していく方が良いでしょう。目安は、1項目あたり3〜4項目に展開することです。3のn乗で展開されるので、3レベルまで掘ると27項目、4レベルまで展開すると81項目になります。

この例では、レベル4くらいに、リサイズの条件(画素数、変換アルゴリズム)やリネームするときの命名規則はどうするか、保存するフォルダは自動指定で良いのか都度選択か、など、出来るだけ細かく分解して全体感を細かくしていきます。こうすることで、必要な機能を網羅しつつ全体の要件を整理していくことができ、さらに次のステップであるコード実装しやすくなります。要件定義が具体的であればあるほどコードに落とし込みやすく、また例外処理なども実装しやすくなります。アプリの規模にもよりますが、4レベルか5レベルまでいけば、ほぼコードを日本語で書いたものになるでしょう。そうなれば、1行の日本語を数行のコードに機械的に直していく、という形で実装できるようになるでしょう。

例えば「画像を選ぶ」において、対象ファイルはJPGだけなのか、pngやbmpなどが含まれるのか、といった想定しておくと具体化しやすいでしょう。またファイルは一つか複数か、といった観点、すなわちこれから使うことを想定しながら書き出すと良いでしょう。その結果、ファイルのフィルタをかけてjpgしか表示しないようにした方がいいのか、全てのファイルを表示した方が良いのか、複数選択可能にした方が良いのか単一ファイルのみとした方が良いのか、といった細かい実装の定義に繋がります。

また、処理の流れを具体的に記述するという点については、フォルダの指定についても、いつも決まっているので前回と同じフォルダを記録しておく、あるいは、様々な設定をまとめた設定ファイルを作ってそこから読み込むようにする、頻繁に変わるので都度指定する、などのように深掘りをします。

さらに、「ファイル選択をしたらリサイズ処理に進む」という手順を考えるとき、リサイズ処理について書き進めるとともに、たとえば「ファイルが一つも選択されなかったらどうするか?」という形で例外処理のきっかけを拾いだすことができます。ファイルが一つも選択されなかった時にどうするかは、コードの方で上手いことやってくれる可能性はありますが、普通に考えれば何もないファイルに対して読み込みをかけようとするためエラーが発生する可能性があります。こういったエラーは、コーディング・デバッグの過程で見つかる場合も多いのですがが、要件定義の場面である程度洗い出しておくことであとで困らないで済む可能性が高くなります。「こういう例もありえるからその処理を具体的に考える」とすることで例外を例外でなくすことができます。

また、処理の流れを具体的に書き下すことで、処理の順番を可視化することができ、それを変えることで全体構造がシンプルになる可能性もあります。順番に行う必要がある処理に対して、先に処理ボタンを押してしまう場合などの対処を取ることもできます。例えばファイル開いてデータを読み込み、何か処理を行うという設計をして、ファイルを開くボタンと処理を行うボタンを作ったとします。通常であればファイルを開くボタンを使ってファイルを読み込み、処理を行うボタンを押して処理を行うでしょう。ですがファイル読み込みボタンを押さない状況で処理ボタンを押したらどうなるでしょう?カラのファイルや配列に処理を行うので、エラーが出るかもしれないし、想定した結果と異なる処理が走る可能性が出てきます。対処としては、ファイルを読み込んだフラグで確認する、読み込んだデータが存在するか確認する、などの処理が考えられますが、いずれも例外を例外でなくす処理を加えることで安定性をあげることができます。

また、画面の構成についてもここで考えます。必要なボタン、設定フィールド、進捗モニタのためのプログレスバーなどがあると便利ででしょう。たとえばボタンは、ファイルオープン兼処理開始ボタンが最低限必要です。条件次第では、ファイルオープンと処理を別ボタンにしてもよいでしょう。設定値は、見せる必要があるかブラックボックスとして良いのかという点で考えます。

次に、処理パラメータの入力フィールドを作ります。処理が固定であればコード本文に埋め込んでも良い場合もありますが、処理を変えるたびにコンパイルし直さなければならないので基本的には設定フィールドを作ると良いと考えます。画像リサイズでいえば、縦、横のピクセル数を入力するフィールドを作り、もう一つチェックボックスを作り、アスペクト比を維持するのかどうかというフラグとするのも良いでしょう。

繰り返しになりますが、要件定義がはっきりしていればはっきりしているだけ、あとの実装やテストが楽になります。

テストしながら実装する

興味のある言語で実装しましょう。特定の言語でなければ実装できないなんてことは99.99%ありえませんから、どの言語を使っても良いです。絶対にないとまでは言い切れませんが、それはそれ。Velirog-HDLでWebアプリを作ろうなんていうへそ曲がりで意味不明なことを考えない限り大丈夫でしょう。この言語を使ってみようという思惑があっての実装でしょうからどの言語が良いかという話はここではしません。

ここまでに実施した要件定義に従って、1段階づつ実装を進めます。1段階づつ実装することで、いつの間にか不明な挙動になっているとか、ミスやバグが混入する可能性を減らすことができます。出来るだけ小さい単位でテストを繰り返すことで進捗も見えやすく、小さな報酬を得つつ実装を進めることができるため、飽きずに進めることができるでしょう。

先の節で細かいレベルの要件定義ができているはずです。レベル4くらいまで展開できていますか?展開できていれば、すでに1行の実行する内容が十分に細かい処理を表していますから、それを数行のコードに変換するだけになっているはずです。

もしすぐにコードに変換できないようであれば、もう少し細かく展開してもいいのかもしれません。

細かいステップというのは、例えばファイルを開くのに対して、ダイアログを出せたか、ファイルの種類のフィルタは適切に動いたか、ファイル名を引けたか、指定したファイルを読み込めたか、といったレベルでテストします。極論すれば、1行ごとにテストするつもりでやってもいいかもしれません。もちろん慣れてくればその粒度は調整して良いのですが、一度は1ステップづつやってみると、その言語における挙動といったこともわかってきます。そのために、テンポラリの表示スペースやConsole、デバッグ出力などを使いましょう。ちゃんとファイル名が読めているのかを確認するために標準出力にファイル名を書き出させるとか、ファイルがちゃんと読めているかを確認するために画像や最初のデータ数点を書き出すなどです。ここで挙動がおかしければ、今実装した部分を確認、修正します。

また、Gitのように粒度の細かい差分を取りやすいバージョン管理ツールを使うことで、細かい頻度でのテストステップを確実に進めることができます。Gitの使い方やメリットは別章に譲りますので、そちらを参照ください。ただし、バージョン管理がなかったら、このような1行づつのテストはかなり大変になると考えられます。1行コードを入力してテストするたびに、program(1).cやprogram(日付).cといったファイルが量産されたり、どれが最新かわからなくなるとか、ミスがあった時にどこまで戻れば良いのかわからないなど、著しく生産性を下げる結果となるでしょう。ゾッとしますね。

お作法やスパゲティコードについて

コーディング初心者であれば、スパゲティコードになったり、やたらメイン関数が長いとか、モジュール化されておらず似たような処理が長々と何箇所にも出てくるなど、洗練されていないコードになることが少なくないでしょう。一旦はそれでも良いと考えます。まずは、「とりあえず動くもの」を作り上げることこそが重要です。最初のものがなければ、アプリのご利益を得ることもできませんし、アプリの改善及びそのアプリを使った業務の改善もできません。

もちろん、それを題材に経験者にリファクタリングをお願いするとか、モブプロの題材にするなど、次の活用方法もあるにはあります。ですが綺麗なコードがかけないからといって一歩を踏み出さないのはもったいないです。とりあえず動くものを作って、後から改善すれば良いのです。なお、コーディングのお作法については別の章を参照ください。

環境構築は最低限にする

環境構築は出来るだけシンプルにしましょう。統合開発環境(IDE)の構築は必要でしょうが、自動テストツールを構築しなければ、CIを設定しよう、リモートリポジトリを作って、あれもやって、これもやって、と欲張りすぎると、結局小さい自分アプリの実開発をいつまでたっても始められません。ツールはあくまでツールであり、アプリの開発が目的であり、環境設定がゴールではありません。それぞれ環境構築にもさまざまな手順や落とし穴があり、それらにつまづいているうちに目的地を見失っては元も子もありません。

一般にエンジニアはそういう環境構築に楽しさを見出してしまったり、環境構築をして満足してしまう傾向があります。ですが手段を目的化すると目的地を見失ってしまいます。その誘惑は断ち切って、まずアプリを作り始めましょう。他のツールの拡充などは、それがある程度できてからやれば良いのです。

セルフフィードバックする

ある程度の部分ができあがったらまずは使ってみましょう。その中で、これまでの要件定義の中で気づかなかった便利な機能、逆に要件定義の中ではほしいと思ってたけれど実際は使わない機能などが見えてくるでしょう。想定していた手順と異なるため入れ替えた方が良い、といったことも見えてきます。これらは、使用者(=自分)の生の声ですから、ぜひ反映させましょう。なんのためのアプリ開発なのか?それは使う人が便利になり省力化や生産性の向上を目的としています。使いづらい物を使いづらいまま使う必要は全くありませんし、自分で作っている物ですから修正もすぐにできます(変更の実装が簡単かという点は別問題です)。

また、それらのツールを公開してみるのも良いでしょう。グループ内や業務チーム内に「こんなツールを作ったよ」といってみるのです。同じチームであれば類似の業務があるでしょうから、あなたのツールを使ってくれるかもしれません。バグ報告や機能追加要望が出てくるかもしれません。これらの声も、使用者の生の声ですし、製作者とは違った視点が得られるので、新しい素敵な機能追加につながるかもしれません。

なお公開するにあたって、バグがあるかもしれないことや、その修正や機能追加は必ずしもなされるものではないことは断っておきましょう。使ってもらえることやフィードバックがあることは嬉しいことですが、それが重荷になってしまっては楽しくありません。また、あくまで自分が使うツールであるという前提に立って、過大な機能追加要求、例えば自分の手に余る場合や自分が使わない機能である場合などは突っぱねることも視野に入れましょう。またあるいは、そのソフトを業務ツールとして認めてもらい、その実装を業務として認めてもらうことを考えても良いかもしれません。

実装してあげる場合、依頼者にしっかり恩を売っておきましょう。便利なツールを作ってあげるのですから、返ってくるかどうかは別として「実装してやるから貸し1ね」などと軽口でも言えるといいですね。コードごと依頼者に渡し、自分で実装してみてもらうのも一つの手です。案外その人が自分で作り始めて、どんどん良いツールになっていくかもしれませんね。

まとめ

自分で使う小さなツールを作ってみよう、ということで要件定義(及び実装・テストの一部)について書きました。この方法自体は我流ですし、チーム開発においては様々なお作法があることでしょう。ですが一人で何かを作るにあたっては有用であると思っています。またこの方法に対してこうすればもっと良くなるといったアドバイスはぜひお願いしたいです。

アプリといいつつ、何かを作ること全般に適用可能な汎用的な技術ですから、小規模開発のご参考になれば幸いです。

Footnotes

  1. 多少語弊はあるし、本来はもっと複雑かもしれませんが、とりあえずコンパクトなアプリなので、そういうことにします。