簡易バージョン管理ツールの作成
今月は、読書の他に、簡易的なバージョン管理ツールの作成を行いました。
https://github.com/mes51/VCS
仕様
アプリの仕様は以下の通り。
要求仕様
- ブランチはmasterのみ
- ファイルの属性は管理しない
- 実装するコマンドは以下のもののみとする
- add
- commit
- reset [--hard] HEAD(~num|^+)
- log
- status
- init [--force]
- add
- diffの対応ファイルタイプは後から増やすことができる
- 対応していないものはバイナリとして扱う
アーキテクチャ
- 使用言語: Ruby 1.9.3
- テストツール: rspec、モックライブラリとしてrr、fakefsを使用
- 環境: CentOS 5.8
登場人物
- Repository 今までのコミットとインデックスを保持する。また、インデックスの更新、コミットの追加等、リポジトリへの変更はこのクラスを通して行う
- Commit コミットメッセージとファイルの変更点(Hunk)の配列、記録日時、コミットのハッシュを保持する。
- Hunk ファイル名とDiffで取得することの出来るファイルの変更点を保持する。
- Index バージョン管理されている各ファイルについて、前回のコミット時の完全な状態と、そこからの変更点、各ファイルのハッシュを保持する。コミットに記録する変更点ははここに記録された変更点を使用する。
- Command、Commandからの派生クラス このプログラムで実行できるコマンドを表す。
- DiffBase、DiffBaseからの派生クラス 比較元のデータから、対応したファイルのdiffを取得、または記録したしたdiffから、元のデータに変更を加える。
- DiffCreator 与えられた拡張子から適切なDiffの派生クラスのオブジェクトを返す。また、クラス名からDiffのオブジェクトを返す。Diffの派生クラスは、plugin/diff以下から検索する。
クラス図
作成したクラス図は以下のようになります

