「SQLアンチパターン」を読んで【第Ⅰ部】
書籍

- 作者:Bill Karwin
- 出版社/メーカー: オライリージャパン
- 発売日: 2013/01/26
- メディア: 大型本
はじめに
読んだ書籍は1記事にまとめると文量が多くなるため、導入+各部ごとの記事としてまとめる。
本記事は「第Ⅰ部:データベース論理設計のアンチパターン」になる。その他の部についての記事は下記参照。
- 導入
- 第Ⅰ部:データベース論理設計のアンチパターン(本記事です。)
- 第Ⅱ部:データベース物理設計のアンチパターン
- 第Ⅲ部:クエリのアンチパターン
- 第Ⅳ部:アプリケーション開発のアンチパターン
印象に残った点
※ 下記のカッコ書きは該当する章番号。
ジェイウォーク(信号無視)[1]
- 目的:複数の値を持つ属性を格納する - アンチパターン:カンマ区切りフォーマットリストを格納する - 検索時にパターンマッチが必要になりインデックスが効かない - アカウント更新/削除が辛い - アカウントIDの妥当性検証ができない - 区切り文字の選択が難しい - リストの長さに制限があり設計根拠に欠ける - アンチパターンを用いてもよい場合 - 非正規化によるパフォーマンス向上 - カンマ区切りのデータが必要 - 解決策:交差テーブルを作成する
- 今携わっている製品でカンマ区切りでデータを入れている箇所がある。アンチパターンのツライ点を見ても思い当たりそうなのは内容の妥当性検証くらい。メリットはテーブルを減らすことだろう。
- 設計した方はメリットデメリットを考えてこの方法を選んだのかもしれない。
ナイーブツリー(素朴な木)[2]
- 目的:階層構造を格納&クエリを実行する - アンチパターン:常に親のみに依存する(隣接リスト) - 階層を深くする度にJOINが必要 - ノード更新が非常に手間 - アンチパターンを用いてもよい場合 - DBMSで再帰クエリがある - 解決策:経路列挙/入れ子集合/閉包テーブル - メリットデメリットがあるので考慮して採用する
- 実務でツリー構造を取り扱ってはいないため、フムフム。そういう方法もあるのか。というコメントくらい。
- ツリー構造部分だけNoSQLでは駄目なのかな?と思い調べると同じ質問をされている方がおり、「RDBでもツリー構造は実装できるし、ツリー構造だけのためにNoSQLを採用するのはコストが高い。」と書かれていた。確かにそうだ。
IDリクワイアド(とりあえずID)[3]
- 目的:主キーの規約を確立する - アンチパターン:すべてのテーブルに「id」列を用いる - 冗長なキーが作成されてしまう(規約を重視して自然な主キーを無視する) - 重複行を許可してしまう(交差テーブルにidを用いる) - キーの意味がわかりにくくなる - すべて「id」にするとUSINGを使用できない - 複合キーは使いにくい - アンチパターンを用いてもよい場合 - ORMフレームワークの規約に従う - 疑似キーや主キーがあまりにも長くなる - 解決策:状況に応じて適切に調整する - idではなく分かりやすい名前にしたり、自然キーや複合キーを採用する
- 実務のテーブル設計ではidの名前には気をつけていると思う。ただ、自然キーを用いれるところもあると思うがidにした経緯が分からないところもある。
- 実務のシステムでは採番テーブルを使いシーケンス番号を振っているが明らかに無駄。DBMSにて提供されている機能を使えば良いのにと思う。
キーレスエントリー(外部キー嫌い)[4]
- 目的:データベースのアーキテクチャを単純化する - アンチパターン:外部キー制約を使用しない - 完璧なコードが前提となる - 参照性の不整合ミスを調べなければならない - アンチパターンを用いてもよい場合 - 外部キー制約をサポートしていないDBMSを利用している - 極端に柔軟なデータベース設計を扱わないといけない - 参照整合性制約を使えないとその他のアンチパターンに陥る可能性が高い - 解決策:外部キー制約を宣言する - カスケード更新により複数テーブルの更新が可能になる - 事前のselectやテーブルロックが不要になる - 孤立したデータが生じない
- 保守している製品は外部キー制約が使えるにも関わらず使っていない。設計真意は不明だが、孤立したレコードができたり、ガチガチにロックしたり、事前selectしたりしている。
- DB設計によってアプリ側の苦労が減るのではと感じた。
EAV(エンティティ・アトリビュート・バリュー)[5]
- 目的:可変属性をサポートする - アンチパターン:汎用的な属性テーブルを使用する - 属性の取得が冗長になる - DBが持つ整合性が利用できない (必須の制約がもてない、データ型を使えない、参照整合性を強制できない) - 行の再構築が必要 - アンチパターンを用いてもよい場合 - RDBの長所を失うため正当化出来る理由は簡単にない - 非リレーショナルな管理が必要であればNoSQLを使うべき - 解決策:サブタイプのモデリングを行う - シングルテーブル継承:1つのテーブルで全て管理 - 具象テーブル継承:共有属性込でサブタイプごとに管理 - クラステーブル継承:サブタイプ固有属性+基底テーブルの外部キーで管理 - 半構造化データ:1つのフィールドにサブタイプ固有の値を半構造化データ入れて管理
- 保守している製品はEAVは使っていないが、フィールド名にcodeとdataを用意し、セットされるcodeに応じdataの意味が変わるようにデータを保存している。参照整合性の問題やフィールドを見ただけでは何のデータか分からないという問題がある。
- うーん、RDBの良さを使っていないのは間違いない。
ポリモーフィック関連[6]
- 目的:複数の親テーブルを参照する - アンチパターン:二重目的の外部キーを使用する - ポリモーフィック関連を定義する(メタデータの混入) - アンチパターンを用いてもよい場合 - ORMフレームワークを用いている - 解決策:関連(リレーションシップ)を単純化する - 参照を逆にする - 交差テーブルを作成する - 共通の親テーブルを作成する
マルチカラムアトリビュート(複数列属性)[7]
- 目的:複数の値を持つ属性を格納する - アンチパターン:複数の列を定義する - 値の検索/追加/削除が辛い - 一意性の保証が出来ない - フィールド追加の影響が大きい - アンチパターンを用いてもよい場合 - 列の順番に意味を持たせる - 解決策:従属テーブルを作成する
- 同じ意味を持つ値を格納するために複数の列を定義すべきではないことは分かった。
- 汎用的な列を用意し、行ごとに列の使い方が異なるのはどうなんだろうか?この話とはちょっと意味合いが違うから、悪い設計ではないのか?デメリットはフィールド名が分かり辛いことぐらい?
メタデータドリブル(メタデータ大増殖)[8]
- 目的:スケーラビリティを高める - アンチパターン:テーブルや列をコピーする - テーブル/列が増殖する(年毎にテーブルが出来る) - データの整合性管理が必要になる - テーブルが分割されると外部キーを使えない - アンチパターンを用いてもよい場合 - 現在と過去のデータを合わせてクエリ実行をする必要がない場合 - 解決策:パーティショニングと正規化を行う - 水平パーティショニングの使用 - 垂直パーティショニングの使用 - 従属テーブルの導入
- 主要なDBMSはパーティショニングできるのか…。使ってみたい。
- 保守している製品は15年くらいのデータが蓄積されている場合もあるので、必要になってくると思う。
「レガシーコードからの脱却 - ソフトウェアの寿命を延ばし価値を高める9つのプラクティス」を読んで
書籍

