bouzuya.hatenablog.com

ぼうずやのにっき

2022-W38 ふりかえり

2022-W38 をふりかえる。

2022-W38 の目標 とその記事

目標。

記事。

つくったもの

(なし)

よんだもの

みたもの

  • 『竜とそばかすの姫』 (2022-09-19)
  • 『オールド』 (2022-09-24)

その他

勉強会。

(なし)

おでかけ。

  • 掬星台 (2022-09-25)

ゲーム。

買い物。

(なし)

体調。

(なし)

育児。

  • 上の子は就寝前に「とんとん」してと甘えてくる (2022-09-19)
  • 上の子はひらがなをふつうに読むようになっている (2022-09-23)
  • 下の子は複数のパズルのピースを混ぜる
  • 下の子は復唱する形でなら「うどん」を言えるようになった

2022-W38 はどうだったか。

気温が急に下がった。月曜日と金曜日が祝日で 3 連休と 3 連休の週だった。さらに間の 1 日に子どもが体調不良だったのでひどい勤務状況になっていた。

2022-09-21 から実装の際に考えていたことを書き出して載せることを試している。

目標に設定していた『ソフトウェアテスト技法練習帳』はもうやる気が出なさそうなので流し読みして終わらせてしまった。

AtCoder は ABC270 に参加した。 1161 → 1181 (+20) (https://atcoder.jp/users/bouzuya/history/share/abc270) 。毎日問題を解いている。 PAST #10 の問題を解いている。 2022-12 のものを受験しようかと考えている。

朝・夜のコミットを続けている。 rust365 (2022-02-19) は twiq を進めている。 Event の永続化まわりの問題を減らしている。前述の通り実装メモを書くようにしている。

ラジオ体操・懸垂・フィットボクシング 2 を続けている。

Slay the Spire をプレイし続けている。ここまでにアイクラアセンション 20 堕落の心臓を合計 3 回倒している。

2022-W39 の目標

  • 2022-09 ふりかえりを書く

TODO: 2022-09 ふりかえり

ABC270 に参加した / twiq 実装メモ (4)

ABC270 に参加した。 1161 → 1181 (+20) 。 D も F もうまくやれば解けそうな気がした……。 E が解けたのは良かった。解けなかったらかなり落ちたはず。

https://atcoder.jp/users/bouzuya/history/share/abc270


bouzuya/rust-sandbox twiq 実装メモ (4)

作業のスタックの把握。

  • user を解決するところまで動作させたい
  • repository などの実装が提供されていない
  • EventStore trait を実装したい
  • FirestoreEventStore は一意性検査などで時間がかかってしまう
  • InMemoryEventStore を使う InMemoryUserRepository をつくりたい
  • User::from_event_stream をつくりたい
  • RawEvent (event_store_core::Event) から Eventtype が原因でうまくとりだせない

Event, EventType, EventStream, EventStreamType の ERD 。

erDiagram
  Event
  EventType
  EventStream
  EventStreamType

  Event }o--|| EventType : ""
  Event }|--|| EventStream : ""
  Event }o--|| EventStreamType : "(via EventType)"
  EventType }|--|| EventStream : "(via Event)"
  EventType }|--|| EventStreamType : ""
  EventStream }o--|| EventStreamType : ""
  • impl TryFrom<RawEvent> for Event をつくっていく
  • 各 aggregate event に type を追加する
  • impl TryFrom<RawEvent> for domain::aggregate::x::Event をつくる
  • domain event と aggregate event の重複が多いので RawEvent への変換をひとまず domain event のみにして domain event と aggregate event 間の変換を設ける

今日のコミット。

PAST #10 の J を解いた / twiq 実装メモ (3)

PAST #10 : 第10回 アルゴリズム実技検定 過去問 の J を解いた。


twiq 実装メモ (3)

作業のスタックの把握。

  • user を解決するところまで動作させたい
  • repository などの実装が提供されていない
  • EventStore trait を実装したい
  • FirestoreEventStore は一意性検査などで時間がかかってしまう
  • InMemoryEventStore をつくった
  • InMemoryEventStore を使う InMemoryUserRepository をつくりたい
  • User::from_event_stream が未実装だった
  • EventStream をつくった

2022-09-21 User aggregate への 2022-09-22 EventStream の適用から。

User::from_event_stream の追加

  • InMemoryUserRepositoryInMemoryEventStore から取得した Vec<Event>User aggregate を再構築しようとして未実装なのに気づいた
  • User aggregate に手を入れるなら EventStream を実装しても良いかもしれない
  • event_store_core::Event から domain::aggregate::user::Event への変換ができない
  • EventData::as_str があっても良さそう
  • event_store_core::EventJSON に type field を入れるタイミングでおかしくなっている
  • 別トピックとして考える

