2019/11/20

素晴らしい。 もう六日目だ。 昨日は激しく深酒をしてしまって、文章は無茶苦茶だし、何がしたいのかもよくわからない記事となってしまった。 今日はすでに酒がかなり入っている状態だが、ここからは比較的穏やかに飲んでいこうと思っているので、昨日のような醜態は晒さずに済む予定である。

では始めていく。


昨日はスキーマの設計が終わった後、何故かAPIの設計を始めてしまった。 しかし、今回のような一人で開発する小規模なプロジェクトの場合、必要になった段階でAPIを生やしていくのが一番手っ取り早いと思うので、一旦API設計の作業はやめて、先にフロントエンドの開発に取り組んでいくこととする。

使用する言語はCoffeeScriptでもTypeScriptでもなく生JavaScriptフレームワークはReact、ベースのコンポーネントライブラリはMaterial UI、ルーティングはReact Router、ステートの管理はReact Reduxを用いる。 その他諸々必要なものは適宜追加していくこととする。

早速手を動かしてコードを書いていきたいのは山々なのであるが、多少なり先にデザインが決まってなければ何から始めれば良いか分からないし、先が見えなさすぎて少々キツイ。 なのでまず手書きのワイヤーフレームもどきを作っていくこととする。


できた。

f:id:tac2nd:20191120222729j:plain

UIを考えてみてようやく気付いたのだが、現状のテーブルスキーマには、予定のルーティンワークがその日に実行されたか否かを管理するテーブルが存在しない。 RoutineHistories テーブルは名前的にそういう用途に使えそうに見えるが、このテーブルはルーティンワークのActivateとInactivateを管理するためのテーブルであり、そのルーティンワークがその日に実行されたことを書き残すためのテーブルではない。

そういった履歴を残すためには別のテーブルが必要となる。 と言っても、DATE 型の日付を表すフィールドと、ルーティンワークのIDを指す外部キーを主キーとした簡単なテーブルを一つ作るだけで事足りる。

しかし、命名はどうしよう…。 色々考えたが、既に存在している RoutineHistories テーブルを RoutineEventHistories とし、 ルーティンワークが実行されたことを記録するためのテーブルは RoutineHistories とすることとした。 新生 RoutineHistories テーブルのスキーマは以下のようになる。