レガシーコードからの脱却 ―ソフトウェアの寿命を延ばし価値を高める9つのプラクティス
- 作者: David Scott Bernstein,吉羽龍太郎,永瀬美穂,原田騎郎,有野雅士
- 出版社/メーカー: オライリージャパン
- 発売日: 2019/09/19
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
TL;DR
- 新規開発や保守など関係なくソフトウェア開発で価値を高めるプラクティスが網羅されており、索引として使うのに最適。
- 開発フローを一通り体験したことがある人であれば、この本を1冊読んだだけでも自組織で足りていなことに気づくことができる本。
- (本の分量的に仕方がないが、)気になったプラクティスの深堀りは各自で行う必要がある。
この本を選んだ理由
- 業務的にレガシーコードに触れる機会が多く今後仕事をする上での気づきを得られると思った為。
- 名著になる!というコメントを見かけ是非読んでみたいと思った為。
印象に残った点
※ 下記の大括弧は該当する章番号。
過度なコメントは良いコードを書いていない言い訳になる[1.5]
- 過度なコメントはノイズになる - WhatではなくWhyをコメントに残すべき - 意図はコードで表現する - 追いかけやすい名前や一貫したメタファーを使う
- 尊敬する先輩が「コードに魂が入っとらん。見れば分かる。」と言っていたのを思い出した。先輩の言葉は具体的ではない為詳しく聞いたところ、言いたいことは上記の内容だった。別の名著(リーダブルコード)を一緒に読んだとき、「オレこの本書いたっけ?」というだけはある。
- ソフトウェアを保守する上でコードだけではなく、コメントも保守することになる。究極はコメントなくてもコードだけで意図が伝わることだろう。
ソフトウェア開発は未知の領域で行われる[1.7]
- 扱うプロジェクトが難しければ難しいほど、その時々の進捗を正確に定量化するのは難しい。 - マネージャーが開発者に作業終了の見込みを聞くと、開発者は分からないと答えることが殆ど。 - 責任逃れでも権力闘争をしているわけではなく、単に分からないだけ。 - 開発者には3つの状態(終わった/始めていない/殆ど終わった)がある。
- これはあるあるネタだなぁ。進捗がだいたい80%から進まない問題と同じ。対策としてはタスク粒度を細かくするくらいしか思いつかないなぁ。
ソフトウェア開発を成功させることは難しい[2]
- 成功の定義を「初期仕様の納期/予算/機能がすべて満たされていること」にすると、見積もり能力の計測にしかならない。 - リリース後に顧客の要望を叶えているか、バクがでていないか、改修が簡単にいくかなどの計測をしていない。 - 失敗するプロジェクトも多く、この業界が課題を解決する道のりは遠い。 - アメリカ合衆国だけでも毎年100億ドル単位の損失を出している。
- 現部署は見積もり能力の計測に力を入れすぎている気がする。その計測も重要であるが、顧客が求める要望を叶えているかどうかを正しく評価しなければ意味がない。
- ソフトウェア開発を成功させることが難しいということを理解していない人が多い。まずはその現状を経営層が理解しないと話が進まないと感じる。
アジャイルはキャズムを超えたとは言い難い[3.5]
- キャズムを超えるとは「アーリーアダプター」から「アーリーマジョリティー」の間を超え行き渡ること - アーリーアダプター:イノベーターと言われる新しい技術に飛びつく人の成功に感化され、その次に飛びつく人 - アーリーマジョリティー:多くの不具合が解消され使いやすくなった頃に使い出す人
プラクティスに従うのではなく原則に従うこと[4]
- 手術に使う器具を「消毒する」というプラクティスに従うのではなく、手術に使う器具を消毒する「理由」という原則に従うことには差がある。
- どういった理由で実施しているのか?という原則を理解していないと何の意味もないことは日々感じている。
- 良い例えなので、なぜ原則に従うのか説明が必要な時にパクりたい!
最高な開発者が1番キレイ好きな開発者[4.1]
- 速いプログラマー≠雑なプログラマー - コードの品質を高く保っている「にも関わらず」速いのでなく、コードの品質を高く保っていた「からこそ」速い - インスタンス変数をアルファベット順や意味のある別順にする - 使われなくなったコードを即座に削除する
- 品質を高く保っているからこそ速い。うーん、素晴らしい。これは方針を選択する時に考えていきたい。
ソフトウェア開発も守破離[4.1]
- 守:型である形式知(プラクティス)の取得 - ソフトウェア開発のルールや禁忌事項を学ぶ - 破:理論の理解&実践 - プラクティスの背後にある原則としての理論を学ぶ - 離:最高の熟練 - プラクティスと理論の境界が曖昧な状態 - 継続的な学習によってのみこの領域に到達できる - 本当に熟練するには10000時間必要
- 10000時間必要なのか。1日8時間で1250日。月に20日働いて62.5ヶ月。一人前なるのに5年か…実際はそこで終わりではないのがソフトウェア開発。
- 日々少しでも学び続けることが大事だなぁ。「型を知ってるからこそ型破り」という言葉があるので、常に学ぶ姿勢は持ち続けたい。
プラクティス1:やり方より先に目的/理由/誰のためかを伝える[5]
- ソフトウェア開発をする上でプロダクトオーナーや顧客から知りたいことは下記になる - 「何」が欲しいのか? - 「なぜ」欲しいのか? - 「誰」のためのものなのか? - 「どうやって」やるのかは不要。それを考えるのがソフトウェア開発者。 - 実装の「標準化」は不要。振る舞いの定義や何のテストを書くべきかは「標準化」したい。 - 解決方法/実装方法は千差万別。そのやり方を選択したトレードオフを理解していれば問題ない。 - 振る舞いの定義やどんなテストを書くかが決まれば多くのことが共通のものとなる。 - プロダクトオーナーが大事なことの1つは重要ではないことを葬り去ること。 - ストーリーで目的/理由/誰のためかを語ると良い - 所謂ユーザストーリー。 - 受け入れテストに明確な基準を設定する - ハッピーパス(正常系)だけでなく、代替処理やアンハッピーパスエラー条件もテストに含める。 - 受け入れ基準を自動化する - テストの自動化をすることで抽象が具体化される - 機能の目的、理由、誰のためかを定義することで開発にあてる時間の?を取り戻せる - 実装を詳細に説明した要求をドキュメント化することをやめれば可能
- 「どうやって」作るのかまで決められたら不満になるだろうなぁ。トレードオフを踏まえた開発者としての考えを判断するところはPOと話がしたい。
- 受け入れ基準の自動化は保守コストの面だけではなく、抽象的な受け入れ基準を具体化するというメリットもあるのか!より具体化し一般化できてないと自動化できないもんなぁー。
- POの7つの戦略の中に「質問にすばやく答える」というものがあり、現在のプロジェクトでもボトルネックになってると感じている。複数の仕事を抱えるPOなのでこのままで良いのか不安を感じる。
- POと開発チームとのあいだで協調できるようになればより楽しく開発者として働けるのだろう。今組織が揺れているが、良いように再構築され、協調して働ける環境になればいいなぁ。
プラクティス2:小さなバッチで作る[6]
- 1年の開発サイクルで開発者が大きなウソをつくのではなく、2週間のイテレーションの中で小さなウソをつく。 - ソフトウェア開発と製造は違う。人の数を倍にしたからといって生産性は倍にならない。 - 製造とは異なり人同士のやりとりが多いことに起因する。 - リリースサイクルを短くすればプロセス効率が上がる - プロセス効率:1つのタスクに費やされる割合 - メトリクスは顧客にとって価値のあるもので計測すべき - コード行数は顧客に何の価値ももたらさない - タスクを99%完成まで持っていくのでは不十分 - このままではリスクが未知のまま。開発したらシステムに完全に統合して初めてリスクが減る。 - 1日の稼働時間を100%としたら理想時間(本当の価値を生み出す時間)は50%前後が理想的 - ソフトウェア開発を計測する戦略 - 価値実現までの時間を計測する。全体最適化に寄与しないような部分最適化は無意味。 - 機能毎の顧客価値を計測する。バックログを作ることで価値の高い項目により多くの時間を割けるようにする。
- 小さなウソをつけばリスクを小さくでき、後になってビックリすることはないということか。
- プロセス効率を上げると待ち時間が減る、タスク切り替えが減る、フィードバックが増えるというメリットがある。今は2ヶ月×3の6ヶ月で一度のリリースとしているが、これを更に半分にできないか上長と話をしてみる。
- 今のプロジェクトでは生産性をコード行数で測定している。顧客にとっては意味がないことは分かっているが組織目標になっているから頑張っている。オカシイよね…。組織の仕組みから変えないと変わらない問題でこれを解決するのは骨が折れるだろう。
- リスクの観点からも完全な統合を急ぐ必要があるのか。今のサイクル半分にしたいなぁ。
- 理想時間か。近いことを自分のチームは計測している。このアプローチは間違っていなかった。ただ、価値実現までの時間や機能毎の価値を測れてはいない。まずは自分達でできそうな価値実現までの時間を測っていきたい。
プラクティス3:継続的に統合する[7]
- 痛みに対処する方法は回避するか順応するかの2つ - ブランチを避ける - コードの統合によってリスクは0になる。リリースする際にブランチを統合するよりも、フィーチャーフラグを使用したほうが良い。
- 回避、回避で後手後手に回ってることは確かにあるなぁ。少しづつ順応できるように小出しに対応していきたいものだ。
- リスク低減のためにフィーチャフラグを使うのか。なるほど。引き出しが増えた。
- 以前読んだ継続的デリバリーに同じことが書いてある。少し昔の本ではあるが継続的デリバリーの本質は変わっていないということを認識できた。
プラクティス4:協力しあう[8]
- ストロングスタイルペアリング by ルウェリン・ファルコ - 「あなたのアイデアをコンピューターに伝えるまでのあいだに、必ず他人の手を経由しなければならない。」 - 説明することで脳の活動領域が変わり、想像以上に詳細を明確に理解できる - バディプログラミング - ペアリングに恐怖や抵抗がある時に有効 - ほとんどの仕事は一人でやるが、例えば1日の最後の1時間だけバディとコードレビューするやり方。 - スパイク - 未知の課題解決のために複数の開発者が1つのタスクに取り組むやり方 - 使う時間を限定して行う - 短期的な問題解決のための委員会を作るイメージ
- ストロングスタイル良い。頭の使い方が変わるというのはその通りだと思う。名前もステキ。黒パンが似合いそう。
- バディプログラミングか。これなら導入しやすいだろうなぁ。ちょっとやってみよう。
- 2人チームで動いているが解決し辛い問題は時間を決めて二人で話しながら解決するスタイルを取っていた。コレ、スパイクっていうんだ。
プラクティス5:「CLEAN」コードを作る[9]
- 良いコードは「CLEAN」なコード。CLEANは下記5つのワードの頭文字を取っている。 - Cohesive(凝集性) - クラスやメソッドが単一の責任を持つべき - Loosely Coupled(疎結合) - 利用しているコードに対し間接的にしか依存しない - Encapsulated(カプセル化) - インターフェイス(やろうとしていること)を実装(どうやってやるか)と切り離す - Assertive(断定的) - オブジェクトは独立していて、自身の責任を持ち、自分で管理する - Nonredundant(非冗長) - 意図の繰り返しを避けるべき - 保守しやすいコードを書くには「コードの読み書き」を繰り返し練習すると良い
- 「Clean Code」本を読むと更に深く知れるのか。読みたい本がドンドン増えていく~。
- 本の中で「性能や別の制約によってコード品質をトレードオフにしてしまうケースが多い。多くの場会、正しい設計を選択すればコード品質が上がる。」とあった。確かにそういうケースに当たったことがある。元々の設計の大事さを再認識。
- コードの読み書きをしないとCLEANコードのプラクティスが習慣化しないのか。圧倒的に足りていないので読み書きする時間を取りたい。
プラクティス6:まずテストを書く[10]
- テストは色々な種類がある - 受け入れテスト=顧客テスト - ユニットテスト=開発者によるテスト - それ以外のテスト=QAテスト - 自動化すれば人間の介入を排除でき、外部からの依存性が下がる - 人間の介入が必要とすることもある(例:GPS) - 「ユニットテスト」の「ユニット」が表現するのは振る舞い。 - ここで言う「ユニット」はメソッド、クラス、モジュール、関数などではないため、新しいメソッドやクラスを追加してもテストを追加する必要はない。
- 振る舞いを表すためのテストを作ることが大事ということか。確かにクラスやメソッドを増やすたびにテストコードメンテしてたら辛いのは分かる。
プラクティス7:テストでふるまいを明示する[11]
- 小さな単位でレッド/グリーン/リファクタを何度も繰り返す。 - レッドから始めることでテストがちゃんと失敗することを担保できる。 - テストは一意であるべき。 - 1つのテストで失敗する理由はシステム内で1つだけ。 - これを意識するだけで1つのことを扱う焦点を絞ったコードになる。 - バグをテストの不足とみなす - バグの修正をする前に失敗するテストを書き、修正によりテストをパスすることを確認する。 - 欠陥をもとにプロセスを修正する - そもそもなぜバグが発生したのか?というプロセスを確認する。
- テストで失敗する理由が一意になることを意識するだけでもコードが良くなるなぁ。
- 二度と同じバグを出さない為にバグを修正する前にテストを書くのか。テストファーストだとこういうアプローチも出来るのか。
- バグが発生したのでテストケースを足して完了ではなく、バグが起きたプロセスのチェックまで行う事に言及していて好感が持てる。失敗からの学びは大事だもんなぁ。
プラクティス8:設計は最後に行う[12]
- コーディングとクリーニングは別タスクとして実行すると良い。 - コーディングは解決方法を探す作業。クリーニングは動くコードを保守可能にする作業。別々に考え集中すべき。 - 大規模なリファクタリングは通常数カ月ごとに返済作業を行う。 - コードは書かれる回数の10倍読まれる。 - 必要なら設計を変えることをためらわないこと。 - 品質は保証できない。品質は作り出すもの。 - 品質を検証するのではなく、作り込むことに集中する。
- テスト駆動開発では片付けられないような大規模な負債のリファクタリングは数カ月ごとに行うのが一般的なのか!!今のプロジェクトは負債を返えすことが一切できてない。
- 10倍も読まれるのか。読むことを意識したコードでないといけない理由がよく分かった。
- 設計に思い入れを持つ気持ちは良く分かる。創発設計をする上で一番重要なスキルと書いてあり、とても難しい部分だとも感じる。ココが一流との分かれ目な気がする。
- 「品質は保証できない。品質は作り出すもの。」この考えはなかった。作り込みによって品質が出来上がるのか。
プラクティス9:レガシーコードをリファクタリングする[13]
- リファクタリングの対象は顧客が使っていて変更の可能性がある部分 - リファクタリングはコードを書くときにしてはいけないこと/代わりにすべきことを学ぶ上での最速の方法の1つ
- 当たり前のことだが、リファクタリングにもコストがかかる。事業のメリットがなければ無理にリファクタリングをする必要もない。開発者だけの目線でモノを語らないようにしたい。
- リファクタリングは辛い作業だと思っていたが、学習効果が大きいことを知った。これを知るだけでも取り組む意欲が異なる。
テストコードを書くことがスピードを落とす原因とはならない[14.1]
- ソフトウェア開発を制限する要因はタイピングではない。 - 仕様書読み込み、ドキュメント作成、会議出席、デバッグなどコードを書く以外にも沢山時間を使う。
- テストコードを書くとスピードが落ちると言う主張を会社でも聞いたがよく考えれば無理があるなぁ。切り返しとして覚えておきたい。
その他所感
- 元職場の先輩がこの本を読んで「 前はイケてるチームのやってたことが、みんなが知っておくべきことになってるんだなーと、組織のレガシー化について考えた」とコメントされていた。「組織のレガシー化」これはレガシーコードよりたちが悪く、今の会社にも起きているように感じる。まずは自分の知識を高め、対応が打てるようになりたい。
- 新規開発や保守など関係なくソフトウェア開発で価値を高めるプラクティスが網羅されており、この本を1冊読んだだけでも今の組織で足りていなことに気づくことができる。索引として利用するには素晴らしく良い本。買ってよかった。ただ、もっと深く知りたいとなった場合、それぞれのプラクティスを深堀りする必要がある。
- 初めてウォーターフォールによるソフトウェア開発を言及した時点で「このやり方は機能しないんだろう」と次のページに書いてあったとのこと。これに対し、「どうやら、これまでに誰もそれを読んでないようだ。」とジョークを飛ばしている。文化の違いを感じた。
今後
Webサービス開発素人がVue.js+Firebaseで在席管理サービスを作ってみた。
はじめに
現在30歳前半。エンジニアとして働いています。 ただ、仕事内容はチームメンバーを管理したり、関係者と仕様を詰めたりとコードを書く機会はありません。 たまにコードを書く場面があっても昔々に作られたコード(主にC++ Builder 6、Visual Basic 2010)の保守をするくらいです。
仕事だけでは技術の進歩についていけていない…と2年ほど前から不安に感じていました。 それから業務以外で勉強を初め、興味のあるWeb技術を色々つまみ食いしてきました。 そのつまみ食いの成果を用いて何かサービスを作れないか?と思い、Webサービスを作ることにしました。
作ったサービス
内容
在席管理サービスです。下記の機能があります。
1. ログイン認証
本サービスを利用するにはログイン認証が必要です。
Googleアカウントがあればログインすることができます。
2. グループ単位のメンバー管理
グループ単位でメンバーを管理できます。
画面上部のプルダウンメニューからグループを選択できます。
選択しているグループはログインユーザ毎に保持されます。
3. メンバー登録&修正&削除
画面右下の新規登録ボタンからメンバーの情報(名前/役職/電話番号)を登録できます。
既に作られたメンバーの情報はUI上から修正や削除もできます。
入力内容のValidationも行っています。
4. メンバーの並び順変更
Drag&Dropにてメンバーの並び順を変更できます。
グループ内のメンバー並び順はログインユーザ毎に保持されます。
5. 行き先変更
メンバーの行き先や補足情報を変更できます。
メンバーを複数選択し、まとめて行き先を変更することもできます。
背景
社内にて利用している「在席管理サービス」が存在しています。 ただ、開発した方の話をしたところ、下記の状況があると聞きました。 その課題を解決しつつ学んだことを活かすには適度なボリュームだなぁと思いこの題材選びました。
1. メンテするにも開発者本人以外は難しい
コードを見してもらったところ、そもそも管理する課毎にDBが異なっていました。 そのため、新たな課を追加する時はDBやソースコードをハードコピーする運用になっていました。
2. UI/UXが古い
10年ほど前に作ったサービスのためSPAになっていません。そのため画面のチラツキが気になりました。 また、10年ほど前からUI自体の変更もないため古風な見た目をしています。
3. サーバ管理が必要
自前で用意したHW+WindowsOSの上で動いています。 そのため、HWトラブルやソフトウェア以外のVersionUpも自分で対応が必要です。 スケールアウトも一苦労です。
採用した技術
フロントエンド
フロントエンドはVueしか触ったことないのでVue+αで構成しています。
- Vue.js
- スモールスタート出来るという触れ込みで採用しています。
- Vuex
- 最初はprops/emitで書いていましたが、値のやり取りが辛くなり途中で採用しています。
- buefy
- BulmaがベースのUIフレームワーク。今風のUIを作る才能はないため力を借りております。
- vee-validate
- メンバー情報のValidationをするために利用しています。
- vuedraggable
- メンバー情報をCard表示しており、その並び替えを行うために利用しています。
- vue-freezeframe
- ホーム画面のGif再生用に利用しています。
バックエンド
バックエンドの知識はほぼありません。全てFirebaseにお任せすることでサーバ管理のコストを減らすことが狙いです。今回は無料枠で利用しています。
- Authentication@Firebase
- Googleアカウントでのログイン認証をするために利用しています。
- Realtime Database@Firebase
- 本サービスに関するデータを永続的に保存するために利用しています。
- Hosting@Firebase
- SPAのファイルをHostingするために利用しています。
- Functions@Firebase
- データの追加/更新/削除は全てFunctions経由で行っています。
開発環境
ローカルで開発⇒リポジトリにPush⇒自動ビルド&デプロイの流れが最低できることを念頭に選定しています。
- Visual Studio Code
- Vue周りで便利なExtensionも色々あり、動作も軽いので採用しています。
- Github
- CircleCIを利用した自動ビルドをする際に参考にした記事ではGithubを使っていたため採用しています。
- CircleCI
- Firebaseへの自動デプロイするために利用しています。
作るまで
平日は朝活として自主学習をしています。1日平均45minくらいです。 今回の成果はその朝活だけで成り立っています。
事前学習
トータルで朝活149日(≒112時間)ほど利用しています。 今回の技術に関係ある朝活内容は下記になります。
No | 内容 | 出典 | 実施日数(日) |
---|---|---|---|
1 | フルスタック・Webエンジニア講座 | Udemy | 49日 |
2 | 基礎から学ぶ Vue.js | 本 | 42日 |
3 | Blackjack-Vue | 個人ブログ | 4日 |
4 | Laravel+Vue.js+JWTAuth | 個人ブログ | 21日 |
5 | WebAPIアプリケーション「超」入門 FirebaseとAPIによるWeb会議システム制作 | 本 | 9日 |
6 | 改訂新版 Vue.jsとFirebaseで作るミニWebサービス | 本 | 15日 |
7 | CircleCiとFireBaseを連携 | 個人ブログ | 2日 |
8 | Cloud Functions for Firebase | 公式 | 7日 |
本作
トータルで朝活65日(≒49時間)ほど利用しています。 途中第三者の方に見ていただき、いただいたフィードバックを受けて修正もしています。
辛かったこと&ハマったこと
- 途中でprops/emit⇒vuexに変更
- 最初はprops/emitで書いていました。このサービス規模でもprops/emitだけでは各コンポーネントのやりとりが辛かったです。最初の判断を誤った気がしています。
- vuedraggableの使い方
- メンバーの並び替えはvuedraggableを使えば簡単に出来ましたが、その並び順を永続化する方法は非常に悩みました。
- oldIndexやnewIndexを使おうかと思いましたが、自力で並び替えるのは辛いなぁ…と対応をあぐねていたところ、toArray関数使うと並び順のリスト取れることが分かり、その後はテンポ良く進みました。
- このIssueとても役立ちました。
- デザインセンス不足
- デザインセンスなさすぎてUI考えるのが辛かったです。
- bulmaのnavbarにburgerメニューを表示
- コードのコピペでは駄目で、追加作業が必要でした。 こちらの記事が参考になりました。
- Vuexの導入
- VeeValidateの導入
- 最新Versionを入れるとエラーが…解決策が良くわからず、旧Versionにして対応しました。
- asyncを足したら「regeneratorRuntime is not defined」エラー発生。こちらを参考にpolyfillを導入して解決できました。
今後やりたいこと
- 管理画面作成
- グループやステータスはDBのマスターから値を取る仕組みなので、Realtime Databaseを直接編集すれば追加出来る作りになっています。管理画面を用意するだけで使い勝手が上がると思っています。
- 自動テスト
- 自動テストが一切ありません。Webサービス開発における自動テストに関する知識が全くないので、まずは自動テストに関する知識をつけたいと思っています。
- Cloud Firestore
- 事前勉強をRealtime Databaseで行っていたので、Cloud Firestoreは使いませんでした。ただ、今後世の中はCloud Firestoreを使う流れになると思うので、次開発する機会があればCloud Firestoreを使っていきたいと思っています。
その他所感
- 事前学習だけでは駄目で、自分の頭で考え、穴にハマって這い上がることで力が付くことを身を以て体験できました。今後も何か自分で作ることを続けていきたいです。
「継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化」を読んで(第2部)
書籍