Event の deserialize 。

  • domain::aggregate::user::Eventserde_json::from_strtype field がないと怒られてしまう
  • domain::aggregate::user::Event::Createdtype を消費してしまうので UserCreated に含めようとしてもできない
  • 一方で UserCreated に含めておかないと EventDatatype が残らなくなってしまう
  • 何段階かに分けて複数回 deserialize すると良さそう
  • event type で適切な aggregate event に処理を振り分ける
  • aggregate event でも event type で適切な event に処理を振り分ける
  • event type は全体で一意でないといけない
  • EventData に event type が埋もれているのはまずそう
  • まずいと考える理由は event type で判定したい場合に EventData を parse して取り出さないといけないから
  • domain event / aggregate event / event という階層は良くないかもしれない
  • 良くないと考える理由は aggregate event と domain event で 2 つの type を定義する必要が出るので
  • event をフラットに扱った上で aggregate event に使う形を取るほうが良いかもしれない
  • EventType を別トピックで考えよう

EventType

  • EventType とは何か
  • Event の分類の 1 つ
  • 他の分類として EventStream がある
  • Event は 1 つの EventType を持つ
  • EventType は 1 つの aggregate (≒ EventStream type) に属する
  • たとえば UserCreatedUser aggregate に属し、同時に UserRequest aggregate に属することはない
  • EventStream を横断する Event を指すものとしての domain event
  • EventStream ごとの Event を指すものとしての aggregate event
  • EventTypeEventStream を横断しているので domain event 側に入りそう
  • ひとまず event_store_core::EventType を追加する
  • それに対応する domain crate における EventType を追加する
  • event_store_core::Event と同様に相互変換できるようにする

EventStreamType

  • EventStreamType も event_store_core に含めるべきか……?
  • 永続化された情報に含められていると、どの aggregate か分かって便利そう
  • 復元時に使えそうな気もするけど EventType から導出できるので必須ではなさそう
  • ひとまず event_store_core には EventStreamType の追加なしで進める

上の子がひらがなを読むのは可能になっていて成長を感じる。


今日のコミット。

PAST #10 の I を解いた / twiq 実装メモ (2)

PAST #10 : 第10回 アルゴリズム実技検定 過去問 の I を解いた。

  • I - 対称変換 https://atcoder.jp/contests/past202203-open/tasks/past202203_i
    • 提出: https://atcoder.jp/contests/past202203-open/submissions/35047419
    • 操作が 0 回で一致する場合は S = T なのでソートして一致するかを調べれば良い
    • 操作が 1 回で X 軸に平行な直線で対称移動する場合は ST の点の X 座標は一致し Y 座標はどこかを基準に対照なので、 SX の昇順 Y の昇順 TX の昇順 Y の降順で並べて、 1 件目で基準位置を求めた後残りがすべて一致することを調べれば良い
    • Y 軸に平行な直線で対称移動する場合も同様に考えれば解ける
    • 二つの点の間を取ると小数になるが、間を取る必要はなくて和をとって一致していれば十分のはず

実装メモ

2022-09-21 の EventStream の続き。

  • Vec<Event> となっているが EventStream にしたほうが良い箇所がありそう
  • EventStream は単一の EventStreamId を持ち、単調増加する EventStreamSeq を持つ
  • ↑の定義から一部は Vec<Event> で残すことになりそう (EventStreamId を横断する場合がある)
  • 「単一の EventStreamId を持つ」という部分を削る選択肢もあるだろうけど、現状は EventStream のグループごとに取り得る event type が分類されているので、 EventStreamId ごとに区切るほうが良さそう
  • EventStream は aggregate の実装の共通部分を削減する上で効果がありそう
  • EventStream への追加のために EventStreamSeq の増加など定形処理が多いので削れそう
  • 現在の目標から外れているので保留する
  • 空の Vec<Event> はあり得るか (空を許容するか)
  • 空を許容しない場合は EventStore::find_event_stream の戻り値は EventStream ではなく Option<EventStream> になる
  • 空を許容する場合は EventStreamId を保持すべきか
  • 空を許容かつ EventStreamId を保持しない場合は EventStream::id の戻り値は EventStreamId ではなく Option<EventStreamId> になる
  • EventStream から aggregate を復元する場合に EventStream が空で得られていると Option<A> を返すべきところで Result::Err になりそう (判断が面倒になりそう)
  • 取り得る状態をより簡素にするため、今回は空を許容しない形で進める