上図のDiffCreatorとDiffBaseの関係はFactoryパターンで、MainとCommandはStrategyパターンで実装する
指摘された点
名前の付け方が変
- プロジェクト名がVCS(Version Control System)となっていますが、一般的な用語ではなく、固有名詞を使用するべき
READMEがない
- プロジェクトのページを見たとき、このプロジェクトが何のプロジェクトなのか、何を刷るプログラムなのかがわからない
クラスをルートに定義するのではなく、名前空間を使用してその中に定義すべき
- 現在、各クラスをルートに定義しているが、VCS::〜等、moduleを定義して名前空間を分け、その中に必要なクラスを定義するべき
printではなくputsを使う
- pとputsとprintは別のメソッドである
不必要にtapを使用しない
- DiffCreator#get_classesではfind_allが使えるし、他にもmapで十分なところでもtapを使用している
DiffCreatorのスクリプト読み込み部分でevalを使用している
- requireを使用して読み込むべき
Factoryパターン(DiffCreator – DiffBase間の関係)について
- 実装としては微妙。そもそもバイナリとテキスト以外比較するものがないため、Factoryパターンを使用するべきかどうかが怪しい。
Strategyパターン(Main – Command間の関係)について
- Command#execute(args)ではなく、Command#execute(*args)にすべき
- Command#executeに受け取った引数を生のまま渡すのではなく、全ての準備が完了した時点でexecuteを呼ぶようにすべき
まとめ
10月にオブジェクト指向のこころ読書会を行い、オブジェクト指向やデザインパターンについてある程度は理解できたかなと感じていましたが、実際に意識するとほとんど適用できていませんでした。また、コードに関しても非常に多くの問題点が浮かび上がり、まだまだ勉強が足りていないことを強く実感しました。すでにプロダクトのコードを書いているということもありますが、evalを使用している点など、業務、業務外関係なくまずいコードを書いているということがはっきりとわかったので、これらの点を早急に直し、再発しないようもっと勉強していきます。
ロジカル・シンキング 論理的な思考と構成のスキル 問題解答
今月は、技術的な勉強ではありませんが、ロジカル・シンキング 論理的な思考と構成のスキルを読みました。同書内では各章に問題が設定されており、学習の度合いを測ることが出来るようになっています。そこで、各章の問題の解答を行ってみたいと思います。
1章
問題1
- おかしいと思われる点
- どういう理由でこの文章が回ってきたのか
- この結果から何のリターンが欲しいのかが書かれていない
- なんのためにこの調査を行ったのか
- どういう理由でこの文章が回ってきたのか
問題2
- テーマが実態についてなのに、内容が実態についての説明がない
問題3
- 件名と聞きたいことが一致していない
- この内容ならタイトルは 【質問】月刊「バラ栽培」の広告料について にすべき
3章
集中トレーニング1
問題1
弁当の種類
- 買う
- 店頭で買う
- コンビニ
- 弁当屋
- スーパー
- 注文する
- 宅配
- 訪問
- 店頭で買う
- 自作
問題2
テレビ番組
- バラエティ
- 旅行
- お笑い
- ドラマ
- ニュース
- 定時
- 臨時
- エンターテイメント
- 音楽
- 映画
- アニメ
- 朝(子供向け)
- ゴールデンタイム
- 深夜アニメ
- スポーツ
- 解説
- 生中継
- 録画
- 文化
- 教育
- 遊技
- 文化発信
問題3
顧客への営業活動
- 営業活動
- 直接的
- CM
- 電話
- 訪問
- 間接的
- DM
- 広告
- 新聞
- POP
- 直接的
- 顧客
- 個人
- 企業
問題4
弊社が提供しているサービス
- エンターテイメント
- 音楽
- 配信サービス
- 着うた
- 着うたフル
- 着メロ
- ライブ
- 動画
- 相撲
- 動画投稿サイト
- リアルタイム動画配信サイト
集中トレーニング2
問題1
- 固定費
- 預金
- 定期預金
- 社内預金
- 保険
- 生命保険
- 車の保険
- 家賃
- 英会話学校の月謝
- お見合いシステムの会費
- エステ・ヘアサロンの費用
- 変動費
- 交通費
- 公共料金
- ガソリン代
- 駐車場代
- 食費
- 社員食堂の食券代
- 食費
- 娯楽
- 旅行
- 交際費
- 合コン費用
- 小遣い
- 本代
問題2
- 買い主の指向
- 1
- 5
- 8
- 10
- 11
- 対抗の動き
- 2
- 4
- 7
- 当社の動き
- 3
- 6
- 9
問題3
- パスタソース市場の動き
- 1
- 4
- 7
- 対抗の動き
- 2
- 6
- 8
- 9
- ミートソースライトについて
- 3
- 5
- 10
4章
集中トレーニング1
問題1
テーマ: 西友の現状と建て直し手段
- 現在、割安感や品揃え、ライフスタイル提案の面で、カテゴリーキラーやディスカウントショップに後れを取っている
- 日曜大工関連や衣料品などの売り場を専門店として出店する
- 定休日の削減や営業時間の拡大を行い、販売機会を増やす
問題2
テーマ: ウイスキーの市場別銘柄指定率
- 家庭用市場では、顧客は自分が欲しい銘柄を明確に持っている
問題3
テーマ: 観光地に関する旅行者の意識
- 評価指数が10以上の観光地は、来訪指数が40以上に分布している
- 来訪指数が40以上の観光地は、大体が若干期待以下から若干期待以上の領域に分布している
- 来訪指数が40以上の観光地は、評価指数-5以下がほぼない
集中トレーニング2
問題1
ミートソースライトのプロモーションとして、新商品導入キャンペーン、ヘルシーダイエットキャンペーン、期末ボリュームキャンペーンと行ってきたが、上期目標の売り上げと利益を達成できていない
問題2
パスタソースの嗜好がミートソース、ナポリタンがメインだったものが、多種に分散している。また、重視する点として価格、メーカー等製品の外側から、味や素材等、製品の中身を重視するように変化している
問題3
ミートソースライトは、スーパーマーケットで値頃感が評価されており、目玉商品として活用されている。
集中トレーニング3
ウイスキーの営業を掛ける対象として、業務用市場は不適切で、家庭用市場に対して掛けるべきだ
6章
集中トレーニング1
問題1
A: 4 医療用チャネルのみで出ている訳ではなく、現状として各社横一線になっているので、3は内容として不適切。 B: 1 内容として判断基準の話になっているのは1のみ
問題2
A: 5 B: 2 5では戦略、2では組織について、今後の方針の説明をしている。 C、D、E、F: 3、6、7、8 G: 4 1はA、Bの内容と照らし合わせたとき、全く関係ない内容になっている
集中トレーニング2
問題1
要因1~3でMECEになっていない。4P(商品、プロモーション、場所(販売チャンネル)、価格)という点で見たとき、要因1はどれにも当てはまらない。 また、1~3で販売チャンネルについてが欠けているため、要因1ではそれを説明する必要がある。また、要因3はプロモーションと価格についてが混在しているため、分割すべき。
問題2
判断基準と判断内容が結論と一致していない。結論の判断基準は「商品を事業化するかどうか」の基準になるべきだが、問の判断基準は「ヒット商品になるかどうか」の基準になっている。また、判断内容についても、「商品を事業化するかどうか」についての基準に照らし合わせ、その基準を満たしているかどうかを示すべきだが、問の内容は「事業化した後の商品の展開について」になっている。
7章
問題1
課題 顧客がどのような不満を抱えているか
結論 オペレータへの接続の悪さや、顧客への提案、質問への回答が適切でない
A: オペレータへの接続の悪さ 電話が一回でつながらなかったり、操作が煩雑等、オペレータに繋ぐまでの手間と時間が掛かっている
- A-1: コールセンターに電話をしても、一回でつながったことがない
- A-2: オペレータに繋ぐまでに、コンピュータの操作を何度も行わなければならず、手間が掛かる
B: 顧客への提案、質問への回答が適切でない 顧客に対しての適切な商品の提案や、顧客からの質問にきちんと答えられていない
- B-1: 顧客から「何か提案は?」「ローンのおすすめは?」と聞かれても、何も提案できなかったり、投資信託の商品を出すなど、適切な商品の提案が出来ていない
- B-2: 一番近い支店の質問をされても、支店名しか答えず、支店の住所や電話番号などを伝えていなかったり、回答するに当たって交通手段や用向き等、適切な回答をする上で必要と思われる事項について何も聞いてこない。
問題2
課題 新婚旅行にあった旅行先はどこか
結論 旅行前の期待感や、旅行先の好感度から、白神山地、黒川温泉、西表島のいずれかが適切である
根拠 「観光地に関する旅行者の意識」という資料に、「どのくらい行ってみたいか」「行く前の期待感と比べ、どのくらいよかったか」を数値化し、図にした資料がある
判断基準 旅行の行き先として、次の2点が重要であると考える
- 行く前の期待感を持てるよう、来訪指数は60以上
- 思い出に残す、行って良かったと思えるよう、評価指数は10以上
判断内容 「観光地に関する旅行者の意識」から、適切な観光地として白神山地、黒川温泉、西表島が適切であると考える。
まとめ
いままで、よく相手に物事を説明する際、「何を言いたいのかわからない」といわれていましたが、今回この本を読んで、原因として、
- 話したい内容がまとまっていない
- 「この点については相手も理解しているだろう」という前提が多すぎる
という点があると思いました。この点を解決するには、同書の方法は有効であると思いますが、実際に練習問題を通して実践したところ、うまく使用できておらず、本にも書いてある通り、実際に使用してなれることが必要だと感じました。
ロジカルシンキングについては他にも本がいくつも出ているので、今後他の本も読もうと思います。
オブジェクト指向でなぜ作るのか まとめ
2月は「オブジェクト指向でなぜつくるのか」という本を読みましたので、まとめてみたいと思います。
各章の簡単なまとめ
1章
- オブジェクト指向の基本的な考え方
- なぜオブジェクト指向が理解しにくいか
- 用語の氾濫
- 比喩の濫用
- なんでもオブジェクト症候群
2章
- オブジェクト指向は現実世界をそのまま表すものではない
- 人や物はクラスから生成されるわけではないし、メッセージだけで動作するわけではない
3章
- プログラミング言語の歴史
- 機械語からアセンブリ言語、高級言語へ
- GOTOレスプログラミング
- グローバル変数と貧弱な再利用をどう解決するか
4章
- オブジェクト指向の基本的な説明
- 前出の「グローバル変数と貧弱な再利用をどう解決するか」という問題の解決策
- OOPには構造化プログラミング言語にはない3つの要素がある
- クラス
- まとめる
- 隠す
- たくさん作る
- ポリモーフィズム
- 継承
- それ以外のOOPの特徴
- パッケージ
- 例外
- GC
5章
- プログラムが動く仕組み
- コンパイル方式とインタプリタ方式
- 中間コードと仮想マシン
- メモリの使われ方
- 静的領域、ヒープ領域、スタック領域
- クラスの情報は1度だけ読み込まれる
- インスタンスはヒープに作られる
- 孤立したインスタンスはGCで回収される
6章
- OOPによる部品の再利用
- クラスライブラリ
- Objectを頂点とするクラスの継承関係
- フレームワーク
- デザインパターン
7章
- OOPの応用
- 集合論と役割分担
- 「汎用の整理術」
- なぜ「汎用の整理術」に化けたのか
8章
- UML
- 使い方
- プログラムの構造や動作の表現
- クラス図
- シーケンス図とコミュニケーション図
- 「汎用の整理術」の表現
- 非OOPの表現
- ユースケース図
- アクティビティ図
- ステートマシン図
9章
- モデリングについて
- 現実世界とソフトウェアのギャップを埋める
- アプリケーションによってモデリングの内容が変わる
- ビジネスアプリケーションではデータのみがシームレスに現実世界とソフトウェアがつながる
- 組み込みソフトウェアは現実世界の仕事をそのまま置き換える
10章
- 設計を行う上での3つの目標
- 重複の排除
- 独立性を高める
- 依存関係の循環をさせない
- 責任の移行
11章
- ウォーターフォール型開発プロセスと反復型開発プロセス
- RUP
- XP
- アジャイル宣言
- TDD
- リファクタリング
- CI
12章
- 今までのまとめ
13章
- 関数型言語
- 関数でプログラムをくみ上げる
- すべての式が返値を返す
- 関数自体を値として扱える
- 関数と引数の組み合わせ
- 副作用を起こさない
- ループは場合分けと再帰で組む
- 型推論
- 関数型言語のメリット
まとめ
内容としては、オブジェクト指向の説明としては、オブジェクト指向のこころほど深くは掘り下げてはいませんが、なぜオブジェクト指向が理解しにくいか、その問題点をあげ、その問題点の解決に重点を置いているように感じました。最後の章に関数型言語の話も出ており、Haskellを紹介しており、こちらについても興味がわいてきたので、調べてみたいと思います。
gitの運用フロー設計・運用と見積もりの練習
1月はgitの運用フローの設計と見積もりの練習をおこなっていました。
gitの運用フロー設計・運用とコードレビュー
gitの運用フローの設計・運用
当時、明確なgitの運用フローは決まっていなかったため、この機会に運用フローの設計を行いました。最初に設計したフローは以下の通り。
- 機能の実装はトピックブランチで行う
- 実装完了後、developmentブランチにマージし、レビューを受ける
このフローで運用開始し、改良した結果、以下のようなフローになりました。
- 機能の実装はトピックブランチで行う
- 実装完了後、リモートにプッシュ、レビューを受ける
- レビュー通過後、developmentブランチにマージする
設計時と比べ、運用後のフローではバグの混入の防止や、コードの質の向上を図ることが出来ました。また、このフローは現在ではチーム全体のルールにもなっているため、今後も運用と改善を続けていきたいと思います。
コードレビュー
コードレビューについては、マージ時のレビューの他に毎朝コードレビューを行っていました。こちらのコードレビューでは、主にコードの書き方に関してのレビューがメインでした。こちらのレビューでは、コードの問題点を見つけることができ、改善することが出来ました。
見積もりの練習
gitの運用フローの設計と運用の他に、作業の見積もりの練習を行っていました。内容としては、Excelなどに作業と内容、予測作業量を書く、というものでした。
1ヶ月通して練習を行った結果、見積もりの際に作業を軽く見積もる傾向がある、ということがわかりました。しかし、作業の見積もりの練習に関しては、途中作業見積もりを行うことが目的になってしまい、見積もりの練習としてはほとんど意味のないものになってしまいました。
まとめ
1月の課題では、ボリュームは少ないながらも、非常に重要な部分について学べたのではないかと思います。ただ、見積もりに関しては目的とゴールを取り違えてしまっていたため、ほとんど成果を出せませんでした。今後の課題ではこういったことがないよう、注意していきたいです。
Padrino + mongoDB + jQuery MobileでWebアプリケーション作成
今月は、Padrino + mongoDB + jQuery MobileでWebアプリケーションを作成する、ということを、23~25の3日間クリスマスハッカソンに参加して実装を行っていました。
作成したもの
ハッカソンで作成したものは、ポストを指定日数後にtwitterに投稿する、というタイムカプセルのようなものです。
まとめ
今回のWebアプリケーション作成について、PadrinoとMongoDB、jQuery Mobileを使用して作成するという内容ですが、これ以外にも、様々なライブラリを使用しました。以下に使用したライブラリ(依存関係を除く)を示します。
- Padrino: Webアプリケーションフレームワーク
- Mongoid: データマッパー
- yajl: JSONのエンコード・デコード
- twitter: Twitter APIラッパー
- oauth: OAuthのruby実装
- clockwork: バッチ処理(ツイートのポスト)
- rspec: ユニットテストライブラリ
- rr: モックライブラリ
このように様々なライブラリを使用した開発は今までほとんど行ったことがなかったため、新鮮で楽しく開発を行うことが出来ました。また、認証やAPIのラッピング、JSONのエンコード等、面倒な処理や実装をライブラリに任せることで速く開発を進めることが出来ました。しかし、ライブラリの使用方法の調査に手間取ってしまい、ハッカソン中ではバックエンドの部分しか実装することが出来ず、フロントエンドに全く手を付けることが出来ませんでした。
オブジェクト指向のこころ読書会
10月頃の話ではありますが、オブジェクト指向のこころの読書会を行っていました。
方向としては、内容を読んでそれをまとめ、それを発表するという形で進めていきました。また、目的としてオブジェクト指向の理解がメインであったため、デザインパターンの章に関しては飛ばし、オブジェクト指向とデザインパターンの概要と適用例、使用するデザインパターンの洗い出しの方法の章についてを読み進めていきました。
各章の簡単なまとめ
1章
- この章で説明していること
- 構造化プログラミングにおける機能分解とその問題点
- 凝集度と結合度
- 要求は常に変化する
- オブジェクト指向による機能分解の問題解決
2章
- この章で説明していること
- UML
- クラス図
- 相互作用図
3章
- この章で説明していること
- CAD/CAMを例にした問題
- 単純にオブジェクト指向で考えた場合
4章
- この章で説明していること
- 著者の最初の解答
- この解答の問題点
5章
- この章で説明していること
- デザインパターンの起源
- 建築学におけるデザインパターンのソフトウェア設計への転用
- デザインパターンを利用する理由
8章
- この章で説明していること
- それぞれの概念の従来の考え方と新しい考え方
- オブジェクトの考え方
- カプセル化の考え方
- カプセル化による再利用性の向上
- 共通性/可変性分析
- アジャイル開発との共通点
- それぞれの概念の従来の考え方と新しい考え方
12章
- この章で説明していること
- 作者はAlexander教に入信しました
13章
- この章で説明していること
- パターンを用いた設計の実演
- 基本的なオブジェクト指向での考え方との比較
14章
- この章で説明していること
- 開放/閉鎖原則
- 依存性の逆転原則
- リスコフの置換原則
- 単一責任原則
- 抽象クラスとインターフェースの違い
15章
・この章で説明していること
・共通性/可変性分析
まとめ
今回の読書会でオブジェクト指向について、様々な意味や考え方、またオブジェクト指向を適用することによる利点を学ぶことが出来ました。しかし、まだオブジェクト指向を意識したプログラミングを行えているとは言えず、1つのクラスが複数の役割を持ってしまっていたり、クラスごとの役割分担をうまく行えていないので、こういった点を早く改善できるよう勉強していきたいです。
vim勉強会&タイピング練習
11月は、CUIでの作業効率の向上をはかるべく、vimの勉強とタイピングの練習を行っていました。
vim
vimに関しては、今まで:q, :q!, :wq、a、A程度しか使用しておらず、コピペもクリップボード経由でしか行っていませんでした。なので、ひそれを改善すべく、vimの勉強をして、それをまとめて社内で勉強会を開く、ということをやっていました。
スライド
学習が間に合わ無かったため、内容はコマンドについてのみとなっています。
まとめ
vimのコマンドは非常に多く、すべてを覚えて使いこなすことは非常に難しいと感じましたが、それでも大分作業効率が向上しました。また、プラグインやテキストオブジェクト等、おもしろそうな機能もまだあるので、いろいろ調べてみたいと思います。
タイピング
タイピングの練習は1日当たり長くて2時間程度、タイプウェル英単語や美佳のタイプトレーナ等を用いて英語のタイピング練習を行っていました。
11月頭の段階では、タッチタイピングが出来ず、見ながらタイピングをして約1.4Key/sでした。