継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化
- 作者: Jez Humble,David Farley,和智右桂,高木正弘
- 出版社/メーカー: KADOKAWA
- 発売日: 2017/07/31
- メディア: 単行本
- この商品を含むブログを見る
はじめに
読ませていただいた書籍は大変ボリュームがあるため、概要+各部ごとの記事としてまとめます。 本記事は「第2部:デプロイメントパイプライン」についてです。
その他の部についての記事は下記になります。
印象に残った点
※ 下記のカッコ書きは該当する章番号。
デプロイメントパイプラインの注意点/戦略/メトリクスについて記載されている
- デプロイメントパイプラインでバイナリを生成するのはコミットプロセス1回にする(5.3.1)
- 再ビルドすると何らかの変更が混ざる可能性があり順々に行うテストの意味がなくなる。
- またビルドには時間がかかるので何度も実施する必要がなければ不用意なビルドは避けるべき。
- 自動ビルド/自動テストが出来ていない現状ではまだまだ先が長い…。
- 自己学習の一環で自動ビルド/自動テストの実施をしていきたい。
- デプロイメントパイプラインを作成するためのインクリメンタルな戦略(5段階)がある(5.8)
- 最小構成でかつ段階的に実施すると良いとのこと。
- こう書かれてしまうと今からでもできてしまうなぁ。
- 最小構成でかつ段階的に実施すると良いとのこと。
- 変更してからデプロイするまでどれくらいかかるか?(=サイクルタイム)が1番プロセスについて教えてくれるメトリクス(5.9)
- 欠陥数でのメトリクスは二次的で、リリースまでに時間がかかるのであれば欠陥数はあまり意味がない。
- またコード行数やバグ件数はホーソン効果により実施者の振る舞いを変えてしまうので、計測するメトリクスはとても重要。
- 現状の組織は欠陥数やコード行数をメトリクスにしている。良くない例の典型だ…。
ライブラリをプロジェクト毎ではなく組織としてリポジトリを作り管理すべき
デプロイメントテストの前に環境/基盤用のスモークテストを用意する
- 環境/基盤が妥当化どうかのテストを事前に実施するという考え。
- 大事なのはアプリケーションが乗る基盤の保証ができているかいなか。
- 環境を用意してもらってもネットワーク不良などにより利用できないことがあるので、環境の妥当性を確認できるテストは欲しいと感じた。
プロセスの自動化はいつやるか?の目安がある
- 自動化は同じことを2回やることになったとき。3回目からは自動化したほうが良い。(6.6.2)
- 手動が許されるのは1度だけか…。回数はさておき、厳し方針を打ち出して対応すべきだとは思う。
- 1部に記載があったが、チームの規律として徹底できるかどうかは別問題だと思い、そこが難しいと感じた。
テストが失敗したタイミングでパイプライン処理を終了させることはない
- ユニットテスト以外にもインテグレーションテストや受け入れテストを行うケースがあり、途中で止まっては勿体無い。(6.6.5)
- 包括的にテストした後、ビルドを失敗させると良い。
- なるほど。確かに他のテストが可能であれば途中で落とす必要はない。
継続的インテグレーションに慣れていないチームに対するTipsがある
- チームが継続的インテグレーションに慣れていない場合にビルドマスターを置くと有効。(7.2.5)
- 規律を身につけるためには設置し、週替りなどで交代することでCIに慣れさせるとあり、一人でやらせるべきではなく、良い学習機会になるとのこと。
- 確かになぁ。これは今のプロジェクトに導入するにしてもその後が上手く回るように考えないといかんなぁ。
- 規律を身につけるためには設置し、週替りなどで交代することでCIに慣れさせるとあり、一人でやらせるべきではなく、良い学習機会になるとのこと。
自動受け入れテストが欠かせない理由
- ユニットテストとコンポーネントテストだけで良いだろうという極端な主張をする人もいる
- しかしながら、ユーザーの求めるビジネス価値の証明点、大規模な修正ではユニットテストやコンポーネントテストは作り直すことになるが受け入れテストは使い回せる点をみても必要。(8.2)
- 大幅に回収したいことはあるから受け入れテストあるといいよなぁー。
- コストが高くつくと思われているが効率性や費用対効果は十分みこめ、デリバリープロセスに対して、フィードバックループが短くなり、開発者、テスター、顧客の協力が進み、ビジネス価値に集中できるようになる。
受け入れテストの原則、考え方が存在する
- 受け入れテストはINVEST原則に従わなければならない(8.2.1)
- INVEST原則はユーザーストーリーの文脈で使われる
- 受け入れ基準を書くためのドメイン特化言語がある
- 前提(Given)、もし(When)、ならば(Then)で記述する。
- 受け入れテストは3層のレイヤで考える
- アプリケーションとのインタラクションを気にするのはアプリケーションドライバレイヤ。それより前はドメイン言語を使うべき。
- ウインドウドライバはアプリケーションドライバのプラグインと考える。
- 受け入れテストの所有権は開発者やテスターを含むデリバリーチーム全体で責任を持つ(8.6.1)
- テストチームだと開発の時差が出てしまい、対応しようとしても新たな要求のテストにプラスして対応しないといけなくなり不良債権が積もるだけ。開発者も受け入れテストを保守する責任があると、新たな変更を加える際もテストスイートを意識するようになるというメリットもある。
- なるほどなぁー。環境の用意だけではなく、マインドの定着もしないと破綻するということだろう。そこの意識を持たないと定着できんなぁ。
- テストチームだと開発の時差が出てしまい、対応しようとしても新たな要求のテストにプラスして対応しないといけなくなり不良債権が積もるだけ。開発者も受け入れテストを保守する責任があると、新たな変更を加える際もテストスイートを意識するようになるというメリットもある。
- 受け入れテストのパフォーマンスを維持するように努力しなければいけない。これはリファクタリングもする8.7.1)
- テストケースもメンテが必要だということか。
非機能要件のテストの仕方の勘所が書かれている
- 非機能要件を分析する際は他の要件と同様に受け入れ基準のストーリーを作ると他の要件と同列で扱えるので良い(9.2.1)
- 早すぎる最適化は諸悪の根源である(9.3)
- キャパシティテストは最適化すべきところを見つける為にする。推測するな計測せよ。
- これはごもっとも。
- 安定的なシステムを作るために「Release it!...」という素晴らしい本があるらしい
- 読んでみたい!がボリュームありそうな本だなぁ。
- キャパシティテストは最適化すべきところを見つける為にする。推測するな計測せよ。
- キャパシティ計測には相対的な方法(スケーラビリティテスト、長期稼働テスト)、絶対的な方法(スループットテスト、負荷テスト)がある。(9.4)
- キャパシティテストの自動化は壊れやすく難しいので、既存の受け入れテストをいくつかピックアップし、キャパシティテスト用に書き換える方法がオススメ(9.6)
- シナリオが反映されているため規模の拡大と成功の判断を足すだけで良いのか。なるほどねー。
- 受け入れテストの出力を記録し、テンプレート化して簡単に出力を複製できるようにする方法もある(9.6.3)
- これは面白いなぁー。そういう機構を入れておけばキャパシティテストも簡単にできるのか。
- キャパシティテスト環境は本番環境に近くなるため、検証や調査を効率的に行える(9.8)
- 確かになぁ。キャパシティテスト環境は品質面だけではなく他の利点もあるのか。
アプリケーションをデプロイ・リリースする勘所が書かれている
- アプリケーションの自動デプロイは、最初のイテレーションから準備しておくとよい。デプロイ先にバイナリを自動で送るプロセスはこのタイミングであると良い。(10.3)
- なるほど。本の中で何度も出てくるが、疑似環境でも開発環境でも自動で環境構築できるようにしておけば、リリースのリスクマネジメントになるとのこと。
- デプロイプロセスに自動スモークテストを組みむことをおすすめする(10.3.2)
- ここにスモークテストを組み込むのか。理にかなってるし、とても効率的だと感じる。
- リリース管理テクニックとして「ブルーグリーン・デプロイメント」がある(10.4.3)
- 環境を2系統用意し、ルータによって本番環境を切り替える。バージョンアップも本番環境ではないほうで確認したのちルータで切り替えればオッケー。ただ、DBの巻き戻しには注意が必要。
- ダウンタイムも少ないし理にかなってる。
- 環境を2系統用意し、ルータによって本番環境を切り替える。バージョンアップも本番環境ではないほうで確認したのちルータで切り替えればオッケー。ただ、DBの巻き戻しには注意が必要。
- 緊急修正という場面でもいつもの手順から外れてはならない(10.5)
- いつもの手順を踏まないといざ振り返ったときに何をやったか確認がとれない。
- スゴく良く分かる。プロセスを軽んじる隣の課はやりそう。てか、やっている。アホは死んでも学ばない。
- いつもの手順を踏まないといざ振り返ったときに何をやったか確認がとれない。
「継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化」を読んで(第1部)
書籍

