やる気がストロングZERO

やる気のストロングスタイル

dlvで実行中Processにアタッチしてデバッグ

Goでcuiアプリ作ってる。

ビジネスロジックはメソッドで切り出しているのでIDEの機能でテストコードから実行してデバッグしてたが、画面に近い部分のデバッグするの辛いなと思ってた。

以下のようにすれば動作中プロセスにデバッガをアタッチしてデバッグ可能。

デバッグ対象アプリ起動
$ ./main

プロセス番号を調べる
$ ps aux 

デバッガをアタッチ。
$ dlv attach プロセス番号
(dlv) 

bでbrake pointを指定して、cでコンティニューして操作してればbrake pointで止まる

Golandでも普通にアタッチできる。

デバッガーで実行中の Go プロセスにアタッチする | GoLand

高トラフィックに耐える構成を考える

トラフィックに耐える構成についてざっくり書いてみる。
インフラエンジニアでもないので間違いあるかも。

アプリケーションサーバ

ステートレスに作っておいて、稼働台数を増やしてLBで振り分ける。
LBに対してはDNSラウンドロビンで負荷分散させる。

DBサーバー

やっぱりDBへの負荷をどう下げるかがキモ。
参照と更新で分けて考える。

参照:

キャッシュサーバーを用意してキャッシュし、DBへのアクセス自体をできる限り減らす。
レプリケーションセカンダリを複数用意し、参照リクエストを分散させる。(ここにもLB使える?)

更新:

更新はプライマリに対して行わなければならず、単純に数を増やして対応することができない。
出来る限りスケールアップによって性能を上げる。
特にメモリは多く確保し、DBのデータをすべてメモリに乗せられるようにしてIOの発生を出来る限り避ける。

更新が極端に多い特性のデータはKVSへ保持させることを検討する。
redisはクラスタ構成を組むことで更新に対してもスケールアウトによる負荷分散が可能。

最終手段としてテーブルの水平分割や垂直分割を行って、プライマリDB自体を分割し、アクセスを分散させる。

そのうち検証とかしたい。raspberry piとか複数買って小さい環境作って限界目指してみるとか。

行われている処理がイメージできるようなテーブル構造を設計したい

見れば行われている処理がイメージできるようなテーブル構造を設計するのが良いと思っている。

このテーブル構造で何が読み取れるか?

user

id state
1 active
2 active
3 disactive
... ...

userはステータスを持っているのはわかる。
データを見るとほとんどactiveでたまにdisactiveがあるように見える。
active, disactiveだけなのかどうかはわからない。 どんなふうに遷移するのかもわからない。

だから、こんなテーブル構造がいいと思っている

user

id user_state_id
1 2
2 2
3 3
... ...

user_state

id name
1 preparation
2 active
3 disactive

user_state_history

id user_id user_state_id until_at
1 1 1 2021-03-15 12:00:00
2 2 1 2021-03-15 13:00:00
3 3 1 2021-03-15 13:00:00
3 3 2 2021-03-15 14:00:00
... ... ... ...

先程のテーブルとは違って、userはpreparation, active, disactiveの状態があることがわかる。他にないこともわかる。
stateはpreparation => active => disactive と遷移しているのも分かる。過去どういうstateを辿ったのかもわかる。

コードを見なくてもなんとなくイメージできる。

性別カラムを1,2で用意するとき、1が男, 2が女だという情報をどこに持つか

性別カラムを1,2で用意するとき、1が男, 2が女だという情報をどこに持つか。

user情報テーブルに性別カラムを用意して男女を1or2で保持させる場合、1が男、2が女である情報をどこに持つのがよいか以前議論になったのを思い出した。

システムで「性別」の情報を扱う前に知っておくべきこと - Qiita
こういう話もあるけど、今回提示した「性別カラム」は例であって、この記事に記載されているようなことは一旦考えない

案A: コード上に持つ。

個人的観測範囲でよく見かける。
DBには1, 2という情報しかなく、アプリケーションコード側に対応表を持たせている(dictデータ構造で'男' => 1, '女' => 2など)
DBで持ってもレコードが追加されることも、値が変更されることもまずない。更新されることがないのであれば、変化するDBへ持っておくメリットはなく、定数としてコード上に埋め込んておくほうがよい、というような意見だった気がする。

案B: テーブルでデータを持つ。