CREATE TABLE IF NOT EXISTS `routine_histories` (
  `routine_id` CHAR(36) NOT NULL,
  `date` DATE NOT NULL,
  `is_done` TINYINT(1) NULL,
  PRIMARY KEY (`routine_id`, `date`),
  CONSTRAINT `routine_id`
    FOREIGN KEY ()
    REFERENCES `routines` ()
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB

一応、更新後のEERダイアグラムも張り付けておく。

f:id:tac2nd:20191120231344p:plain

では早速フロントエンドを書いていこう。


ということで、コードを書き始めたのが、眠気がマックスに近くなってきたので今日はここまでにすることにする。

では、おやすみなさいませ。

2019/11/19

また今日も帰ってくることが出来た。 今は茄子の生姜醤油炒めと、大根ステーキをつまみながらプライムリッチをカッ食らっているところである。 やはり茄子は美味い。 特にアブラがギットギトに染みた茄子は、これさえあれば死ぬまで無限にビールが飲めるんじゃないかと思うくらいに美味い。

よし、今日も作業を始めていく。


と、思ったのだが少し待ってほしい。 豚の切り落としの唐揚げでプライムリッチをゴックゴクと流し込みたい欲がマックスに高まってしまっている。 ちょっと先に作ってきます…。


作ってきたので始める。

昨日は Users テーブルと Routines テーブルの設計をした。 今日はまずルーティンワークの履歴を管理するためのテーブル RoutineHistories から始める。

CREATE TABLE IF NOT EXISTS `routine_histories` (
  `routine_id` CHAR(36) NOT NULL,
  `created_at` DATETIME(6) NOT NULL,
  `event` VARCHAR(16) NOT NULL,
  PRIMARY KEY (`routine_id`, `created_at`),
  CONSTRAINT `routine_id`
    FOREIGN KEY ()
    REFERENCES `routines` ()
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB

言わずもがな routine_idRoutines テーブルを指す外部キーであり、created_at はその履歴が発生した時間をミリ秒単位で保存するフィールドである。 そしてこれら二つを主キーとして設定している。 DATETIME で細かく設定する方法に関しては、こちら(https://dev.mysql.com/doc/refman/5.6/ja/date-and-time-type-overview.html)を参考にすると良い。

また、event フィールドにはそのルーティンワークに対して行われたイベントが文字列として保存される。 ENUM を型に使うことも考えたが、どういうイベントが必要かも全然定まってないし、正直そこまで厳密に縛る必要性もあまり感じられないため通常の文字列として保存することにした。

最後に、一日の感想を軽く残すための Diaries テーブルの仕様を決める。

CREATE TABLE IF NOT EXISTS `diaries` (
  `id` CHAR(36) NOT NULL,
  `user_id` CHAR(36) NOT NULL,
  `datetime` DATETIME NOT NULL,
  `content` TEXT NOT NULL,
  `created_at` DATETIME NOT NULL,
  `updated_at` DATETIME NOT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `user_id`
    FOREIGN KEY ()
    REFERENCES `users` ()
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB

まあ、正直このテーブルに関しては特に言うことない感じもするので、詳細の説明は省くこととする。

出来上がったテーブルスキーマは以下のようになった。

f:id:tac2nd:20191119233349p:plain


はあ…。とりあえずテーブルスキーマの設計だけは終わらせることができた。 もうすでにプライムリッチを1L近く飲んでしまっているため意識は極めてボンヤリしている状態である。 でもまだやれる! やれるのだ! 次はAPIの設計を軽くしていくこととする。


正直今回のテーブルのスキーマは滅茶苦茶シンプルなので、APIも滅茶苦茶シンプルになると思われる。 しかしもうすでに脳が酒に侵されて頭が全然回ってないのでざーっくりとした草案だけ書き残しておくこととする。

  • ユーザの登録やユーザ情報の取得は /users/users/{userId} エンドポイントを利用する。
  • ユーザのルーティンワークは /users/{userId}/routines エンドポイントを利用する。
  • ルーティンワーク自体を扱うためのエンドポイントとして /routines を生やす。

ダメだ…。 眠みがマックスになってしまった…。 今日はこのくらいにして明日続きを書くこととする。

では、おやすみなさい。

2019/11/18

三日坊主にならずに帰ってくることができた。

では、今日も作業を始めていく。


先週の木曜日はベッロベロになりながら、適当なテーブルスキーマを書いた。 今日はその適当なスキーマに肉付けと説明を書き残す作業から始めることとする。

まずユーザ情報を管理するための Users テーブルから始める。

CREATE TABLE IF NOT EXISTS `users` (
  `id` CHAR(36) NOT NULL,
  `name` VARCHAR(255) NOT NULL,
  `display_name` VARCHAR(255) NULL,
  `email` VARCHAR(255) NOT NULL,
  `password` VARCHAR(255) NOT NULL,
  `salt` VARCHAR(45) NOT NULL,
  `is_admin` TINYINT(1) NOT NULL,
  `created_at` DATETIME NOT NULL,
  `updated_at` DATETIME NOT NULL,
  PRIMARY KEY (`id`))
ENGINE = InnoDB

id フィールドにはUUIDまたはULIDを用いる。 UUIDとその互換のULIDはピッタリ36文字と決められているため、型は CHAR(36) とした。 (参考:primary key - UUID max character length - Stack Overflow )

email フィールドの長さに関しては色々な議論があるだろうが、まあ個人で適当に作るサービスなのでそこまで厳密には考えず適当に VARCHAR(255) とした。 ちなみに VARCHAR の長さを256ではなく255としているのをよく見かけるが、これは文字数カウントのための領域が255だと1バイト、256だと2バイト必要なため、どっちでも良い場合は255を使うのがお作法ということらしい。

次にルーティンワークを管理するための Routines テーブルを示す。

CREATE TABLE IF NOT EXISTS `routines` (
  `id` CHAR(36) NOT NULL,
  `user_id` CHAR(36) NOT NULL,
  `title` VARCHAR(255) NOT NULL,
  `description` TEXT NULL,
  `status` VARCHAR(16) NOT NULL,
  `start_time` TIME NULL,
  `finish_time` TIME NULL,
  `color` VARCHAR(7) NOT NULL,
  `days` TINYINT NOT NULL,
  `is_allday` TINYINT(1) NOT NULL,
  `created_at` DATETIME NULL,
  `updated_at` DATETIME NOT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `user_id`
    FOREIGN KEY ()
    REFERENCES `users` ()
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB

id フィールドはユーザ情報と同じくUUIDかULIDを用いる。 また、user_id は外部キーで users テーブルを参照し、複数のユーザで同じルーティンワークを共有することはできないこととする。 すなわちユーザとルーティンワークは一対多の関係となる。

description にはそのルーティンワークの詳細な説明を入れる。 この説明文は長くなる可能性が高いので型は TEXT 型とした。

status には、そのルーティンワークがまだActiveかどうかを示す文字列を格納する。 TINYINT(1) にしなかったのは、将来的にActive/Inactive以外にも状態を持たせる可能性があると判断したからである。 ただしこのフィールドは後述する routine_history テーブルの存在により必要なくなるかもしれない。

start_timefinish_time は、一日の中でどの時間帯にそのルーティンワークを行うかを示す。 終日行ったり、start_time だけ決めて finish_time は決めない、といった状況にも対応するためにNOT NULL制約はかけていない。

color はルーティンワークに色で簡単にタグ付けできるようにするための機能である。 もちろん文字列によるタグ付けも実装は簡単だが、少しそれはやり過ぎな気がしたので、このようなシンプルなデザインにした。 型は VARCHAR(7) としたが、これは #FFFFFF のような文字列を直接格納することを想定したからである。 しかしよく考えるとアンチパターンな気もするのでこれは変えたほうが良いかもしれない。

days は何曜日にそのルーティンワークを実行するかを管理する1バイトの整数値である。 整数値である理由は何となく予想がつくと思うが、以下のようにビットで管理したいからである。 ただこの方針はアプリケーションの実装にテーブルが密に依存してしまうのでバッドプラクティスなのかもしれない…。

(High) 0 1 1 1 1 1 1 1 (Low)
X Sat Fri Thu Wed Tue Mon Sun

is_allday はそのルーティンが終日行われるルーティンか否かを示すフラグである。

時間が時間なので、今日はここまでとする。 今日も色々調べ物がメインだったため全然作業が進まなかった。 ただSQLアンチパターンをまとめた記事をざっと目を通せたのはとても良かった。

では、おやすみなさいませ。

2019/11/14

なんとかまた帰ってくることが出来た。 今は豚の切り落としを揚げたものと、その残りの油で素揚げした茄子をつまみながらプライムリッチをカッ食らっているところである。

訳あって明日から三日間ブログを書くことはできないが、三日坊主だと思わないでほしい。 理由があるのである。 まあもしかすると本当に永遠に戻ってこないかもしれないが…。

では技術ブログを始めることとする。


環境構築

昨日は仮想マシンの容量の問題で環境構築すら途中で終わってしまった。 なので今日もそこから始めることとする。

npx create-react-app taskiee-ui

ここまでは何とか昨日やった。 次に必要そうなパッケージをインストールしていく。 必要になった段階でインストールすれば良いのではと思われるかもしれないが、これらのライブラリはほぼ間違いなく使うのでこれで良いのである。

yarn add @material-ui/core @material-ui/icons @material-ui/styles classnames prop-types react react-dom react-redux react-router react-router-dom react-virtualized react-vis redux redux-thunk

yarn add eslint eslint-config-airbnb eslint-plugin-import eslint-plugin-jest eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-react-hooks --dev

ちょっと話が変わるが、/var/lib/dpkg を消すという愚かな行為をしてしまった人はこの記事(How to recover deleted “dpkg” directory in Debian or Ubuntu – Anglehit)を参考に復旧すれば良いと思われる。 普通に考えてそんな奴滅多にいないと思うが…。 はい、すいません、自分です…。

モデリング

実際にコードを書いていく前にテーブルのモデリングをしていこうと思う。

user(id, name, display_name, email, encrypted_password, salt, created_at, updated_at)
routine(id, user_id, title, content, status, start_time, finish_time, color, days, created_at, updated_at)
routine_history(id, routine_id, event, created_at)
routine_calendar(routine_id, date, done)
diary(id, user_id, date, content, created_at, updated_at)

多分ここらへんだけで十分だろう。 それぞれのフィールドについては覚えていれば次の日記で説明する。 今日は眠気が異常なので寝ます。 全然作業が進まない…。

おやすみ。

2019/11/13

何とか無事に一日坊主にならずに帰ってくることが出来た。 今は第三のビールをカッ食らいながら、大量の野菜炒めの上に大量の豚が乗っているという、それはそれは粗末な自炊料理を胃袋に流し込んでいるところである。

第三のビールの中ではやはりプライムリッチが一番うまい気がする。 今まで飲んだ第三のビールの中では喉を通したときに嫌な感じが一番少ないし、度も6%と少し強いのでコスパが良い。 まあ出来ることならば本物のビールを浴びるように飲みたいものだが、あれは貧乏人には到底手が出ない代物である。

では、今日も技術ブログを始めることとする。


こうやって自分でサーバもクライアントも実装する時、何から始めるのが良いのかとても悩ましい。 今までは何となく、とりあえずサーバから作っておけばクライアントを実装する時にモックサーバを作ったりといった余計な工数をかけないで済むだろうなどというぼんやりとした理由から、サーバサイドから実装していたのだが、これが上手くいったためしがない。 よくよく考えれば当たり前と言えば当たり前なのである。 こんな仕事でもない、金が生まれるわけでもない、ただの自己満足のプロジェクトで、目に見える成果があまりないサーバサイドから実装していくのは確かにおかしい。

ということで、今回はまずフロントエンドから作り始めることとする。 順番的にはブラウザで動くフロントエンドをモックサーバと共に作り、そのモックサーバを参考にバックエンドサーバを作る。 その後それら二つを統合し、デプロイまでやる。 余力が残っていればスマホアプリまで開発する。 という形式にしようと思う。

環境構築

環境構築というほどのことは何もない。 npmさえ入っていれば npx create-react-app でWebpackの邪魔臭い設定なんか一切知らずともそれなりのReactの開発環境が構築できてしまうわけだから本当に良い世の中である。 未だにJavaScriptを書きもしないのに毛嫌いしている輩が多いが、パッケージ云々の話に限れば相当上手くまとめられてる気がしている。 Goのようにリポジトリが消される危険を常に孕みながら開発しなければいけないわけでもなく、JavaみたいにXSLやGroovyに奮闘する必要もなく、コマンド一つでそれっぽいことを割としっかりやってくれる。

なんということだ…。 VirtualBoxで立てたLubuntuで開発しようと思っていたのだが、Create React Appを実行する時点で、もうすでにディスク容量が100%で追加のパッケージがインストールできなかった。 そのため新規に仮想マシンを作り直して、諸々の初期設定をしていたらあっという間に時間が過ぎてしまった。 そして今とんでもない睡魔に襲われている…。 本格的な開発は明日からにすることにする。

では、おやすみ。

2019/11/12

柄にもなくブログを始めてみることにした。

最近、夜な夜な酒をカッ食らって、いつの間にか寝落ちしているということが毎日のように続いている。 飲み始めはNetflixでドラマを観たり、Nintendo Switchゼルダの伝説をやってたりはするのだが、急激な睡魔には抗えずすぐにやめてしまう。 そのためドラマは同じシーンを何回も繰り返し見直す羽目になるし、リンクは何時までたってもガノンを倒せない。

このままではいけない。 こうして退社してからの時間が酒だけにすり潰されてるのは流石に勿体なさすぎる。 しかし酒は飲みたい。 酒さえあれば全て世は事も無しなのである。 ただ、それ以上の実りのある生活を求めてもいるわけだ。

そこで今回ブログを始めたわけである。

自分のような筆の立たない人間がこうしてくだらない独白を書き残しておくという作業をしているだけで、たくさん考える必要がある分、酒の進み方は遅くなるし、現に今も焼酎のロックをチビチビ飲んでいるのだが一向に酔う気配がない。

しかし自分のように趣味も特技も、世の中をバッサバサと切り捨てていく鋭い感性も持たない人間が、ただ独白を書き残すブログをやっても三日坊主で終わってしまうのは火を見るよりも明らかである。 そこで今回は「技術ブログ」という要素を取り入れてみることにした。

他のことよりは多少プログラミングについての知識はあるし、曲がりなりにもウェブ企業のソフトウェアエンジニアとして働いているわけなのだから、ネタが尽きるはずがないわけであって、アウトプットをすることで自分のスキルアップにも多少なり繋がりそうである。 また基本的に自分は技術ブログを書くのが苦手なのだが、それは正確な情報を伝えなければいけないことに必死になり過ぎて一向に筆が進まないというのが主な理由であって、今回のように「酔っ払いが暇つぶしに書いているブログ」という前提なのであれば、そもそもそんな記事を信用する方がバカだと思うので、自分も肩ひじ張らずに自由に書くことができそうである。

素晴らしい! 非の打ち所がない! というところで、ここらで一日目やっていこうと思う。


以前から自分用のルーティン管理サービスが欲しいと思っていた。 例えば月曜日と木曜日はプッシュアップで上半身バンバン鍛えて、火曜と金曜日はスクワット、平日は英語の勉強を1時間、みたいなのを記録し成果を可視化するためのサービスである。 もちろんPlay Storeを探せば似たようなサービスはたくさんあるのだが、どれも今一つ痒い所に手が届かない。

例えば、今まで「一日あたり一時間英語の勉強」していたのを、これからは「一日当たり三時間」したくなったとする。 その場合、自分が見たほとんどすべてのアプリでは、今まで登録していた「一日当たり一時間英語の勉強」ルーティンを消して新しいルーティンを作るか、そのルーティン自体を編集するしかない。 すなわち今まで頑張ってきたルーティンの情報が消えてしまうのである。 ルーティンをこなすというのは結構つらいものであり、それを記録することで達成感を得て何とか続けられるものだと思うので、将来的に今の頑張りが記録から消えてしまうんじゃないかという不安を抱えたままアプリを使ってルーティンを続けるというのは中々辛いものがある。

なのでこれからしばらくは自分用の俺々ルーティン管理サービスを開発することにする。

サービス名

プロダクトを作るときに一番最初の障害になるのは命名である。 あんまり汎用的な名前にすると後々他のものと衝突して問題になるかもしれないし、あまりに突飛な名前だと自分自身気持ち悪くて触りたくなくなってくる。

というところで三十秒ほど熟考した結果、「Taskiee」という名前にすることにした。 これならあまり汎用的じゃないし、そこまで突飛じゃないと思う。

技術スタック

バックエンドは完全にモノリシックなアーキテクチャにし、Java + Spring Boot + Hibernetesで作り、DBは普通にMySQLを使うことにする。 フロントエンドはReact + Material UIの最近よくやっているパターン。 TypeScriptは使わない。 スマホ用のアプリケーションはReact Nativeを使ってみたいが、全然知識が無いので要調査である。 デプロイ先は適当にVPS借りてその上に、という形になると思う。 この際AWSGCP使ってみても楽しいのかもしれないが、自分のためだけに作るサービスにそこまでする必要はないだろう。 またルーティン管理サービスでよくあるプッシュ機能は色々面倒くさそうなので当面考えないことにする。


ダメだ。 睡魔が限界に達してしまった。 今日はリポジトリだけ作成して寝ることとする。

あと取りあえずGitHubでOrganizationも先に作っておいた。

完成して来たらコードをここに移す予定である。

では、おやすみ。