Closed14

「TODOアプリづくり」で知識の整理 (+ write code every day)

ピン留めされたアイテム
aocmaocm

このスクラップについて

概要

自分が知っている知識を駆使+新しい領域にチャレンジして「TODO管理アプリ」を真面目に作ります。
このスクラップには、考えたことや知ってることをアプリ開発を通して気づいた・思い出したベースで記録していこうと思います。

目的

  • 知識の整理と記録すること
  • 正しいかわからないが、考えたことを残すこと

目的じゃないこと

  • 人に読んでもらうために文章練習
    • 基本的に人に読んでもらうときは記事にする
    • スクラップは、記事にするための下書きになると思われる

※指摘・質問コメントは大歓迎です。

なぜ始めたか

仕事でかなりいろいろなことを経験して、何度か力不足を痛感して挫折しかけて、それを乗り越えてきました。
入社してから3年分の知識は、そこそこ膨大になったけれども、それらは形あるものとしてあまり残せていないのが現状です。

誰にも評価してもらってないこの知識は、本当に価値のあるものなのか。
「自分はそこそこできるようになったかも☺」という気持ちは井の中の蛙でしかないのではないか。

そこで、「TODOアプリ」を知ってる知識を整理しながら作ってみようかなと思います。

題材「TODOアプリ」なのはなぜか

  • ドメイン知識がイメージしやすいこと(TODOを記録する、という基本概念はイメージしやすく見てもらうひとに説明する内容が少なく済む。)
  • 小さく始めることもできる(初心者の作ってみたの題材になることもあるし、スコープを小さくして始めることが可能)
  • 発展性も高い。(カンバンボードにしたり、業務で利用できるものまで昇華させてもよい。)

なんでもよかったのですが、この辺の理由からこれを選びました。
もっと作りたいものができたらそちらにするかもしれません。


最終的に人にみせることで、人から見た自分の評価がもっと輪郭がはっきりするし、入社したころの「わからないこともわからないだらけ」の自分への道しるべになるかなと思います。

また、自分の中で代表的な作ってみたものをもっていると新しいことを試すときに評価がしやすいと思うので、ずっと何か作りたいとなお持っていました。

車輪の再発明は無駄といわれますが車輪の再実装は価値があると思います。

前置きはこれくらいにして、明日から少しずつ継続的に更新していこうと思います。

aocmaocm

全体的な進め方

  • githubにパブリックリポジトリを作成して、設計と実装したものを管理する
  • 考えたことやTipsはスクラップに
  • イテレーションを2週間で設定し、短期間で目標をたて、設計して、実装して、ふりかえることをしていく(ひとりアジャイル開発)
    • この進め方自体もふりかえり時にかえるかどうか判断する
    • (3/25追記) write code every dayで毎日コツコツ積み重ねていくこととする(別のリポジトリにコミットした日はTODOアプリ関係はお休み)
aocmaocm

プログラム練習・なにかアプリ作るときにやってること

  • リポジトリを新しく作成する
    • githubで作成 https://github.com/new (readmeとLICENSEファイルを作っておく)
    • ローカルにクローン
PS D:\workspace\repos> git clone https://github.com/aocm/my-todo-app-challenge-prototype.git
Cloning into 'my-todo-app-challenge-prototype'...
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (4/4), done.

このタイミングでの各便利ツールの紹介とセットアップ

  • GitのGUIクライアント(なんでもいいけど、以下に一例)

    • gitkraken
    • sourcetree
  • VSCodeの拡張機能

    • Project Manager... 画像のように、プロジェクトのパスを設定できる。簡単に別のディレクトリを開けるようになるので、VSCodeでいろいろ触るひとはおすすめ。
aocmaocm

write code every dayにも挑戦

t_wadaさんの講演を聞いて挑戦することにしました。

aocmaocm

Day1

  • リポジトリ作成+Quasarセットアップ

Day2

  • 画面レイアウト作成

Day3

  • 画面レイアウトを意識して、Tasks.vueを作成