12/4日現在ではミスタイプは多いものの、何とかタッチタイピングが出来るようになり、約2.4Key/sになりました。

タイプウェル英単語による測定結果(12/1測定)は以下のようになります。

まとめ
目標としては、5key/sを目標としていましたが、それを大きく下回る結果となってしまいました。しかし、今までがひどかったのもありますが、アウトプットが速くなったと自覚できる程度には速くなったので、一定の効果はあったように感じます。タイピングに関しては、今後も時間が出来次第練習していく予定です。
twitterクローン制作-リベンジ
今月は、7月に作成したtwitterクローンのリベンジを行っていました。
目標としては、以下のような感じです。
- 未実装の機能をすべて実装する
- テーブルに外部キーを張る
- クエリの実行結果を取り、最適化を行う
- テストを書く
- コードのリファクタリングを行う
うち、成果は以下の通り
- 未実装の機能をすべて実装する
- クエリの最適化
- 外部キーの設定
未実装の機能
未実装の機能は、以下の4つありました。
- 投稿へのパーマリンク
- フレンドTL
- ユーザー検索
- フォロー、アンフォロー
これらの未実装だった機能を実装をしました。
クエリの最適化
クエリの最適化は、クローン内で投げているクエリをすべてexplainで実行計画をとり、削れそうなところやjoinで結合できそうなクエリをまとめる、といったことを行いました。この結果、一部を除いて検索時のインデックスが有効になるようにすることが出来ました。以下にその結果を示します。
public timeline
クエリ
select * from willow left join user on (willow.user_id = user.id) where willow.delete_flag = ? and user.delete_flag = ? order by willow.post_time desc limit 0, 5
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE user ALL PRIMARY NULL NULL NULL 2 Usingwhere;Usingtemporary;Usingfilesort 1 SIMPLE willow ALL user_id_index NULL NULL NULL 4 Usingwhere 対策
- delete_flagについて、インデックスを追加
- 結果
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE willow ref user_id_index,delete_flag_index delete_flag_index 2 const 2 Usingwhere;Usingtemporary;Usingfilesort 1 SIMPLE user ALL PRIMARY NULL NULL NULL 2 Usingwhere
login
クエリ
select * from user where user.user_name = ? and user.password = ? and user.delete_flag = ?
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE user const user_name,user_index user_name 51 const 1 select * from user where user.user_name = ? and user.delete_flag = ?
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE user const user_name,user_index user_name 51 const 1 対策
- ログイン処理の返値をboolからUserクラスのインスタンスに変更し、クエリを減らす
- 結果
- select * from user where user.user_name = ? and user.delete_flag = ?を削除
home
クエリ
select * from follow left join willow on (follow.follow_user_id = willow.user_id) left join user on (follow.follow_user_id = user.id) where follow.user_id = ? and follow.delete_flag = ? order by willow.post_time desc limit 0, 6
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE follow ref user_id_index user_id_index 6 const,const 1 Using where; Using temporary; Using filesort 1 SIMPLE willow ref user_id_index user_id_index 4 willow_poem_test.follow.follow_user_id 2 1 SIMPLE user eq_ref PRIMARY PRIMARY 4 willow_poem_test.follow.follow_user_id 1 対策
- 特になし
perm
クエリ
select * from willow where willow.id = ? and willow.delete_flag = ?
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE willow const PRIMARY,delete_flag_index PRIMARY 4 const 1 select * from user where user.id = ? and user.delete_flag = ?
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE user const PRIMARY PRIMARY 4 const 1 - 対策
- ユーザーの検索のクエリを川柳の検索時にjoinで検索するようにする
- 結果
- クエリ
select * from willow left join user on (willow.user_id = user.id) where willow.id = ? and willow.delete_flag = ?
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE willow const PRIMARY,delete_flag_index PRIMARY 4 const 1 1 SIMPLE user const PRIMARY PRIMARY 4 const 1
- クエリ
user
クエリ
select * from user where user.user_name = ? and user.delete_flag = ?
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE user const user_name,user_index user_name 51 const 1 select * from willow where willow.user_id = ? and willow.delete_flag = ? order by willow.post_time desc limit 0, 6
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE willow index_merge user_id_index,delete_flag_index delete_flag_index,user_id_index 2,6 NULL 1 Using intersect(delete_flag_index,user_id_index); Using where; Using filesort 対策
- 特になし
follow:show
クエリ
select * from user where user.user_name = ? and user.delete_flag = ?
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE user const user_name,user_index user_name 51 const 1 select * from follow left join user on (follow.follow_user_id = user.id) where follow.user_id = ? and follow.follow_user_id = ? and follow.delete_flag = ?
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE follow ref user_id_index,follow_user_id user_id_index 6 const,const 1 Using where 1 SIMPLE user const PRIMARY PRIMARY 4 const 1 対策
- 特になし
follow:follow(new)
クエリ
select * from user where user.user_name = ? and user.delete_flag = ?
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE user const user_name,user_index user_name 51 const 1 select * from follow left join user on (follow.follow_user_id = user.id) where follow.user_id = ? and follow.follow_user_id = ?
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE follow ref user_id_index,follow_user_id user_id_index 4 const 1 Using where 1 SIMPLE user const PRIMARY PRIMARY 4 const 1 insert into follow values(?, ?, ?, ?)
対策
- 特になし
follow:follow(refollow)
- クエリ
select * from user where user.user_name = ? and user.delete_flag = ? select * from follow left join user on (follow.follow_user_id = user.id) where follow.user_id = ? and follow.follow_user_id = ? update follow set delete_flag = ? where id = ? and user_id = ? and follow_user_id = ?
- explain
- 同上
- 対策
- 特になし
- クエリ
follow:unfollow
- クエリ
select * from user where user.user_name = ? and user.delete_flag = ? select * from follow left join user on (follow.follow_user_id = user.id) where follow.user_id = ? and follow.follow_user_id = ? update follow set delete_flag = ? where id = ? and user_id = ? and follow_user_id = ?
- explain
- 同上
- 対策
- 特になし
- クエリ
search
クエリ
select * from user where user.delete_flag = ? and user.user_name like ?
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE user range user_name,user_index user_name 51 NULL 1 Using where 対策
- 特になし
一番最初のクエリで、userの部分がALLになっていますが、これはレコードの本数が少ないことによるもののようで、レコードを増やすことによってrefに変化します。
外部キーの設定
今回のtwitterクローンの場合、川柳やフォローの情報はユーザーにひも付いているので、ユーザーのIDを外部キーとして以下のように張りました。
alter table willow add foreign key(user_id) references user(id); alter table follow add foreign key(user_id) references user(id); alter table follow add foreign key(followuser_id) references user(id);
しかし、外部キーの意味として正しく設定できたかどうか、今回の場合だとはっきりと確認できなかったため、達成の度合いとしては微妙なところです。
テスト
今回、上記の項目に気を取られすぎて、テストについては全く書けませんでした。まだ「テストを書く」という習慣が身についておらず、テストよりも実装を優先してしまう傾向があったため、テストを書く習慣をつけるために、今後の課題ではTDDを意識して実装を行いたいと思います。
リファクタリング
コードのリファクタリングについても、インデントをスペース4つから2つに直したり、不要なreturnキーワードを削除する程度しかできず、殆ど何もしていないに等しい状態になってしまいました。これについても、実装を優先してしまって、1週間に1度、といった時間単位ではなく、この項目が終わったら、という項目単位でレビューを行おうとしてしまい、結局実装が間に合わずにレビューが出来なかった事が原因でした。
まとめ
今回の課題に関してはいつも以上に達成率が低かったように思います。
原因としては、機能実装の方に気を取られすぎたことが1番だと思います。レビューを行う間隔を週単位で行っていれば、
リファクタリングとテストも行えたように思います。
このあたりは、次の課題で改善していきたいです。
OOP練習-まとめ
またいきなりまとめになってしまいましたが、今月はruby+rspecでOOPを意識しつつ、
テストと一緒に書く練習をしていました。そのコードについてのレビューで出た点をまとめます。
コードについては、githubにありますので、そちらをご覧ください。
1問目 Baseball Simulation
- invalid_operation_error.rb
- Exceptionは継承せず、StandardErrorを継承する
師匠のブログに詳しく書いてありますが、深刻なものである場合以外は、Exceptionではなく、StandardErrorを継承するべきのようです。
- Exceptionは継承せず、StandardErrorを継承する
- game.rb
- 長い
- accessorの定義は必要最低限にとどめる
- startedのようなものは、習慣としてstart?のように?付きのメソッドとして定義する
- team1_scorem, team2_scoreのように名前に数字が出てきたら設計を疑う
- お題にそった用語を使用する(team1→bat_first)
- Gameクラス内でアクションを処理するのではなく、各イニングをオブジェクトにして、そっちで処理する
- データに不備がある場合は例外を投げる
- チーム名を決めるのはGameクラスではなくてユーザー
- “HIT”等、定数は文字列ではなくシンボル(:hit等、:で始まる識別子)を使う
- 同一インスタンスであるかどうかは==ではなくequal?を使う
- runner.rb, team.rb
- 階層構造がおかしい
走者がチームの(実物の)看板を背負うべきではない
- 階層構造がおかしい
2問目 自動販売機
- vending.rb
- 名前が変
vending machine(自動販売機)ではなく、vending(ものを売る)を使うのはおかしい
- 名前が変
- vending_machine.rb
- お金の種類や保持している枚数は、VendingMachine内に持つべきではない
- クラスインスタンス等、オブジェクトが1つであるものに対する処理(ソート等)は、そのオブジェクトに対してメソッドを定義する このあたりも含め、お金の種類と枚数はMoneyStocker等を定義してそこに保持するようにするべき
- 初期の硬貨・紙幣や、飲み物は最初から(インスタンス作成時)入っているのではなく、利用者(テストクラス等)が持つべき
- 入れた硬貨をすぐにmoney_stackに足すのではなく、一度プールすべき
現状だと10円玉10枚入れておつりを出すと、100円玉が出てきてしまうため、両替機になってしまう - 不等号の向きを揃える
- 購入時は、例外ではなくfalseを返す
- 同じ処理が出てきた場合は、切り出して1つにまとめる
- 配列やハッシュをすべて舐めるような処理は、injectを使う
- can_buy→available
- Drink.rb
- 在庫はDrinkクラスに持つべき
今回の場合は、各飲み物に個性がある訳ではないため。また、”あたたかい”や”つめたい”、自動販売機内での位置(何段目の何個目等)
も持てるようにしておくとさらによい
- 在庫はDrinkクラスに持つべき
という感じでした。
今までコードを書いているときは、機能が似通った処理同士をクラスにまとめる、という程度の認識しかなかったので、いざOOPを意識
すると、かなり難しいことを改めて実感しました。OOPでコードが書けるようにはまだ先になりそうですが、出来る限り業務でも意識していきたいです。
bashコマンドまとめ
開発環境にmac、linuxを使用することが多くなってきたため、ターミナルでの作業が増えてきました。 ただ、ショートカットキーがいつまでたっても覚えられないので、備忘録的な意味も込めて、表にまとめてみます。
- カーソル操作
| コマンド | 名前 | 説明 |
|---|---|---|
| Ctrl+b | backward-char | 1字戻る |
| Ctrl+f | forward-char | 1字進む |
| Esc,b | backward-word | 1単語戻る |
| Esc,f | forward-word | 1単語進む |
| Ctrl+a | beginning-of-line | 行頭に戻る |
| Ctrl+e | end-fo-line | 行末に移動する |
- 削除
| コマンド | 名前 | 説明 |
|---|---|---|
| Ctrl+d | delete-char | 1字削除 |
| Ctrl+h | backward-delete-char | 1字削除し、1字戻る |
| Esc,Ctrl+h | backward-kill-word | 1単語戻り、単語を削除する |
| Ctrl+k | kill-line | カーソル位置以降から行末まで削除 |
| Esc,d | kill-word | 1単語削除する |
| Ctrl+w | unix-word-rebout | 1単語削除(空白区切り) |
| Ctrl+u | unix-line-discard | カーソル位置以前から行頭まで削除 |
- 履歴
| コマンド | 名前 | 説明 |
|---|---|---|
| Esc,< | beginning-of-history | 履歴の一番最初を表示する |
| Esc,> | end-of-history | 履歴の一番最後を表示する |
| Ctrl+n | next-history | 次の履歴を表示 |
| Ctrl+p | previous-history | 前の履歴を表示 |
| Ctrl+r | reverse-search-history | 前の履歴からコマンドをインクリメントサーチする |
- 入力
| コマンド | 名前 | 説明 |
|---|---|---|
| Ctrl+m | accept-line | Enter |
| Esc,c | capitalize-word | 単語の頭を大文字にする |
| Esc,l | downcase-word | 1単語すべてを小文字にする |
| Ctrl+i or tab | complete | 単語を補間する |
| Ctrl+y | yank | ヤンクにあるバッファの内容を貼付ける |
| Esc,y | yank-pop | ヤンクの一番上にある内容を取り出す |
| Ctrl+_ | undo | 元に戻す |
- その他
| コマンド | 名前 | 説明 |
|---|---|---|
| Ctrl+g | abort | 中断 |
| Ctrl+],何か1文字 | cahracter-search | カーソル位置以降にある指定文字を検索する |
| Esc,Ctrl+],何か1文字 | backward-cahracter-search | カーソル位置以前にある指定文字を検索する |
| Ctrl+l | clear-screen | 画面をクリアする |
| Crtrl+x,Ctrl+v | display-shell-version | シェルのバージョンを表示 |
- アルファベット順
| コマンド | 名前 | 説明 | |
|---|---|---|---|
| Ctrl+a | beginning-of-line | 行頭に戻る | |
| Ctrl+b | backward-char | 1字戻る | |
| Ctrl+c | なし | ||
| Ctrl+d | delete-char | 1字削除 | |
| Ctrl+e | end-fo-line | 行末に移動する | |
| Ctrl+f | forward-char | 1字進む | |
| Ctrl+g | abort | 中断 | |
| Ctrl+h | backward-delete-char | 1字削除し、1字戻る | |
| Ctrl+i | complete | 単語を補間する | |
| Ctrl+j | accept-line | Enter | |
| Ctrl+k | kill-line | カーソル位置以降から行末まで削除 | |
| Ctrl+l | clear-screen | 画面をクリアする | |
| Ctrl+m | accept-line | Enter | |
| Ctrl+n | next-history | 次の履歴を表示 | |
| Ctrl+o | operate-and-get-next | 現在のコマンドを実行後、次のコマンドを履歴から取ってくる | |
| Ctrl+p | previous-history | 前の履歴を表示 | |
| Ctrl+q | quoted-insert | 次に入力されたキーを協定的に文字として入力する? | |
| Ctrl+r | reverse-search-history | 前の履歴からコマンドをインクリメントサーチする | |
| Ctrl+s | forward-search-history | 後の履歴からコマンドをインクリメントサーチする? | |
| Ctrl+t | transpose-chars | カーソルの位置の文字と、その1つ前の文字を入れ替える | |
| Ctrl+u | unix-line-discard | カーソル位置以前から行頭まで削除 | |
| Ctrl+x,Ctrl+v | display-shell-version | シェルのバージョンを表示 | |
| Ctrl+w | unix-word-rebout | 1単語削除(空白区切り) | |
| Ctrl+x、何か | キーボードマクロ系操作 | ||
| Ctrl+y | yank | ヤンクにあるバッファの内容を貼付ける | |
| Ctrl+z | なし |
Ctrl+qや、Ctrl+s、Ctrl+x系はなぜか反応しなかったため、正確な内容はわかりませんが、動いたものに関してはこのような 感じになりました。