継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化
- 作者: Jez Humble,David Farley,和智右桂,高木正弘
- 出版社/メーカー: KADOKAWA
- 発売日: 2017/07/31
- メディア: 単行本
- この商品を含むブログを見る
はじめに
読ませていただいた書籍は大変ボリュームがあるため、概要+各部ごとの記事としてまとめます。 本記事は「第1部:基礎」についてです。
その他の部についての記事は下記になります。
- 導入
- 第1部:基礎(本記事です。)
- 第2部:デプロイメントパイプライン
- 第3部:デリバリーエコシステム
印象に残った点
※ 下記のカッコ書きは該当する章番号。
「すべてバージョン管理に入れよ」はソフトウェアデリバリーの原則の1つ
- コードやドキュメントだけではなくプロビジョニングのスクリプトも入れる。
継続的インテグレーション(CI)はあくまで「プラクティス」であり、チームが規律を守ることが必要不可欠
- 継続的インテグレーションは真似れば出来る。ただ真似ただけでちゃんと運用として回るかどうかは別問題であり、ここにチームとして規律を守るという要素が絡んでくる。
- 例えば、変更においてアプリケーションが壊れたら最優先タスクして修正することをプロジェクトとして合意しないといけない。
- 規律なくして望むほどの品質向上にはつながらないとのこと。なるほど。これは肝に命じておきたい。
- 例えば、変更においてアプリケーションが壊れたら最優先タスクして修正することをプロジェクトとして合意しないといけない。
CIを始める前のプラクティス/基本的なプラクティス/やったほうがいいプラクティスが記載されている
- CIはプロジェクト途中から始めると多大な苦痛を伴う。そのためCIを始める前のプラクティスが必要となる。
- CI時における基本的なプラクティス(3.5)、やったほうがいいプラクティス(3.6)が書かれている
- ツールの使い方だと時代背景により廃れがあるものの、ノウハウ的なモノは普遍でありとても勉強になる。
- テストの種類としてブライアン・マリックが考えた「テストの四象限図」がある。(4.2)
- みたことある。無理に自動化すべきではない点はあることは体感してる。メリハリだよね。
- レガシーシステムとは自動テストがないシステムのことであるby マイケル・フェザーズ(4.3.3)
- 恥ずかしいことに、実務ではレガシーシステムしかみたことがないことになる...
「継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化」を読んで(導入)
書籍

