【ルーティン】36歳パパエンジニアの日常 2021/4/6(火)

目次

今週の目標

  • CS50W Project4 1つ機能作る
  • 2社目の会社のスキルチェック課題を終わらせる
  • 長女と公園に行く
  • 金魚の水槽を洗う
  • SQLアンチパターン読破
  • ブログ1本書く
  • 父親の退職祝いを送る

今日の目標

娘たちが義実家から帰宅。

ここからいかに娘たちとの時間を取りつつ、自分のルーティンを守り通すかの戦いが始まる。

5:40 起床・シャワー

昨日娘らが帰ってきたゴタゴタでシャワーを浴びれなかったので朝シャン。

6:30 長女にメシをあげつつ、ルーティンブログを書く

ちょうどパソコンを開いたところで、長女が起きてリビングにやってきた。

さあやるぞとなった時に、子供が来るのはあるあるである。

ロールパンとヨーグルトをあげつつ、

「お父さんはちょっと勉強するからね〜」

と宣言してルーティンブログを書く。時折長女と雑談をはさみつつも、きちんと書けた。イケる。

こうしてなにか、アウトプットする様を見せれるのは良いことだと勝手に思っている。

「勉強しなさい!!」

とか子供に言いつつ自分はずっとテレビとか見てる、みたいな親には昔からなりたくなかった。自分の怠惰を棚にあげて他の人に勤勉を強要するのはいかにもバカがやりそうなことだと思っている。

アドラー心理学的にも、子供に対して「勉強しなさい!」とか言うのは愚策だと証明されている。背中で語りたいね。

9:00 CS50W Project4をやる

今日も今日とてCS50W。Twitterクローンサイトの作成だ。

class ユーザーに関するリポジトリのテスト(TestCase):
  def setUp(self):
    self.user = User(
      UserId(1),
      UserName('yhei_hei'),
      UserProfile('yhei desu')
    )

  def test_1(self):
    '''ユーザーの作成、保存ができること'''
    repository = UserInMemoryRepository()
    self.assertEquals(
      self.user,
      repository.save(self.user)
    )
  
  def test_2(self):
    '''ID指定でユーザーの取得ができること'''
    repository = UserInMemoryRepository()
    repository.save(self.user)
    self.assertEquals(
      self.user,
      repository.find(UserId(1))
    )

Userのリポジトリに対するコードを書いていた。

Userエンティティをリポジトリ経由で保存し、UserId値オブジェクトを使ってfindメソッドで検索して取り出す、みたいな。

Userエンティティの定義は下記。

class User:
  def __init__(self, id: UserId, name: UserName, profile: UserProfile):
    self.__id = id
    self.__name = name
    self.__profile = profile

  def __str__(self):
      return f'{self.__id.__str__()} {self.__name.__str__()} {self.__profile.__str__()}'

  def get_id(self):
    return self.__id

UserエンティティはUserIdという値オブジェクトを持っている。

リポジトリの定義は下記。

from network.domain.models.users import User, UserId

class UserInMemoryRepository:
  def __init__(self):
    self.users = []
  
  def save(self, user: User):
    self.users.append(user)
    return self.users[-1]

  def find(self, user_id: UserId):
    # 値オブジェクト側に等価性の関数を用意して比較せよ

findメソッドで、渡されたUserIdオブジェクトをもとに、Userが保存されたリスト内からUserIdが合致するUserを探す。

ユーザーIDが普通のint型ならたやすいが、UserIdオブジェクトなので、普通に等価性を比較できない。例えば下記のような記述だと、うまく比較できない。

  def find(self, user_id: UserId):
    for user in self.users:
      if user.get_id() == user_id: // オブジェクト同士の比較だと等価性が評価できず全てFalse
        return user
    return None

おまけにUserIdオブジェクトのpropertyはprivateである。

UserIdオブジェクト側に、equals(user_id : UserId)みたいなメソッドを作って、比較をする必要がある。

このめんどくさい感じ。DDDっぽくなってきた。

12:30 昼メシ後、CS50W

引き続きCS50W。割愛。

19:20 帰宅

帰宅したらちょうど長女と次女が2階に上がって寝ようとしているところだった。

ぼくの姿を見た次女が喜びの奇声をあげながら降りてきた。可愛い。

可愛いが、覚醒してはたまらんので、「ただいま!!!!! おやすみなさい!」と笑顔で言って急いでリビングに引っ込んだ。

21:00 SQLアンチパターンを読む ツリー構造のDB設計のアンチパターン

メシを食べて風呂から出たら、散乱しているオモチャを片付け、シチューでギトギトのダイニングを拭き、子供達の皿の残骸をシンクに突っ込む。

シチューを使って水遊びをしたのかってぐらい汚れてた。重曹スプレーをつけないと落ちないレベル。

ダイニングにカバーをかけておいてよかったと実感する。

その後、SQLアンチパターンを読む。

ツリー構造のテーブル設計のお勉強。

例えば、下記のようなスレッド構造ってあるじゃないすか。

  • (1)このバグの原因は何かな?
    • (2)ヌルポインタのせいじゃないかな?
      • (3)そうじゃないよ。それは確認済みだ
    • (4)無効な入力を調べてみたら?
      • (5)そうかバグの原因はそれだな
        • (6)よし、じゃあチェック機能を追加してくれるか

このような場合、親IDを持たせて下記のようなテーブルを組むのってよくあると思う。

create table comments (
  id bigint,
  parent_id bigint,
  author bigint,
  comment text
# 外部キー制約とかは割愛
);

常にparent_idを元に親子関係を作っていくやつ。これ、アンチパターンらしい。え、普通にやっちゃいそうだけど?

確かにこの構造だと死ぬほどめんどくさい。どのぐらい深さがあるかわからないし、親からずっと辿っていかないとツリーは完成しない。アルゴリズム考えるのもめんどくさい。SQLが死ぬほど呼ばれること必至である。

確か、WordPressのカテゴリーはこの構造になっていたはず。

これの代わりとして代替ツリーなる方法があるらしい。

経路列挙、入れ子集合、閉包テーブルなるやり方があることを知る。

経路列挙、閉包テーブルはめちゃくちゃわかりやすく、アルゴリズムも簡単だった。SQLもめちゃくちゃ少なくていい。

入れ子集合は理論としてはわかるけど、プログラムに落とし込むのがよくわからなかった。

やっぱ勉強しとくもんだな〜。SQLアンチパターン、おすすめである。

22:30 就寝

寝る前に、プロテイン、グルタミンパウダー、亜鉛、マルチビタミン摂取。

今日は学びが深かった。やはり本を読むことが重要だ。

本日の目標は達成

以上!