Gitで'fatal: object {hash} is corrupted'になった際の復旧手順

Macがフリーズする現象がたまにあって、そうなるとgitの状態が壊れることがある。
その時の修復手順を記録として残しておく。

現象

git操作を行おうとするとfatal: object <hash> is corrupted が出る。

/home/kanno/repository% git status
fatal: object 43a1c7ca8e29251954a806714bd1db24ddcf1905 is corrupted

復旧手順

念のためバックアップを取っておく

/home/kanno/repository% cp -rp .git git-old

表示されたhashのオブジェクトファイルを消す

/home/kanno/repository% rm .git/objects/04/313fa358eabb459b0c9ea1f48709f1cbb88118

git操作でfatal: bad object HEADが出るまでオブジェクトファイルを消すのを繰り返す

/home/kanno/repository% git status
fatal: bad object HEAD

該当ブランチのrefs/headsの中身を見る
(.git/logs/refs/heads/20432-hoge-branchのところは見たいブランチを指定)

/home/kanno/repository% tail -n 2 .git/logs/refs/heads/20432-hoge-branch
dcba72adc7078cfcced387a69246f0b29ea589b6 74e8aa0c09550804b40024ab33a98321627e1b4a kannokanno <...> 1429095527 +0900   commit: [#20432] WIP
74e8aa0c09550804b40024ab33a98321627e1b4a 43a1c7ca8e29251954a806714bd1db24ddcf1905 kannokanno <...> 1429096095 +0900   commit: [#20432] WIP

2行目の左のhash値を使ってHEADを戻す

/home/kanno/repository% git update-ref HEAD 74e8aa0c09550804b40024ab33a98321627e1b4a

git操作が出来るようになっているのでcommitしなおしておく

参考: how to fix GIT error: object file is empty?

MySQLでSQLの実行時間のみを調べる

SQL設計やチューニングで実行時間を計測する際に以下のような状況がよく出てくる。

  • SQLの実行時間が知りたい
  • 実行結果はいらない

方法1 mysql -vvvを使う

/home/kanno% cat sample.sql | mysql -vvv hoge_db | tail -n 3
1 row in set (3.62 sec)

Bye
  • 対象のSQLを書いたsample.sql(ファイル名は何でも)を用意
    • 単純なSQLならecho "select ..." | mysql ...で十分
  • mysqlコマンドの標準入力に渡す
    • -vvvオプションで実行時間を出すようにする
  • tailで実行時間以降の行だけ表示させる
    • Byeとかも邪魔ならheadで更に絞る
    • cat sample.sql | mysql -vvv hoge_db | tail -n 3 | head -n 1

方法2 timeコマンドを使う

/home/kanno% time (cat sample.sql | mysql hoge_db > /dev/null)
real    0m12.526s
user    0m0.079s
sys     0m0.009s

プログラミングにおける設計の難しさについて考える

前提

この記事における設計は主に以下の4点をイメージして書いています。
(具体的にどうこう、という話は出てきません)

  • REST設計
  • レイヤー設計
    • MVCとかDDDにおけるレイヤーみたいなやつ
  • クラス/インターフェース設計
    • どういう処理/データを持たせるのが適切かとか
  • コード設計
    • for文で書くかeach使うかとかそういう細かい話

目的

  • 設計に悩んだり微妙な設計をすることがあって改善したい
  • 設計に関する本を読んでいる中で、私にとってなぜ設計が難しいのか見えてきたので勢いで書き出す
  • あくまで現時点での私が思う難しさなので、1年後は別の原因で難しさを感じてるかもしれない

設計の何が難しいか

以下の要素により明確な正解がないからではないかと感じています。

  • 選択肢がいくつもある
  • 選択肢が浮かばない
  • 判断基準がいくつもある
  • 捨てる決断が必要なことがある
  • 技術的負債を恐れる

難しい要因1: 選択肢がいくつもある

プログラミング覚え立ての頃は数少ない方法でコードを書きます。

  • (Javaから入ったので)繰り返しといえばfor文を回すだけ
    • whileは無限ループ怖いので理由がない限り書かない
  • 再代入バリバリ
  • メソッド/クラスを分けない
  • クラスの責務を分けない
  • 変数名/メソッド名/クラス名が適当

他人が見れば汚いコードですが、少なくとも書いている本人は設計で迷うことは少なかったはずです。
設計していなかったので。
迷うのはアルゴリズムというか手続き的なところで、単純に「どう書けば仕様を満たすのか」という点でした。

それが経験や学習を経て、色々な方法を学んでいきます。

  • map/filter/reduceなどを覚える
  • 変数は不変を保つ。再代入とか辞めてほしい
    • ifが文ではなく式である言語に喜びを覚える
  • 「このクラス/メソッドの責務って何だ」を考え始める
    • 名前を考えるのに時間を費やす

携わる仕事は大概ありがちなCRUDなので難しいコードを書く事は少ないです。
ただ昔と違い色々な手法を知ってしまったため設計に時間がかかるようになっています。
ちなみにコード寄りの例を出しましたが、コードに限らず設計全般です。

たぶん中途半端に色々知っている状態のため判断に迷っているのだと思います。

難しい要因2: 選択肢が浮かばない

ざくっとした言い方ですが。

  • 経験として何か良くないのは分かる
    • いわゆるコードの臭いとか
    • コードじゃなくても、何となくこの設計イケてないよなあ感
  • けどどうしたら良いかが分からない

これは単純に経験に知識が追いついていないのでしょうね。

難しい要因3: 判断基準がいくつもある

※以下に出している例は例であって、今の現場がそうだということではありません

  • 現メンバーのスキル
    • OOPを知らない/好まないチームでOOPで書くべきか
      • 教える/議論するコストもあるし
  • 今後保守するかもしれない人のスキル
    • xx言語が向いているけど、書ける人が少ないのにxx言語で社内ツール作るべきか
  • 既存コード(アーキテクチャ)との調和
    • xxの方が良い設計なんだけど、そうすると既存の他の部分と統一性がなくなるとか
    • 統一性を重視してそっちに合わせるか、ゼロベースでの最善を取って良い設計にするか
  • 予算
    • カスタマイズしやすいようにオンプレがいいけど予算がとか
  • 人的リソース
    • 単純に人が足りない
  • 時間リソース
    • 単純に時間が足りない
  • タスクの優先度(重要度)
    • 急ぎでやるべきなものは「とりあえず」でやりがち
      • 「あとでやる」はまずやらない
      • やらなくて困らないならそもそも不要だったのではという考えもある
  • 難易度
    • 簡単なものほど飛びつきやすい

難しい要因4: 捨てる決断が必要

上記判断基準と併せて。
多くの場合において捨てる決断が求められます。
上記と重複する部分がありますが、捨てる理由としては主に以下の3つが浮かんでいます。

  • 人が足りない
    • 増やせばいいってものではないですが
  • 時間が足りない
    • さっさとリリースしたいねんという圧力
    • 緊急時の対応
  • 知識/経験が足りない
    • xxがいい気がするけどやったことないから怖いね
      • もしくは時間がかかるね
    • xxという簡単な解決策(手法、ソフトウェア、サービスなど)があるのに知らない

難しい要因5: 技術的負債を恐れる

苦悩の末に決断をしてそれがその時の最適解だったとしても、
時が経ったり新しく入ってきた人からするとそれは技術的負債になり得ます。
自分が関わった部分を指して「これはひどい」とか言われたくなくて、
見えない未来に思いを巡らせてあれこれ悩むのかもしれません。

プロとしてのありかた

こういった難しい要素に対して、私のプロ像はどう振る舞うだろうかというのを考えてみます。

色々なケースで最適解を出す

正解はない(と思う)けど、最適解は必ずある(と思う)。
その場その場で、色々なコストを考慮して最適解を出せる人がプロ。
幅広い知識と多くの経験と理路整然とした思考が必要。

責任を持つ

理想を語るのは簡単です。
理想を振りかざして既存のコードをけなすのは簡単ですし、
自分が高尚に感じるし、責任から逃れられているような感覚になります。
(参画した時点で自分もコードの責任者だと思う)

ですがきっとプロはグチグチ言わない。その方がモテるから。
プロはアウトプットで語る。
変えられるなら変えていくだろうし、
それが出来ないなら「これが今出来る最高の状態」と決断に誇りを持つ。

設計の難しさにどう立ち向かうか

  • チームとしての立ち向かい方
  • 個人としての立ち向かい方

チームとしての立ち向かい方

  • レビューを挟む
    • 自分が見えていない観点で指摘してくれるかもしれない
    • 人に説明することで抜け漏れに気付きやすいかも
  • 議論は前提の認識を明確にしておく
    • お互いが見ているもの、目指しているものが違うと議論もすれ違う
    • 「こっちの方が開発が早い」と「こっちの方が保守性が高い」みたいなことを言い合っても平行線
    • 「急ぎでやる必要あるの?」「一度しか使わない機能で保守性とか必要?」みたいなところから認識合わせるとか

難しい要因のほとんどはチーム内レビューとか相談で解決する気がします。
そのためにチームでもありますし。

ですが、出来ることなら自分一人でも最適解を出せるようにはなりたい。
「最適解の判断に迷う」という相談ではなくて、
「こういう理由でこれが最適解だと判断したのだけどどう思う?」という相談にしたい。

個人としての立ち向かい方

  • 知識を増やす
    • 悩まないという点では知識は少ない方がいいかもしれない
    • でも最適解を出すには知識は必要
  • 経験を増やす
    • 「知っている」と「やったことがある」では全然違う
  • 常に考える
    • 本やネットの知識を鵜呑みにして受け売り野郎にならない
    • 手法やサービスなどについて何がいいのか、何故いいのかを自分の言葉で説明できるようにする

感想

何が難しいと感じているかは分かった気がして書き出してみたけど、
個人については結局勉強しろという当たり前かつ抽象的な結論しか出ていなかった。

「入門Puppet」を読んだ

自社ではPuppetを使っています。
私が直接いじることはほとんどないけど、
基礎の基礎ぐらいは知っておきたいなということで「入門Puppet」を読みました。

事前知識

  • Chef-soloをほんの少しだけ使ったことがある
  • Ansibleをほんの少しだけ使ったことがある
  • Puppetの存在は知っていたけど使ったことはない
    • でもどういうものか概要は知っている
  • Vagrantを使ったことがある
    • 書籍ではVagrantを使って説明が進む
  • どこかの勉強会かネットでPuppetはちょっと面倒みたいなことを聞いた気がする
    • 外部DSLなので学習コストがーみたいな話だったかな

読み方

  • 1回目: 全体をさらっと一読
  • 2回目: 実際にコマンドを実行しながら読んだ
    • 15章以降は一身上の都合により試してはいない
  • 3回目: この記事のために流し読みで復習

最後に1章ずつserverspecやcapistranoとの連携があるけど、今知りたいことではないので流し読み。

知ったこと

全体的なこと

  • 「システムのあるべき状態」を記述したmanifestを用いる
    • 他の構成管理でも同じことなのだろうけど、状態っていう言葉がなんかしっくりきた
    • 今までは「手順の自動化」っていう感覚だった
  • あるべき状態を管理と捉えると、Puppetの宣言的なDSLは読みやすい気がした
    • もっと複雑化してくると違うのかもしれない
  • 基本的な記述でシンプルに使う分には簡単
    • 最初に抱いていた面倒なイメージは消えた
  • むしろ簡単で良いではないかという気分
  • 基本的な機能はChef/Ansibleとさすがに違いなさそう

具体的なこと

  • 一つの記述でyumやaptとかを自動的に判別して実行してくれる
    • ChefよりAnsibleが好きだけど、この方法が分からなくてうーんってなったのを思い出す
  • あるべき状態を表すresource
    • 具体的な種類をresource typeと呼ぶ
    • resource typeは独自に追加定義できる( defined type )
  • resourceをまとめるclass
  • 上記のmanifestファイルをまとめるmodule
  • moduleの組み合わせとしてのrole
    • サーバー毎の役割
  • resource typeの依存関係を表す書き方
    • 事前にこれが必要だよ => require
    • このあとこれをしてね => notify
    • あれが変わったらこれしてね => subscribe
  • classの場合は依存関係を->~>で表す
  • moduleでは命名やパスに色々ルールがある
  • 変数や条件分岐も使える

感想

説明のバランスが自分にはとても良かった。
動作環境もVagrantを使って「このbox使います」と簡単だった。

段階的に仕様を学んで行く構成も非常に分かりやすかった。

題材とか説明を飛ばしたりとか推奨しない項目について、きちんと理由が書かれていて納得感があった。
これは読みやすさの上で結構重要だったように思う。

各章の最後に「まとめ」として、要約が載っているのがとても良かった。
ハウツー本とかでは良く見る手法な気がするけど、技術本ではあまり見ないかも?

あくまで初歩ということで、扱う項目も最小限になっているっぽい。

  • agent/masterモードは扱わない
  • node情報を管理しない
  • 標準的なディレクトリ構成を用いない

自分は初歩を知りたかったので好都合でした。

総じて言うとすごい説明上手だなーと感じました。

Re: previmでプレビューのタイミングがよりリアルタイムになったりcssを定義できるようにした

前回の更新 で問題がいくつか報告されました。

それを受けて考え直し、以下のように仕様を変えました。

デフォルトではリアルタイムにプレビューしない

保存時のみプレビューを更新します。
これまでと同じです。
挿入モードを抜けてもプレビューは更新されません。

リアルタイムにする場合はg:previm_enable_realtimeを1にする

前回の記事では以下のように説明しました。

  • g:previm_enable_realtime はデフォルトで1
  • リアルタイムプレビューを無効にしたければ明示的に0を設定すること

今回の修正で以下のようになりました。

  • g:previm_enable_realtime はデフォルトで0
  • リアルタイムプレビューを有効にしたければ明示的に1を設定すること

おまけ

あと前回の修正ではプラグイン側でupdatetimeを変えていました。
リアルタイムを有効にした場合、updatetimeに依存して更新されるためです。
updatetimeはVimのデフォルトで4000(4秒)です。
updatetimeを小さく設定しているユーザーなら問題ないのですが、今回の用途ではちょっと遅いなあと思っていました。

ただ「ユーザー側でupdatetime変えればいいだけか」と考え、書き換えるのを辞めました。

例えばこんな設定でリアルタイムプレビューの間隔を早められる(はず)。
関数に切り出してtry-catchしてってのがお行儀良いのだろうか。
その辺りは良く分かっていない。

" .vimrcに書く。この例では.markdownの場合のみ
augroup Markdown
  autocmd!
  autocmd BufEnter *.markdown let s:updatetime_origin = &updatetime | let &updatetime = 100
  autocmd BufLeave *.markdown let &updatetime = get(s:, 'updatetime_origin', &updatetime)
augroup END