ここで気づいたが、main(デフォルト)ブランチに反映されるまで芝にならない。

aocmaocm

Day4

https://github.com/aocm/my-todo-app-challenge-prototype/commit/20d247e07cbc61e7539becf20ca18f698e889a86

やったこと

  • AtomicDesignを意識して、コンポーネントを分解。
    • atoms→components/atomsに作成(今回はQuasarのパーツがatomsとして、いったん)
    • molecules→components/moleculesに作成(今回はタスクアイテムを配置)
    • organisms→components/organismsに作成(今回はタスク一覧コンポーネントやメニュー一覧コンポーネントを配置)
    • templates→layoutsに作成。organismsらを組み合わせる役目。(今回はタスクページの見た目を担う)
    • pages→pagesに作成。templatesにデータを投入する役目。(今回はタスクページのデータ管理を担う。今後はここにAPI操作やStore管理する)

考えたこと

今後はStorybookでコンポーネント管理するのは決めているけど、データ管理をどうするかは悩み中。
今のかきっぷりだと、バケツリレーになってしまうが、そういうもんだろうか。要調査。

aocmaocm

Day5

https://github.com/aocm/my-todo-app-challenge-prototype/commit/d31abf4cb6af61bf40871dd07470efcebf8ad486

やったこと

  • TaskListとTaskItemのEmitでイベント受け渡し

考えたこと

  • コンテナの中で作業していると、npm(/yarn)モジュール追加がすごく遅く感じる。ホストPCはネットワークは100mbpsでているのにコンテナ内は明らかに遅い。
    • Dockerのメモリ割り当て2GBしかしてないことが原因であればちょっと拡張してもう一度試す。もしくは、開発環境をコンテナからWSL2とかに変えてみようかと。
  • QuasarのものにStorybookを追加することにてこずっている。そもそもStorybookを使ったことがないので、VueCliでつくったシンプルなプロジェクトで試してみたほうがいいかもしれない。

aocmaocm

Day6(2021/2/28)

https://github.com/aocm/my-todo-app-challenge-prototype/commit/695f0894826c32251e695c70013bb996c62c9dd2

  1. いったんフォルダ構成を変更する。
  2. Quasarパターンの隣にStorybookを使ったコンポーネント管理したフロントを配置しようとおもったのだけれど、QuasarとStorybookの組み合わせがうまくいかず

Day7(2021/3/1)

https://github.com/aocm/try-tutorial-storybook-vue/commit/f79f78df13bc3780d1d1a20e727e25e0c7330776
Storybookがそもそも不慣れなので、Storybookの公式ページを写経しながら練習してみる
https://storybook.js.org/tutorials/intro-to-storybook/vue/en/get-started/

理解ふかまってから元のTODOアプリに合流する

aocmaocm

2021/3/2

https://github.com/aocm/try-tutorial-storybook-vue/commit/715499d69677a91f978d3bb463394eacef02f8e8

Storybookの公式ページを写経つづき

2021/3/3

Storybookの公式ページを写経つづき(composite-component)
https://storybook.js.org/tutorials/intro-to-storybook/vue/en/composite-component/

ここでミスが。

Automated Testingの項目で真似してかくも、テスト失敗する

 FAIL  tests/unit/TaskList.spec.js
  ● renders pinned tasks at the start of the list

    expect(received).not.toBe(expected) // Object.is equality

    Expected: not null

      22 | 
      23 |   // We expect the pinned task to be rendered first, not at the end
    > 24 |   expect(firstTaskPinned).not.toBe(null);
         |                               ^
      25 | });

      at Object.<anonymous>.it (tests/unit/TaskList.spec.js:24:31)

やったこと・考えたこと

  • :nth-childってなんだ?

  • セレクターの書き方がミスってるんか?

    • これならnullじゃなかったconst firstTaskPinned = vm.$el.querySelector('.list-item:nth-child(1)');
    • TASK_PINNEDが誤っているっぽい。
    • .list-item:nth-child(1).TASK_PINNED ... あれ、stateに渡すことはしたけどクラス指定したっけ?
    • 書き漏れでした。simple-componentのBuild out the states <div class="list-item" :class="task.state">
  • TaskListのテストは通るようになったけど、(当たり前だが)スナップショットテストが落ちた。

