「失敗から学ぶRDBの正しい歩き方」を読んで
Twitterでおすすめされていたので
失敗から学ぶRDBの正しい歩き方 (Software Design plus)
- 作者: 曽根壮大
- 出版社/メーカー: 技術評論社
- 発売日: 2019/03/06
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
何がわかりやすいか
図もサンプルクエリも豊富でわかりやすいことに加えて、一つ一つのアンチパターンの小話形式?の話が、日本で実際にありそうなことなのがイメージの助けになりました。職業エンジニア二ヶ月目で実際にアンチパターンみたいなのを体験したことがまだないのが悲しいところですが。(気づいてないだけでもうしているかも)
噛み砕いた説明
噛み砕いて書いてある本だとも感じました。
例えば、INDEXがそもそも有効に利用されるのか?、実行するテーブルの規模を意識してクエリを組み立てているか?という視点から丁寧な解説が書いてありましたし、強すぎる制約を判断する基準なんかは、長くエンジニアとして働いてきたゆえの知見を端的に書いていただいてるなと感じました。
条件に列を使わない、カーナビリティの高低でのRDBMSの処理の違い、エグゼキューターの評価順序なんかは取り入れやすい知見だと思うので、なんとかアウトプットをだしたいです。
RDBに対しての無知
「テーブルに状態をもたせる」なんかも知らないとデメリットを理解せずやってしまいそうですし、トランザクションの分離等にいたっては初耳です。 まだまだRDB、RDBMSに対して無知であるなぁと強く思いました。 データベースから情報をとってきたり、データベースに情報をいれたり、というのはサーバーサイドであれば言語やフレームワークが変わろうとも(恐らく)ずっとやり続けることだと思うので、転ばぬ先の杖をもっとたくさん持ちたいです。
オブジェクト指向設計実践ガイド 四章まで読んで気になったこと
序盤の章は具体的に自分のコードにしてみました。
メソッドの責任の分割
メソッドの責任を分割してみました。
自分より変更されないものに依存しなさい
引数の依存を避けるためにキーワード引数を導入してみました。
これで別の場所でインスタンスを作る際にクラスがどの順番で処理しているかを考える必要がなくなります。
もちろん世の中これがデファクトではなくていくつかの順番に依存する引数と残りをオプションハッシュにしているメソッドが多いですね。
オブジェクトは相手を信頼して隣人にしか声をかけない
Player
がHardware
を使ってSoftware
をプレイしようとしてもPlayerはSoftwareに直接メッセージを送るのは避けるべきで、PlayerはHardwareを信用して、遊びたい中身はSoftwareだとしてもPlayerにはplayというパブリックインターフェイスをもたせて詳細な実装は隠すべき
こうするとplayするゲームがVRになってplay以外のことをHardwareとSoftwareを使ってするようになっても、player.experience等一般化して対応できるようになる。
player.hardware.software.run #ではなく player.play #とするべき
オブジェクト指向とは
オブジェクト指向ってなんだ(困惑)。
単一責任とか疎結合とかパブリックインターフェイスとか他のオブジェクトを信頼はしても依存はしないのが良いということはわかりました。人間関係かな。
StackEditで簡単にシーケンス図がかけるので最高
はじめてのペアプログラミングをしたので感想とか
はじめてのペアプログラミング
会社でペアプログラミングをやる機会がありました。ペアプログラミングという経験は初めてだったのですがとてもいい経験だったので所感と反省を書きます。
今回ペアの方はベテランで、自分はエンジニア歴一ヶ月のペーペーなので教育的要素があったペアプロでもあった前提で読んでいただければと思います。
やってみて感じたメリット
明らかにコードの質が高まる。
- ベテランの方一緒に作業したので当然ですが自分一人で書くよりコードの質がよくなり、考慮した要素が多いものになりました。単純に手戻りが少なくなりそうです。
他の人のコーディングを逐一質問しながら進められる。
- 新人側の視点でのメリットですね。オブザーバーとしてどういう考えでこのコードを書いているのかその場で聞けるので設計とかの仕組みが頭に入ってきやすかったです。
二人でやるので開発の手順をしっかり踏むことになる。
- やる前はあんまり考えていなかったのですが、これが一番大きいなと思ったメリットです。自分だけで開発を進めるわけではないので なんとなくでコードを書いたりすることなく、現状の仕組みを把握し、問題を理解して、解決策を具体的にタスクとして実行するというステップを決めて開発することになります。お互いの足並みが揃わないのにいい開発ができるわけがありませんからね。自分たちが今何をやっているのか、方向性がわかりやすく開発効率が明らかに良かったです。
ペアプロと合わせてやってみて良かったこと。
-
- 今回はモデルをいじる開発で、テストから先に書く開発を行いました。テストを先に書くので開発途中にテストが落として修正するというサイクルが発生し、二人で話し合って分析する対象が明確になります。二人で一つの画面をみて開発するペアプログラミングでは相性が良いと感じました。
自分のやろうとしてる事と考えをどんどん声にする。
反省点
二人で進めるものという認識が甘かった。
- ペアプログラミングをスタートした時に、僕がすぐさまコードを書こうとしたらペアの方に「最初に手順について確認しましょう」という助言がありました。二人で一つのコードを書くのだから現状の問題、仕組みに関する共通認識と、解決策と具体的な実行手順をお互い把握することがまず最初にあるべきなのは当たり前です。
自分は最初は自分がコードを書いて、それに間違いがあれば指摘してもらうのが新人とベテランのペアプログラミングだろうという認識があったことが招いた行動だと思います。もちろん教育の要素は多分にあるとは思いますが、二人で一つの問題に対して解決策を見つけ、実行する、というのが前提にあるのがペアプログラミングです。
次回機会があればまず二人でこの問題を解決するにはどうしたら良いか、の認識、共有を一番に考えてペアプログラミングを始めるとよりスムーズに行くんじゃないかと思いました。
- ペアプログラミングをスタートした時に、僕がすぐさまコードを書こうとしたらペアの方に「最初に手順について確認しましょう」という助言がありました。二人で一つのコードを書くのだから現状の問題、仕組みに関する共通認識と、解決策と具体的な実行手順をお互い把握することがまず最初にあるべきなのは当たり前です。
いつ始めるか明確に定義してなかった。
- これは細かい点なんですが始める時にこれからやる?ok?と声をかけて頂いて始めた(もちろん前日に明日ペアプロやってみるみたいな話はありました)のであいまいな感じでスタートしたのはあんまり良くなかったかもしれないです。
やっぱり二人でやるものですからきっちりこれから始めるという区切りがあるとより良いと感じました。
- これは細かい点なんですが始める時にこれからやる?ok?と声をかけて頂いて始めた(もちろん前日に明日ペアプロやってみるみたいな話はありました)のであいまいな感じでスタートしたのはあんまり良くなかったかもしれないです。
まとめ
ペアプログラミングって普段の開発と違って喋りながらやるので単純に疲れます。ですが思考が整理されていくのを感じますし、やっぱり二人で一つの物を作ったというのは達成感も違います。新人側なのでメリットばかり享受している気もしますが、次もやりたいと思える経験でした。ペアをくんでくださった方には感謝しかないです。
SQLアンチパターン 第六章を読んで
を読んでの要約、感想です。
目的
複数の親を持つテーブルが欲しい。例えばキャラクターに関するコメントもアイテムに関するコメントもおなじコメントテーブルに置きたいとうのが今回の目的です。
アンチパターン
ポリモーフィック関連を定義するというのがアンチパターン。 ポリモーフィック関連とは親のテーブルの名前をカラムとして追加してその後外部キー制約なしに外部キーに当たるものをカラムに格納する関連付けの方法です。
comment_id | target_type | target_type_id |
---|---|---|
1 | Characters | 1 |
2 | Items | 1 |
デメリット
- target_typeに他のテーブルの値のみが入ること、target_type_idに他のテーブルの主キーが入ることを保証できない
- Characters、Itemsと結合しようとしても全ての行が一つのテーブルと関係があるわけではないので内部結合はできない
使用してもいい場合
外部キー制約使えってあります。フレームワークがしっかりしてるならまぁ使っても良いんじゃない?って感じです。使用してもいい場合の文章割と身も蓋もないです。
解決策
参照を逆にします。今回の例で言えばCommentsテーブルをCharactersとItemsの親にして関係テーブルを仲介させることでtarget_typeカラムを使わずに関係を表すことができます。 共通の親テーブルを作成することも有効です。今回ならGuidesテーブルを作成してguide_idを主キーとしてそれぞれのテーブルにもたせればそれぞれのテーブルが比較可能なカラムをもつので結合が簡単になります。
感想
毎日書くペースだとまとめ過ぎな気もしてきた(後大変)なのでさっくりまとめる感じでいきたい。どうせならもっと短くしたいという気持ちが強まってきました。この章は解決策がしっかりしていてポリモーフィック関連を使わないのも十分可能だなと感じました。ただSQLの正義が絶対正義ではないみたいな話を職場できいたのでメリデメしっかり理解するのが大事ですね。多分この本全てに言えますけど。
React チュートリアルをやってみた感想とか
はじめに
ぎょーむでReactをつかうらしいのでチュートリアルやってみました
すごい良くできていて、途中のコードも全てサンプル載せていて、ローカルの準備までかいてあり、アロー関数宣言とかもコラムにまとめてあったり、なんでこの処理をするのかとか、処理がどんな順番で実行されているのかとか丁寧に書いてあり、JSがそもそもそんなにわからんおじさんでもなんとかなる感じに作ってありました。
簡単な機能からつくって、段々と一つのコンポーネントに機能を盛り込んでほかは表示するだけのコンポーネントにしていく構成になっています。
いくつかなるほどなぁと思ったことを書きます。
コンポーネントのstateはそのコンポーネントだけの物
チュートリアルでは○×ゲームを作るために、マス、ボード、ゲームそのものという感じでコンポーネントを作っていくんですが、
最終的に作るマスもボードもゲームコンポーネントからプロパティを受け取って表示してるだけのコンポーネントなります。
function Square(props) { return ( <button className="square" onClick={props.onClick}> #渡されたプロパティを参照してる {props.value} </button> ); }
class Board extends React.Component { renderSquare(i) { return ( <Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)} #渡されたプロパティを参照してる、Boardコンポーネントはマスの番号だけ渡している /> ); } render() { return ( <div> <div className="board-row"> {this.renderSquare(0)} .............
class Game extends React.Component { constructor(props) { super(props); this.state = { history: [ { squares: Array(9).fill(null) } ], stepNumber: 0, xIsNext: true }; } (中略) return ( <div className="game"> <div className="game-board"> <Board squares={current.squares} onClick={i => this.handleClick(i)} /> #ここでコンポーネントクラスの中での関数とかをプロパティとして渡している。 </div>
ここで重要なのはGameコンポーネントはstateを持っていてsetStateしてstateに情報を追加したりしていくんですが、BoardコンポーネントもSquareコンポーネントでもstateの変化は考えません。
GameコンポーネントのstateはGameコンポーネントの中でのみ扱ってプロパティとして子コンポーネントにわたす必要があります。 子コンポーネントが子コンポーネント同士や親コンポーネントと連携が取れなくなってしまうからです。
stateは不変性が大事
この○×ゲームではターンの履歴を前回のボードの状態を一度コピーしてからそのコピーに変わった状況を書き込んで、stateに加工したコピーを追加しています。state直接変えないです。途中の履歴とかを意識しない段階でもstateを一度コピーしてから加工したコピーをsetStateしています。
これは何故かと言うとReactの利点である、変更されたもののみ描画し直すという機能のために、変更されたものと変更前がわかる必要があるからです。直接変更してしまうと、前と後がないためstateの変化が検出できません。stateそのものは不変であるべき、というのがおすすめされています。pure components
つくっていきたいザウルスですね。
functionコンポーネント
そのコンポーネントがstateを扱わないときはReact.Component継承しないでfunctionでコンポーネントつくるのもよい、とチュートリアルにあります。
逆にfunction componentsみたらそれはstateは扱っていないんだな、と考えるとコードが読みやすくなるかも、と感じました。
Reactというよりは、、、
職場でもきいた話なんですけど、Reactが難しいというより、どういう形でコンポーネントの組織が作られていて、どこでstateをどのように管理しているか把握するのが難しいのかなと感じました。適当にやるとコンポーネント同士の連携がめちゃんこになって「React わからない 人生」とかで検索することになりそう。
SQLアンチパターン 第5章を読んで
を読んでの要約、感想です。
目的
同じ属性を持ちつつも、例えばSmartphoneというオブジェクトがあるとして方やandroid_version、方やios_versionを持っている場合に対応したいというのが今回の目的です。
アンチパターン
別テーブルをつくり属性を行に格納してしまうというものです
smartphone_id | os_version | os_version_value(VARCHAR) |
---|---|---|
1 | android_version | oreo |
2 | ios_version | 12 |
3 | blackberry_version | 7.1 |
いちいちSmartphonesテーブルに列を増やさなてくてもいいですし、急なOSの登場にも耐えられます。
デメリット
- 対象の行を指定してから取り出すして使う必要がある。(これは織り込み済みのデメリットの気もしますが)
- 行に属性がはいるのでデータ型なんかは整合性はとれず文字列をいれるしかありません。もしくはデータ型に対応するカラムをたくさん用意するかです。
- 行として属性をもっているので内部結合しようと持っていない属性を指定してしまうと結合できず、何も取り出せないので外部結合するしかありません。必然的に扱う行の数は多くなります。
使用してもいい場
SQL以外の非リレーショナルな技術をつかう時とあります。確かに。
解決策
- シングルテーブル継承
サブタイプの数が限られていれば
smartphone_id | name | os | android_version | ios_version |
---|---|---|---|---|
1 | iphone6 | ios | oreo | null |
2 | honor9 | android | null | 12 |
ActiveRecordを使うような単純な設計の時◯です。
- 具象テーブル継承
変化する属性ごとにテーブルをつくります。
smartphone_id | name | os | ios_version |
---|---|---|---|
1 | iphone6 | ios | 12 |
smartphone_id | name | os | android_version |
---|---|---|---|
2 | honor9 | android | oreo |
nullがなくなります
- クラステーブル継承
smartphone_id | ios_version |
---|---|
1 | 12 |
smartphone_id | android_version |
---|---|
2 | oreo |
共通要素を元テーブルで持ち、違う要素をそれぞれ別のテーブルに切り出すというものです。その名の通りクラス継承と同じ形です。
- 半構造化データ
smartphone_id | name | os | version_attributes |
---|---|---|---|
1 | iphone6 | ios | android_version: oreo |
2 | honor9 | android | ios_version: 12 |
LOB列を作りそこにJSON等の形式で格納してしまおうというものです。SQLでアクセスできなくなるので流石に無理がある気がします。
感想
メタデータを格納させると大変だよという章だと思いました。現実的にはシングルテーブル継承が一番使いやすいかなと思います。
SQLアンチパターン 第四章を読んで
を読んでの要約、感想です。
目的
データベースのアーキテクチャを単純にしたい データベースのアーキテクチャ、複数のテーブルが複雑にからみあう中で、その関係をもっと柔軟にしたいとういのが今回の目的です。
アンチパターン
外部キー制約をしない
デメリット
- 関係してるテーブルを確認してから削除や追加をして、という作業をしている間に新たな行が作られたりしてぼっちの情報ができるのを防ぐことができない
- 外部キー制約がない場合全ての参照を調べなければならない
使用してもいい場合
外部キー制約が用いれない場合は仕方ないと本書にはあります。
解決策
外部キー制約を使用する。
ミス防止は投資以上の効果を発揮する事例が紹介されていました。外部キーを使用するのはミスを防ぐのでとても有用であるとのことです。
例えばRailsでもvalidationを定義するのはエラーメッセージ等レールにのれるというメリットもありますが、それ以上にミスを防げるというのがメリットだというのと同じだと思います。
制約を作ることは柔軟性を下げるかもしれませんがそれ以上にバグを減らすメリットがあるということですね。
カスケード更新もできるから柔軟性もあるとあります。確かにカスケード更新はよく書かれていますね。
関係ないですがrailsのdependent: :destroy
だけだと単に探して消してくれているだけです。
Guide Load (0.3ms) SELECT "guides".* FROM "guides" WHERE "guides"."champion_id" = $1 [["champion_id", 5]] Guide Destroy (0.3ms) DELETE FROM "guides" WHERE "guides"."id" = $1 [["id", 3]] Champion Destroy (0.3ms) DELETE FROM "champions" WHERE "champions"."id" = $1 [["id", 5]] (0.1ms) RELEASE SAVEPOINT active_record_1
感想
外部キー制約を使いなさいという章でした。手軽にできてバグを大幅に減らしてくれるなんてなんて素敵な制約なんだ…