継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化
- 作者: Jez Humble,David Farley,和智右桂,高木正弘
- 出版社/メーカー: KADOKAWA
- 発売日: 2017/07/31
- メディア: 単行本
- この商品を含むブログを見る
はじめに
読ませていただいた書籍は大変ボリュームがあるため、概要+各部ごとの記事としてまとめます。 本記事は「導入」についてです。
その他の部についての記事は下記になります。 (第3部はまとめるか微妙です。。。)
- 導入(本記事です。)
- 第1部:基礎
- 第2部:デプロイメントパイプライン
- 第3部:デリバリーエコシステム
この本を選んだ理由
- リリースサイクルを早くしたいと思いながらもその基礎知識が足りていないと感じていたため、基礎からしっかりと学べそうなこの本を選んだ。
この本の対象読者
- 製品開発の経験が少しある人。全くないと想像し辛いところはあるかも。
- 構成管理、ビルドプロセス、テストの種類(単体テスト/受け入れテスト等)のワードが分かるレベルでOK
今後
- エコシステムの情報が古いため、最新のエコシステムについて網羅されている本/ブロク記事など読んでみたい。
- ご存知の方がいらっしゃればコメントお願い致します。
「RDB技術者のためのNoSQLガイド」を読んで
書籍

- 作者: 渡部徹太郎,河村康爾,北沢匠,佐伯嘉康,佐藤直生,原沢滋,平山毅,李昌桓
- 出版社/メーカー: 秀和システム
- 発売日: 2016/02/24
- メディア: 単行本
- この商品を含むブログ (3件) を見る
TL;DR
- NoSQLの全体像を俯瞰したい人に最適な本。(ゴリゴリ利用したいというアプリ開発者向けではない。)
- 3年以上前の本のため、各NoSQLについては自らUpdateが必要。
- ただ、NoSQLを選ぶときのポイントがまとめられており、このポイントを用いて自らUpdateすることができるのでそれだけでも一読の価値がある。
この本を選んだ理由
- NoSQLの利用用途って何だろう?と思っていた時に本屋で見かけた為。
印象に残った点
RDBが適さない理由が書かれている(2-1)
- RDBはデファクトスタンダードであり業務システムを作る上では最適な選択肢であることが多い - しかしビジネスを拡大するために業務以外のデータを扱おうとすると、高速大量データや半構造データを扱うことが求められる - これらのデータはRDBではうまく行かない ⇒この問題を解決するにはNoSQL
- 要件を踏まえ適切なDBを使う必要があるということか。最適解を導くためにはRDB以外の選択肢を学ぶ必要があるのか。ふむふむ。
NoSQLは大きく分けて3つに分類される(2-2)
- キーバリューストア(KVS)、ドキュメントDB、グラフDBの3パターン - KVS - スケールアウトして大量データに対するクエリを高速に応答できる。 - キーでアクセスするシンプルな使い方がメイン。 - ドキュメントDB - KVSの特徴に加えてJSONを扱う機能が豊富。 - スキーマレスである特性も相まって開発効率がアップする可能性あり。 - グラフDB - スケールアウトできないがRDB以上に複雑なデータ処理が可能 - データの複雑度とスケールアウトはトレードオフ - 複雑度で並べると、KVS(キーバリュー)<KVS(ワイドカラム)<ドキュメントDB<RDB<グラフDB - RDBに比べ複雑度が右なのか左なのかは覚えておくとよい
- NoSQLでも種類があるのか。適材適所で使い分けできるようにならなければいかんなぁ。
アプリ開発者/DB管理者/経営者目線でのNoSQLに対するメリット/デメリットがまとめらてれいる(2-3)
- アプリ開発者目線 - メリット 1. データにあったデータモデルを選択できる ⇒ JSONやグラフデータを無理してRDBに入れることでの工数増加 ⇒ 直感的ではないクエリになってしまう 2. スキーマ定義をせずにデータを格納できる ⇒ スキーマが変わっても取り敢えずデータを貯めておけるのであとからのアプリ修正が可能 3. ドキュメントDBによる高速開発が可能 ⇒ スクリプト言語とデータ構造がマッチしており、プロトタイプ時には向いている。 ⇒ がっちり作るときはRDBを用いた手法を取ることがある。 - デメリット 1. KVSとドキュメントDBはRDBより機能が乏しい ⇒ スケールアウト性能を高めることで機能が落ちているところがある。 ⇒ RDBに比べ何ができないかを理解して選択する必要がある。 2. KVSとドキュメントDBはトランザクションや整合性を保つ機能が使えない ⇒ スケールアウト性能の為の代償。トランザクションが必要であれば採用すべきではない。 ⇒ ただ結果結合性という弱い整合性は提供している。 3. スキーマ管理をしないと何が入っているか分からなくなる ⇒ 最近はバリデーション機能があるものもある。 ⇒ ただし、本番環境で利用するのであればスキーマ定義は管理したほうが良い。 - DB管理者目線 - メリット 1. KVSとドキュメントDBは性能増強が容易 ⇒ メモリやCPUの増強、ストレージやクラスタ構成は不要で一般的なハードウェアを横に並べるだけで良い 2. KVSとドキュメントDBは高可用構成を簡単に構築できる ⇒ 一般的なハードウェアを横に並べてレプリケーションすること前提。 ⇒ レプリケーションであれば標準機能でまかなえる。 - デメリット 1. トラブルシューティングが難しい ⇒ ノウハウの充実がRDBに比べて不十分なので有償サポート加入がオススメ。 2. 運用に関する機能が乏しい ⇒ クエリ統計や診断レポートの出力がなかったり、SQL実行計画を出す機能がない場合がある。 ⇒ 作り込みする必要になることになる場合があり工数増加の可能性がある。 - 開発者目線 - メリット 1. KVSとドキュメントDBはハードウェア、ライセンスのコスト削減が期待できる ⇒ スケールアウトしやすいので流量が増えた時に買い増しが可能だがRDBであれば難しいし。 ⇒ KVSやドキュメントDBであればOSSを使うことも可能 2. ドキュメントDBは開発生産性向上による新製品投入速度向上が期待できる ⇒ RDBに格納することが非効率なケースにおいてはドキュメントDBにすることで開発や保守の効率改善になる - デメリット 1. 技術者の確保・育成に苦慮 ⇒ 一般的なエンジニアがNoSQLを学習し、他人の力を借りずに本番運用をこなせるようになるのはかなり難易度が高い。 ⇒ RDB利用するレベルのエンジニアであれば手が出ない。有償サポートを購入し、トレーニングすることがオススメ。 2. 開発の標準化が困難 ⇒ スキーマレスなのでいかようにも格納でき、問い合わせ方もばらばら。性能問題のノウハウも蓄積されていない。
- 立場の違いからメリット/デメリット書いてあってとても良い!
- NoSQL学ぶのは敷居高いのか。相当ビビらせる記載になっている。
よくあるNoSQLの勘違いがかかれている(2-4)
- 「バッチが高速になる」は勘違い ⇒ ビッグデータのバッチ処理ができるのはHadoop - 「トランザクションが高速になる」は勘違い ⇒ RDBのような厳密にACID特性を保証したNoSQLはない。 ⇒ ACID特性とスケールアウトによる性能向上がトレードオフのため。 - 「ビッグデータを分析できる」は勘違い ⇒ ビッグデータの分析を得意とするのはHadoop。 - 「非構造データが効率的に扱える」は正解ではない ⇒ 「非構造データ=音声や動画といったマルチメディアデータ」でありNoSQLが扱うのは不得意。 ⇒ 得意なのはJSONなど構造を事前に知ることができない「半構造データ」。 - 「RDBから置き換えると速くなる」は正解ではない ⇒ 正しく言うと「速くしたい処理が分散でき、かつその分散処理をできるNoSQLを使えればRDBより速い」。 ⇒ NoSQLにも得手不得手があるので適した分散処理のNoSQLを選択して初めて速くできる。 - 「オープンソースしかない」は昔の話 ⇒ クラウドサービスや商用製品もある。既存のRDBもJSONを格納できるNoSQLインターフェースがある。 - 「スキーマがない」は昔の話 ⇒ スキーマ定義しないといけなかったり、バリデーションがあるNoSQLが出てきている。 ⇒ 型のチェックができるようになっている - 「SQLが使えない」は昔の話 ⇒ NoSQLにてSQLライクな問い合わせ言語を提供してきている
2つの軸によってDBは4つのエリアに分類できる(3-2)
- 2つの軸 1. ターンアラウンドタイム対スループット 2. スケールアウト性能 - 4つのエリア スケールアウトできる ┃ 4┃3 ターンアラウンドタイム重視 ━━━╋━━━ スループット重視 1┃2 ┃ スケールアウトできない 1-1. RDB(OLTP) ⇒ OLTPとはOnline Transaction Processingの略でオンラインのCRUDをトランザクションとして処理する方法。 ⇒ 一部を高速に処理できるが、全体に対する集計は苦手。 ⇒ OracleやMicrosoft SQL Server、MySQLがこのエリア。 1-2. グラフDB ⇒ RDBでは表現が困難なつながりを表現し、複雑なクエリを高速に実行できる。 ⇒ ただデータの結合度が高く、クエリやデータの分散が難しい。 ⇒ ドキュメントDBに至る経緯とは全く異なる。Neo4j、OrientDBがこのエリア。 2. RDB(DWH) ⇒ DWHはデータウェアハウスの略。データの使い方がスループット重視。 ⇒ Teradata、Oracle Exadata、AWSのRedshift、GCPのBig Queryがこのエリア。 ⇒ ハードウェア含めてライセンスとして提供するものもある。 ⇒ 列指向の性質を持っており、列ごとにデータを圧縮している。 3. Hadoop(HDFS+MapReduce) ⇒ Hadoopという名のソフトがあるわけではなく、あくまでフレームワーク。 ⇒ 分散システムであるHDFS、そのうえで動く分散集計フレームワークMapReduceなどのソフトウェアが連動し、スケールアウトして集計する。 ⇒ Apache HadoopやAWS Elastic MapReduce、Oracle Big Data Aplianceなどががこのエリア。 4-1. KVS ⇒ スケールアウトして処理を分散する。 ⇒ オンラインでビッグデータに対するランダムなCRUDに対して短いターンアラウンドタイムで応答可能。 ⇒ データ間が疎結合であり分散配置しやすい。 ⇒ Cassandra、Redis、DynamoDB、Google Datastoreなどがこのエリア。 4-2. ドキュメントDB ⇒ KVSと同様にオンラインでオペレーションを行う点では同じだが、格納がJSONであり、JSONに特化した機能を持つ。 ⇒ MongoDBやMicrosoft Azure DocumentDBなどがこのエリア。
RDB(OLTP)とKVS/DocDBの違い(3-3)
- RDB(OLTP)は強い整合性があるが、その整合性を保ったままではスケールアウトできない - 強い整合性を保つための機能がトランザクションであり、トランザクションはACID特性を持つ 1. 原子性(Atomicity) ⇒ トランザクションに含まれる操作は全て行われるか行われないかのいずれか。 2. 整合性(Consistency) ⇒ トランザクションがDBに課した整合性ルールを満たすことを保証。 ⇒ ルールを満たさないトランザクションは失敗させる。 3. 独立性(Isolation) ⇒ トランザクション同士が互いに影響を与えることはない。 4. 永続性(Durability) ⇒ コンピュータがクラッシュしても成功したトランザクションの結果は失われない。 - 強い整合性を保つために「2フェーズコミット」の手法を用いている ⇒ 2つのノードがある場合、両方の準備が整った返答を受けてから一斉にコミットする。 ⇒ したがって、台数が多くなるほど応答が遅くなる。 - KVS/DocDBでは3つの工夫で性能をスケールさせている 1. 分散トランザクションを提供しない ⇒ 代わりにクエリを分散する「シャーディング」が可能。 ⇒ 複数のノードを更新が必要な場合でもバラバラにクエリを実行できる。 ⇒ ACID特性の独立性が守られないため強い整合性は保たれない。 2. 分散しやすいデータ構造とクエリだけを提供する ⇒ データ間に関連がないため分散しやすい構造。 ⇒ クエリもキーで問い合わせるだけのシンプルなモノであり、処理は確実に1つのノードで完結する。 3. 強い整合性を犠牲にして、データの複製に対して読み書きする ⇒ データを複製する「レプリケーション」によりアプリケーションの応答とは非同期でデータ同期する。 ⇒ そのため、一時的に正しくない答えになることになったり、同時更新によりどちらが正しいか分からなくなったりする。 ⇒ ただ、最終的には整合性が取れる「結果整合性」にはなる。 - KVS/DocDBの思想はACID特性になぞらえはBASE特性と呼ばれる 1. どんな時でも動く(Basically Availability) 2. 常に整合性を保っている必要はない(Soft-state) 3. 結果として整合性が取れる状態に至る(Eventual Consistency) - CAPの定理 - Consistency(整合性)、Availability(可用性)、tolerance to network Partitions(分断耐性)の3つのうち最大2つまでしか満たすことができないという定理 1. C(整合性):全てのノードで同時に同じデータが見える。「強い整合性」と同義。 2. A(可用性):単一障害など一部のノードの障害が起きても処理の継続性が失われない 3. P(分断耐性):ノード群までネットワークが分断されても正しく動作する - CA特性を持つシステムの特徴 ⇒ シンプルなActive-Standbyのクラスタ構成DB。RDB(OLTP)が該当。 - CP特性を持つシステムの特徴 ⇒ 奇数台のクラスタで構成する ⇒ ネットワークが切れた時にクラスタの過半数より多くのノードと通信できる集団を生きているクラスタとして動作させ続ける ⇒ しかし、残ったクラスタは利用できなくなるため可用性が下がる。 ⇒ Redis、MongoDB、HBaseがこの特性を備える。 - AP特性を持つシステムの特徴 ⇒ ネットワークが切れてもクラスタを構成する全てのノードで読み書きが可能。イメージとしてはGit。 ⇒ 同じデータに対して複数のクライアントで書き込みをするため、古いデータがみえたり、書き込みが競合する可能がある。 ⇒ 整合性は保たれないが、競合が発生することを前提として設計されているため、動作を停止させるような事態にならない。 ⇒ Cassandra、CouchDB、DynamoDBがこの特性を備える。
- ACID特性の細部まで理解していなかったので良い勉強になった。
- 結果整合性か。結果整合性が正しければ許されるのであればKVSやDocDBを使っても良いのだろう。要件次第ですなぁ。
- BASE特性か。KVSやDocDBの強みを説明する上で重要な言葉だなぁ。覚えておこう。
- CAP定理言わんとすることは分かるが、新たな製品をみてどこに分類されるか分かる自身がない。
HadoopとKVS/DocDBの違い(3-4)
- Hadoopの動作 1. データを分散ファイルシステムに書き込む 2. 分散ファイルシステムは各ノードにファイルを分割する 3. 分散処理フレームワークにプログラムを提出する 4. コーディネータが各ノードにプログラムを各ノードにばら撒く 5. プログラムを各ノードで実行 6. 各ノードで順次計算が終わるとコーディネータが結果を集める 7. 最終的な計算結果を分散ファイルシステムに格納する ⇒ 書き込みは1回、読み込みは多数。実行してから答えが出るまで時間がかかるバッチ処理。 - KVS/DocDBの動作 1. データを分散して格納する(シャードノード) 2. CRUDオペレーションの為にクエリルータにクエリを投げる 3. アプリケーションは同期処理のためクエリ応答を待つ 4. クエリルータはデータのキー値によって適切なシャードを選出し、シャードにてクエリを実行 ⇒ ターンアラウンドタイムは数ミリ秒。クエリ実行中にシャードがダウンするとエラーになるものもある。
- 全データを舐める処理は確かにKVS/DocDBのやりたいことからはズレますなぁ。何をやりたいNoSQLなのか?理解して採用しないとアカン。
各NoSQLの説明が機能/非機能の観点からまとめられている(6〜13)
- 概要、機能(データモデル/API)、非機構(性能拡張/高可用/運用/セキュリティ/できないこと/主なバージョンと特徴/国内のサポート体制/ライセンス体系/効果的な学習方法)として決められた観点からまとめている - 対象プロダクトは下記8つ - Redis - Cassandra - HBase - Amazon DynamoDB - MongoDB - Couchbase - Microsoft Azure DocumentDB - Neo4j
- 決まった観点から複数のではプロダクトを説明しておりメリット/デメリットが分かりやすい
- ただ、発行から3年半ほど経っているで色々と変わってそう。この本で概略を掴んでから更に詳しい本を読むのが良さそう。
- Cassandraすげー。有償のものもあるが運用面だけみれば何でも出来る。RDBにあるトランザクション、ロールバック、ロック、SQL関数、結合、外部キー、ストアドプロシージャはないが、そういう用途で使うものではないので問題ないのだろう。悪い事書かれてないなぁ。
- HBaseの設計思想はテーブル定義は列ファミリのみ定義し、列名はアプリケーションの実装段階(データの格納時)に決めるのか。面白い考え。
- DynamoDBは13個のAPI、複数行更新のためにBatch API用意しているのか。自分でFaaS作る時の名前の付け方参考にもなるなぁ。
- MongoDBはJSONスキーマの事前チェックが可能なのか。決まった構造だけを対象にできることはメリットがあるだろうなぁ。
- インデックスの種類や属性も色々用意されてるなぁ。地理空間のインデックスなんてあるんだ。
- Couchbaseはクラウド、オンプレ、更にモバイルまでカバーするものが特徴。
- Microsoft Azure DocumentDBは昔REST APIアクセスする際のURLに内部で自動生成されるリソースID使っていたらしい。途中でユーザ設定可能なIDを使えるようになったらしいが、最初の仕組みはどう考えても辛い。
- デフォルトだと全てのドキュメントプロパティに同期的にインデックスを貼るとのこと。デフォルト運用はしないんだろなぁ。
- DocumentDB SQL、ストアドプロシージャ、トリガなどを見てもRDBと遜色なく触れそう。しかもストアドプロシージャやトリガなどはJavaScriptで書くのか。書きやすそう。
- CosmosDBに名前変わってるのか。DB-Enginsのランキングに載ってないわけだ。
- 整合性が強い整合性から結果整合性まで4種類提供している。ほぇー、選べるなんてすごい。
- わ
- と思い調べてみたら、いくつものグラフDBではクエリ言語としてGermlinがサポートされているらしい。
NoSQLを利用するユースケースが多数紹介されている(14)
- Redisのユースケース - Webアプリケーションキャッシュとして利用する - WebアプリケーションとRDBが直接やり取りするとRDB部分がボトルネックになる。 - Redisにキャッシュを格納しておき、Webアプリケーションはまず最初にRedisに問い合わせる。 - キャッシュになければRDBに問い合わせし、その結果をキャッシュする。同様なクエリを何度も発行する場合に効果的。 - RDBのスケールアウトしづらさをRediusによってレプリケーションによる容易なスケールアウトが可能となる。 - Casandraのユースケース - 時系列データを横持ち(列追加)にして扱う - IoTの場合、毎秒データを挿入するケースがあり、センサーが増えると爆発的に増える。 - RDBだとレコードを挿入する形になり、パフォーマンスを維持することが難しい。 - Casandraであれば20億カラムまで1行に持たせられ、毎秒更新、毎分更新なども1行にあ納められる。 - MongoDBのユースケース - ログ格納システムに利用する - RDBだとフォーマットがバラバラなログを集約しようとするとテーブル定義が大変、スケールアウトが大変、トランザクション、結合、ストアドプロシージャなど高度な機能はオーバースペック。 - Hadoopだと即応性が低い。その要件がなければHadoopでもよい。 - 他のNoSQLでも良いがFluentdとの組み合わせを考えると最も適切。 - ECサイトのカタログ管理に利用する - ECサイトはアイテムをDBに格納するが属性が異なることが多い。RDBを利用して格納すると属性変更になり重いクエリを発行しないといけないだけではなく、アイテムが増えた際の応答速度向上のスケールアップが大変。 - MongoDBによりアイテムをJSONで入れれば属性変更が容易でかつ、アイテム増加もシャーディングで対応できる。 - JSONにすることでIT知識が少ない人でも生データからレビューが可能となり、開発の生産性向上にもつながる。 - Couchbaseのユースケース - モバイルとサーバのデータ同期に利用する - 従来型だとサーバサイドでDBにアクセスするためのAPIサーバが必要だったり、電波が不安定や届かない場所だとアプリが全く使えない問題がある。 - Couchbase Liteを使うことでローカルデータベースをモバイルアプリに組み込み、ネットワークの接続状況に依存せず稼働できる。サーバとの同期も用意されているため自作不要。 - Neo4jのユースケース - リアルタイム詐欺検出に利用する - IP、クレジットカード、ID、クッキーの関連性をグラフ化することで、取引パターンが違いを検出できる。 - RDBでは結合のコストが高く、SQLクエリだけで記述が困難。 - 適材人材の検索システムに利用する - 人材データ(経験年数、スキルセットなど)をグラフデータベースに入れ、適合度を計算する。 - RDBだとテーブル設計の煩雑さに加え、結合、入れ子など複雑なSQLになり、性能が出ないという問題になる。
- なるほどー、最初にRedisのキャッシュにアクセスさせるのか。
- 時系列データを横持ちにするのか。これはRDBではできない。
- ログ格納システムにてRDBを使うとツラミが多く、NoSQLのウマミがよく出せる。Fluentdとの相性を考えると他のNoSQLより沢山の実績があり、公式にも接続方法の記載があるためMongoDBになるのか。
- ECサイトの例はRDBとNoSQLのメリットが分かる良い例だなぁ。ハイブリットにしアプリケーション側からは意識しないで使える仕組みにするのか。
- FirebaseとCouchbaseのモバイル対応は似てるなぁ。この考えがモバイル対応の王道なのかも知れない。
- グラフDBは経路検索などのグラフの問題を解く為だけではなく、異常系パターンの検知、パターンの適合度などに使えるのか。
RDB(OLTP)⇒NoSQLにより解決できない/できるかわからない/できるの3つの観点からまとめられている(15-1)
- 大前提として現状のデータ処理に課題があるかないかにフォーカスし、課題がなければ検討しなくて良い。 - 解決できない 1. バッチ処理性能向上 ⇒ シャーディングにより性能向上はするかもしれないが、HadoopやRDB(DWH)を利用すべき。 2. データローディング処理性能向上 ⇒ 分析のためのデータローディングであればRDB(DWH)が得意。用途が違う。 - 解決できるかわからない 1. トランザクション処理性能向上 ⇒ 厳密なACID特性が必要であれば解決できない。 ⇒ ただし、1つのJSONとして管理できるのであればACID特性に対応したNoSQLを採用して解決できる。 2. パフォーマンスチューニング簡素化 ⇒ NoSQLはそもそも複雑なクエリは実行できないのでチューニング問題が発生しづらい。 ⇒ またスケールアウトも簡単なので割り切った考えができる。 3. 非構造データの処理のしやすさ ⇒ JSONやXMLのような半構造データが得意 ⇒ 少容量のデータの出し入れに向いているをマルチメディアデータは外に置き、メタデータを格納するのが一般的。 4. 運用管理コストの削減 ⇒ クラウドであれば初期構築、運用のコスト削減は期待できる。 ⇒ ただ、NoSQLは知見が少なくトラブルシューティングのコストは増加する。 ⇒ スケールアウト前提に作られているため性能拡張によるコストは削減できる。 - 解決できる 1. クエリ検索の性能向上&データレイテンシ改善 ⇒ ボトルネックをシャーディングにより分散できるなら効果がある。 ⇒ RDB(OLTP)の性能改善余地があるのにNoSQLを前提とするのは間違い。 2. 初期導入コストの削減 ⇒ スケールアウト前提なのでスモールスタート可能 ⇒ システム規模に応じて後からサーバ台数の増加でカバーできる。
- 現状のデータ処理に課題がなければNoSQLの採用を検討する必要がないと断言されている。会社なので利益にならないことするな的なのとも書いてあり刺さるわぁー。
- まずはRDB(OLTP)で出来ることをやる。を念頭にしていきたい。
処理性能や半構造データの処理のしやすさによる選び方などがまとめられている(15-1〜15-4)
- データが古いので鵜呑みにできないところがある。
NoSQLを選ぶときのポイントがまとめられている(15-5)
- 下記の差別化になる特徴に着目すると良い - データモデル - データモデルは何か? - データ型は何に対応しているか? - データ構造の事前定義は必要か? - API - クエリはどのような言語か?SQLライクか? - トランザクションがあるか? - ACID特性をどこまで保証しているか? - セカンダリインデックスがあるか? - EXPLAIN句やHINT句があるか? - 条件検索、ソート、LIMIT、集計、結合、データの部分更新があるか? - クエリの整合性は調整できるか? - 性能拡張 - どのようにデータを分散するのか?ハッシュかレンジか? - どうやってクエリを分散するのか? - データの再配置が自動でできるのか? - 複製に対する書き込みができるか? - 高可用 - レプリケーションはマスタースレーブか?マルチマスターか? - 原子性をもった更新はどの単位か? - 運用 - ツールはCUIベースか?GUIベースか? - 監視やバックアップは自動でできるか? - デプロイメントの自動化ができるか? - クエリのプロファイラはあるか? - セキュリティ - 細かいアクセスコントロール、監査ができるか? - その他 - 国内サポートを受けられるか? - どれくらい使われているか?事例はあるか?
- この観点表だけでも十分な価値がある。関係者へNoSQL導入を説明するために最適だ。
今後
- NoSQLにて解決したいことは何なのか?そこが不明確なのであればNoSQLを導入することに意味がないことをこの本より学んだ。
- まずは業務で利用するRDBについて深く学ぶことが必要だと感じた。