性別マスタテーブル(1, 男 2,女の2レコードのみ)を持つ。
個人的にはこちら派。

自分が案Bが良いと思う理由。

案Aの場合、DBだけ見た時1が何なのか、2が何を意味するのかわからない。
案Bの場合、DBだけで意味が理解できる。
「DBの寿命はコードよりも長い」に従って、仮にアプリケーションコードが死んで、DBだけ生き残って引き継がれた場合、案Aだと一部の情報が失われてしまうあたりが「それでいいのか?」と気になっている。
そんな状況、実際どれくらい発生するねんって話ではあるけど。

案Aの場合、未定義の値(例えば99等)が入れられてしまうことが可能。
案Bの場合、外部キー制約で1or2しか入らない。これが大きいと思っている。

テスト駆動開発の一番大きいメリットは「テストコードができる事」ではなく「システムの複雑性が下がる事」

僕はテスト駆動開発(以下TDD)の信者だ。
TDDを学びだした最初は「TDDのメリット」とは「テストコード」が同時に出来上がり回帰テストが可能になる事だと思っていた。 しかしすぐに「TDDで開発を行うとシステムの複雑性が下がりやすい」事こそが最大のメリットであると気がついた。 その事について書く。

TDDで開発しない場合

構造に対して興味が薄い人が作業した場合、以下のような感じでコードが書かれている事が良くある。

# userのtypeを更新する(コード構造イメージを示すだけで、処理自体に特に意味はない)
X処理() {
    # DBからデータ取得する処理
    user = load()

    if user.status == 1 {
        user.type = 1
    } else {
        user.type = 2
    }

    # DB保存処理
    save(user)
}

データの取得や永続化と処理がごっちゃに実装されている。 この関数を使っている側からのコードの見た目は以下のようになる。

続きを読む

俺専用の最強メモアプリを作ってる(メモった内容を後から探すのムズい問題の解消)

メモって難しい。
メモる事自体は難しくない。
メモった内容をあとから参照するのが難しい。

どこに書いたか忘れる問題

最近メモった内容であれば問題ない。
どこにメモったか覚えているのですぐ見つかる。

でも「1年前に着手していた作業の関連資料を置おいてある共有ディレクトリのパス」をどこにメモったかなんて覚えてない。

続きを読む

【エンジニア職】手元で実行できないシステムを作ると定時で帰れなくなる説

エンジニア職で慢性的な残業が発生している現場がなぜそうなるのかを考えてみた結果、原因の一つとして「手元で実行できないシステムを作ると定時で帰れなくなる説」を思いついたのでこれを提唱したい。

  • 手元で実行できないシステムを作ると、仕様知識が失われる
  • 仕様知識が失われると「調査・認識合わせ」のコストが跳ね上がる
  • 「手元で実行できるシステム」だと上記のコストが掛からない
  • なぜ手元で実行できないのか?
    • 依存先がコントロール外である
    • 動かすために必要な条件がコードを理解しないとわからないようになっている
      • 動かすために必要な条件を知るのにコードを読まねばならない状況とは?
        • 処理がinput => 処理 => output というきれいな構造になってない。
        • 必要なデータを作成する手段がシステム内部に無い。
  • まとめ:手元で実行できる環境は残業してでも全力で守る

手元で実行できないシステムを作ると、仕様知識が失われる

仕様は大体においてそこそこ複雑である。 新しくjoinする人にはもちろん知識がないので仕様を伝えねばならないが、言葉や資料で伝えられるのは概要だけで細かい本当の動きは伝わらない。 また、一度理解しても定期的に思い出さなければ忘れていくので、特にエッジケースの仕様は失われやすい。

だから新人もそうでない人も定期的に「どういう仕様だっけな?」と調べないといけない。

ここで「手元で実行してみる」が出来れば動作仕様がはっきりと確認できるのだが、これが出来ないとコードを読んで把握するしかなくなる。

しかしコードを静的に読んで全ての挙動を完全に理解するのはかなり難易度が高く、不可能と言っていいのではないかと思っている。 人は簡単に勘違いしてフラグの意味を逆に理解してしまったりするので、いくら頑張って読んでも動かしてみるまで本当に理解通りなのかは確証が取れない。 (静的に読んで完全に理解できるなら、この世にポカバグは存在しないはず)

こうして「手元で実行できないシステム」の仕様知識は基本的に失われてしまう運命にある。

続きを読む