EventStream の属性。

  • id, seq, events を追加した
  • id はすべての Vec<Event> に共通の EventStreamId
  • id は取れないと不便そう
  • seqVec<Event> の最後の EventEventStreamSeq
  • 永続化する際に更新前・更新後の EventStreamSeq が必要になる
  • 更新前・後の履歴管理は複雑になるので避けて aggregate ごと clone する
  • Clonederive に入れておく必要がある
  • eventsVec<Event>
  • 永続化する際に 1 件ずつ Event を取り出したいため
  • 順序は EventStreamSeq の昇順で問題ないはず
  • aggregate では Event の追加がある
  • EventStream::push(Event) として単純に Event を追加するのは欲しい
  • EventId の生成や EventStreamId の指定や EventStreamSeq のインクリメントを自動でやってほしい
  • 名前に迷う
  • もう Event の生成はほとんど隠蔽してしまっても良い気もする
  • 基本的なユースケースとしては EventData を渡して残りの情報は保管してもらうで良さそう
  • EventStream 自体の生成はどうなる……?
  • Vec<Event> から生成する想定だけど最初の Event の生成を隠蔽してしまうと困る
  • EventStream::empty(EventStreamId) のような形で生成できると良いけど空は許容されていない
  • EventStream::generate(EventData)
  • EventStream::push(EventData)
  • EventStream::push_event(Event)
  • Event を push することのほうが少なそうなのと generate 側を EventData にしたので pushEventData に譲って push_event とした

今日のコミット。

PAST #10 E, F, G, H を解いた / twiq 実装メモ

PAST #10 : 第10回 アルゴリズム実技検定 過去問 の E, F, G, H を解いた。


実装時に考えたことをメモしておくと良いかもしれない。毎日貼っているコミットの URL と合わせてみると良いかもしれない。そう思ったので試しに書いてみる。

bouzuya/rust-sandbox の twiq の実装メモはリポジトリにすこし残している。

https://github.com/bouzuya/rust-sandbox/tree/389a2b447463a061ec126bf7d9e4fd5d1022a8a0/twiq/docs

EventStore trait の簡素化

  • EventStore trait のメソッドをもうすこし簡素化したい
  • find_eventsfind_events_by_event_id_after の二種類がある
  • after: Option<EventId> を引数にして統一して良さそう
  • 時間的な余裕があるなら criteria にしておくほうが良さそう
  • 見えているユースケースが「ある EventId よりも後のもの」だけなので after: ... で進める

EventStream の追加

  • Vec<Event> となっているが EventStream にしたほうが良い箇所がありそう
  • EventStream は単一の EventStreamId を持ち、単調増加する EventStreamSeq を持つ
  • ↑の定義から一部は Vec<Event> で残すことになりそう (EventStreamId を横断する場合がある)
  • 「単一の EventStreamId を持つ」という部分を削る選択肢もあるだろうけど、現状は EventStream のグループごとに取り得る event type が分類されているので、 EventStreamId ごとに区切るほうが良さそう
  • EventStream は aggregate の実装の共通部分を削減する上で効果がありそう
  • EventStream への追加のために EventStreamSeq の増加など定形処理が多いので削れそう
  • 現在の目標から外れているので保留する

InMemoryEventStore の追加

  • InMemoryUserRepositoryHashMap ではなく EventStore にして共有しないと他の repository を追加した際に困る
  • FirestoreEventStore を進めても良いがまだ一意性の検査などに時間がかかるので InMemoryEventStore を作って先に進めたい

User::from_event_stream の追加

  • InMemoryUserRepositoryInMemoryEventStore から取得した Vec<Event>User aggregate を再構築しようとして未実装なのに気づいた
  • User aggregate に手を入れるなら EventStream を実装しても良いかもしれない
  • 明日はここから

今日のコミット。

PAST #10 の A, B, C, D を解いた

PAST #10 第10回 アルゴリズム実技検定 過去問 の A, B, C, D を解いた。


急に寒くなった。


今日のコミット。

ABC075 の A, B, C, D を解いた

ABC075 : AtCoder Beginner Contest 075 の A, B, C, D を解いた。


『竜とそばかすの姫』を観た。話が全体的に散らかっている。 U の AS 、現実世界と 1:1 に対応しており U の世界での失敗にやりなおしが効かないのに「やり直せます」みたいなフレーズで売っていることへの嫌悪感が強い。


上の子が寝るときに「とんとんして」などと甘えてくる。下の子を見て甘えたくなる、そんな時期なのだろうか。


今日のコミット。