$ vue-cli-service test:unit
 PASS  tests/unit/example.spec.js  
 PASS  tests/unit/TaskList.spec.js      
(node:18140) DeprecationWarning: \`storyFn\` is deprecated and will be removed in Storybook 7.0.

https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-storyfn
 FAIL  tests/unit/storybook.spec.js (7.666s)

略

 › 3 snapshots failed from 1 test suite. Inspect your code changes or re-run jest with `-u` to update them.

Test Suites: 1 failed, 2 passed, 3 total
Tests:       3 failed, 6 passed, 9 total
Snapshots:   3 failed, 4 passed, 7 total
Time:        9.012s
Ran all test suites.
PS C:\workspace\repos\taskbox> yarn test:unit -u
yarn run v1.16.0
$ vue-cli-service test:unit -u
 PASS  tests/unit/example.spec.js  
 PASS  tests/unit/TaskList.spec.js      
(node:5628) DeprecationWarning: \`storyFn\` is deprecated and will be removed in Storybook 7.0.

https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-storyfn
 PASS  tests/unit/storybook.spec.js (7.548s)
 › 3 snapshots updated.

Snapshot Summary
 › 3 snapshots updated from 1 test suite.

Test Suites: 3 passed, 3 total
Tests:       9 passed, 9 total
Snapshots:   3 updated, 4 passed, 7 total
Time:        9.577s
Ran all test suites.
Done in 11.11s.

https://github.com/aocm/try-tutorial-storybook-vue/commit/547876194aff193e9ffcc8e7835950ddb216330c

aocmaocm

2021/3/4

https://github.com/aocm/try-tutorial-storybook-vue/commit/38a73d6c84a09f4d731ade999b0a8e00e21fea6c

今日の対象

VuexとStorybookのつながりが疑問だったのでこの章をやって何点か気づきがあった。

  • PureTaskList.vueとTaskList.vueの分解はテスト容易性の話から行っていたが、AtomicDesignの文脈のTemplateとPagesの分解をみているようだった。AtomicDesignを実用性もたせるためにドメイン知識を持たせるorganismsからVuexを絡ませるというQiita記事を思い出した。TaskListというコンポーネントであることも踏まえると、比較的このQiita記事の考え方がStorybookと相性がいいのかもしれない。
  • PureTaskList.vueにemitの受け口つけてないけどどうするんだろうと思っていたが$listenersが肝っぽい。(これを外したら処理がよばれなくなった。)
$listeners考察
TaskList.vue(親)
<template>
  <PureTaskList :tasks="tasks" v-on="$listeners" @archive-task="archiveTask" @pin-task="pinTask" />
</template>
PureTaskList.vue(子)
    <template v-else>
      <Task v-for="task in tasksInOrder" :key="task.id" :task="task" v-on="$listeners" />
    </template>

https://jp.vuejs.org/v2/guide/components-custom-events.html

listeners プロパティを使うことで、コンポーネントの全てのイベントリスナを v-on="listeners" を使って特定の子要素に送ることができます

TaskList.vueのイベントリスナを全部PureTaskListコンポーネントに送り付け、
PureTaskList.vueはそれを受け取ってそのリスナふくめてTaskコンポーネントに送り付けている?

現時点だとTaskList.vueのv-on="$listeners"はなくてもうごくが、さらに親(TaskList.vueを含めたコンテナ・Page)が作られたときなどに親から渡されたときにいい感じにバケツリレーしてくれる、という感じだろうか。

Tips propsに書いていない属性

https://qiita.com/shinobu_shiva/items/e0c458aa6c1e683a9881

Vueでは、propsに書いてないattributeはコンポーネントのルート要素に設定される。。。知らなかった、、、

なるほど。

これのソースを探したらv3の記事しか見当たらなかったけど、たぶんv2系でも同じってことなんだと思われる。

https://v3.vuejs.org/guide/component-attrs.html#attribute-inheritance

When a component returns a single root node, non-prop attributes will automatically be added to the root node's attributes.
(DeepLで翻訳:コンポーネントが単一のルート・ノードを返す場合、非プロップ属性はルート・ノードの属性に自動的に追加されます。)

aocmaocm

2週間分のまとめ。

2021/3/5

https://github.com/aocm/try-tutorial-storybook-vue/commit/eed1e38912c1e0351366ccb42bf7703f2333b23f
https://github.com/aocm/try-tutorial-storybook-vue/commit/8c655654d0e43a751c234a6cc65632ccf4b9f6f1

エラーで表示が分岐する方法を記載している。
あまりerrorのもとになる情報をStoreで管理すればいいので、とても扱いやすいと率直に感じた

2021/3/6

https://github.com/aocm/my-todo-app-challenge-prototype/commit/fb2d7fd6a3b8bfa15b818b6a78e9d160f7479b30

QuasarにStorybookを追加する方法がわからなかったので、方向転換としてまずVueCLIのVue2デフォルトプリセットで作成して試してみることにする。
※とりあえずvue createまで

2021/3/7

https://github.com/aocm/my-todo-app-challenge-prototype/commit/7c42c4c5d47bbb61f715ad78a88c74ecfbe05fac
Vue2のデフォルトアプリにStorybookを追加してみる

2021/3/8

https://github.com/aocm/my-todo-app-challenge-prototype/commit/a2c686a2742c55941ef58d7dfb62b816ea5033bd
既存のVueアプリへStorybookを追加する方法がわかってきたので、とりあえずQuasarアプリにもStorybookを追加・起動するところまで。

2021/3/9

https://github.com/aocm/my-todo-app-challenge-prototype/commit/8820c3724194c2b26f6ffe9ce9f2a8d0f187e1e6

storyを追加してみる。
ただし、Quasarのスタイルが全く効かない。

2021/3/10

https://github.com/aocm/my-todo-app-challenge-prototype/commit/7a581d2e6a82e5530a076f01bb35c6f90b0f5f2b
QuasarをStorybookに読み込ませる必要があった。
ただし、Storyで起動しようとするとTaskListがエラーでてしまう。
<q-page-container>がトップレベルにあるのが問題なのか?

※エラーログを控え損ねたが、この日のコミットログでチェックアウトして試せば確認できるはず

参考記事
https://dev.to/yemolai/using-storybook-with-quasar-3090

2021/3/11

https://github.com/aocm/my-todo-app-challenge-prototype/commit/fdb8b44e1b7c2788a73a4ff2542422accd9c05d5
アクションを追加してみる。
なぜexport const actionsDataと、エクスポートしているのかわかっていなかったが子供コンポーネントのアクションをそのまま使いたいときに便利なんだと気づく。

写経をちゃんと考えてやっていないことがばれる。。。

2021/3/12

https://github.com/aocm/my-todo-app-challenge-prototype/commit/ed60952df639ef5e8b044d81878cf34ea8b321bd

メニュー一覧コンポーネントもStorybookにしてみる。
汎用的なコンポーネントなので、入力によって表示が大きく変わるのでStorybookの強みが出るなと思った。
Storyもうちょっと加えてもよかったかもしれない。

2021/3/13

https://github.com/aocm/my-todo-app-challenge-prototype/commit/f55d2992b304c5c16642257cdd23d45217d4db3f

layouts(AtomicDesignでいうTemplateの役割で区切っている)がStoryで表示できるのはすごくいいなと思った。

課題なのが、コンポーネントの解決がうまくいかない。
Storybookだとちゃんと相対で表記しないといけなく、Quasarだとcomponentsからでエイリアスが組めている。
Webpackのコンフィグをいじった(2021/3/10のコミット)のに、なぜうまくいかないかがよくわからない。。
JavaScriptの理解不足が痛い。

- import TaskList from 'components/organisms/TaskList.vue'
- import MenuList from 'components/organisms/MenuList.vue'
+ import TaskList from '../components/organisms/TaskList.vue'
+ import MenuList from '../components/organisms/MenuList.vue'

2021/3/14

https://github.com/aocm/my-todo-app-challenge-prototype/commit/54bf57ed5d9470139ff54c78a248d84e515aa7f8

Storeのファイルをexampleのコピペで作ろうとしていたが、
「quasarはコマンドでStoreのファイルを生成ができる」ということを思い出したの利用してコミット。

$ quasar new store tasks

2021/3/15

https://github.com/aocm/my-todo-app-challenge-prototype/commit/e2de9578341ec7f40349c18ccdfffc50f9de9207

Vuexの書き方がプロジェクトごとにいろいろあって、Quasarのデフォルトの書き方の使い方がぱっとみで理解できなかった。
根本的な使い方をちゃんと学ばないといけないと感じた。

2021/3/16

https://github.com/aocm/my-todo-app-challenge-prototype/commit/56c5745bfb802a8b3f5a7448fc9138708b35f59e
レイアウトの通りになるように書き加えた。
この内容で一回コンポーネントをつくると、エラーになってしまったため、一回コンポーネントをわけずに作成。
q-footerを一番トップレベルに宣言しているからだろうか。

      <q-footer bordered class="bg-white text-primary">
        <q-list class="rounded-borders">
          <q-item>
            <q-item-section>
              <q-input color="" v-model="text" label="add tasks">
                <template v-slot:prepend>
                  <q-icon name="add_tasks" />
                </template>
              </q-input>
            </q-item-section>
          </q-item>
        </q-list>
      </q-footer>
TypeError: Cannot read property 'view' of undefined
    at VueComponent.fixed (http://localhost:6006/vendors~main.6aec0e0f20b9a40ac5b0.bundle.js:115681:21)
    at Watcher.get (http://localhost:6006/vendors~main.6aec0e0f20b9a40ac5b0.bundle.js:200594:25)
    at Watcher.evaluate (http://localhost:6006/vendors~main.6aec0e0f20b9a40ac5b0.bundle.js:200699:21)
    at VueComponent.computedGetter [as fixed] (http://localhost:6006/vendors~main.6aec0e0f20b9a40ac5b0.bundle.js:200949:17)
    at VueComponent.classes (http://localhost:6006/vendors~main.6aec0e0f20b9a40ac5b0.bundle.js:115711:20)
    at Watcher.get (http://localhost:6006/vendors~main.6aec0e0f20b9a40ac5b0.bundle.js:200594:25)
    at Watcher.evaluate (http://localhost:6006/vendors~main.6aec0e0f20b9a40ac5b0.bundle.js:200699:21)
    at Proxy.computedGetter (http://localhost:6006/vendors~main.6aec0e0f20b9a40ac5b0.bundle.js:200949:17)
    at Proxy.render (http://localhost:6006/vendors~main.6aec0e0f20b9a40ac5b0.bundle.js:115758:19)
    at VueComponent.Vue._render (http://localhost:6006/vendors~main.6aec0e0f20b9a40ac5b0.bundle.js:199663:22)
aocmaocm

ここ最近更新できてませんでしたが、なるべくコミットはし続けていました。
この空白の1か月半分の活動を簡単にまとめると、

だいたいフロント側はVue3とCypress、サーバーサイドはDDD(ついでにSpringBoot)に興味があった感じ。

aocmaocm

TODOアプリのために参考にしたブログ

松岡さん(little_hands)のブログ

ドメイン駆動設計のための Spring の上手な使い方

  • DDDとSpringの相性を整理していた時に見つけた、増田さんのSlideshare。SpringBootふくめSpringでDDDやモデリングするときは見直したい。

モデリングもしないでアジャイルとは何事だ

  • Iwao Haradaさんの記事。「"設計する"と"設計書をかく"は違う」ということをうまく自分の言葉にできなくて悩んでいたときに見つけた。
このスクラップは2021/10/20にクローズされました