2014年7月31日木曜日

動的型付けを「複数の型を持てる」と考える

PHPやRubyなど、動的型付けをもつ言語を僕も普段から使っています。ただ、動的型付けに対しても、僕は明確に変数の型を意識します。

そもそも、動的型付けに対して、「型を意識しなくてよくなる」と考えるのは間違っていると思っています。そうではなく、「一つの変数が複数の型を持てる」と考えるべきかと。

例えばPHPだと、ある関数の返り値は場合によって整数かもしれないし文字列かもしれません。失敗時にはfalseだったりします。その関数の返り値を変数に代入すると、この変数は整数かもしれないし文字列かもしれないし真偽値であるかもしれません。しかしこの特徴によって、ソースコード記述の柔軟性を上げることが出来るのですね。

ただ、やはり変数を取り扱う上で、変数の型を意識しないと思わぬバグを産んだりします。だから、「型を意識しなくてよくなる」のではなく、「一つの変数が複数の型を持てる」と考えるべきなのです。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月30日水曜日

開発における "あと一歩" の追求

例えば、UIの配置やプログラミングのパターンを、あと1つだけ多く試してみるとか。手間としては、それほど多くなるわけではないでしょうが、これをやるかやらないかの違いは大きいと思います。

時間との兼ね合いもありますけれども、特にソフトウェアにおいてはちょっとした違いが積み重って全体の印象を決めています。むしろ地味な違いほど効たりします。

だから、ソフトウェア開発において、"あと一歩" の追求は時間に切羽詰まっていない限りは重視したいと思うのです。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月29日火曜日

UI設計では素朴な感覚を大切にする

ソフトウェア開発におけるUI設計は、経験や理論も影響してくるものではありますが、それより大切だと思っていることは「素朴な感覚」です。

まっさらな気持ちで、初めてそのソフトウェアを触った人のような気持ちになって操作し、何を感じるか。そこで「使いやすい」と感じられるか。何か足りないと思うことはあるか。多すぎると思うことはあるか。変えたほうが良いと思うことがあるか。などなど・・・。そこでかすかに感じるわずかな違和感に気づくことが何よりも重要です。

確かにプログラミングには経験や理論もファクターとして大いに絡んできます。しかし、そのプログラミングを通して作り上げ、最終的にユーザとの接点になるUIにおいては、何も知らない人間の感覚になる必要があります。

こういった感覚の切り替えもソフトウェア開発の面白いところですね。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月25日金曜日

git diffって多用するよね

git diffは非常によく使うコマンドの1つで、僕の仕事のクオリティを支えてくれているツールでもあります。また、difftoolにvimdiffを用いたgit difftoolも同じくらいよく使います。

僕はかなりこまめにgit diffを使います。プログラミングをしていると、ちょっと書いたらgit diffで差分を見て、動作確認し、またちょっと書く、みたいな感じです。差分を確認せずに一気に書くことはほとんどないです。

あとコミット前にはインデックスとHEADの差分をgit diffとgit difftoolの両方で確認します。ここで原則として差分については全て余すところなく確認します。

あと、ローカルブランチのコミットをgit merge --squashでまとめて提出用ブランチにした際も、提出用ブランチの直前との差分を確認しますが、この際はざっと目を通す感じですね。

こんな感じです。実に利用シーンは多いです。ちなみに差分アルゴリズムはhistogramがおすすめです。difftoolにvimdiffを用いる場合に、差分作成アルゴリズムを変更する方法については過去の記事を参照。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月24日木曜日

言われたとおりにやるエンジニアは二流

依頼者から言われた通りのものを作る。と言えば一見問題ないように感じますが、ただ言われたとおりにやるだけでは、それはソフトウェア開発エンジニアとして二流だと思ってます。

仕事の依頼というものは、それ自体が依頼者の本当に欲しい物を示しているのではありません。依頼者が、欲しい物を伝えようとして表現した結果が仕事の依頼なのです。そこには依頼者が表現する際にどうしてもズレや抜け漏れが生じていると考えなければいけません。

だから、依頼を受けたエンジニアとしては、依頼通りのものを作る事を目指すのではなく、依頼を通じて依頼者が本当に欲しがっているものを推理し、依頼をチューンナップしてあげる必要があります。

上記の話は、ソフトウェア開発においてウォーターフォール型開発だと要件定義の段階で実際によく言われる話です。しかし、ウォーターフォール型開発のように、ステップが明確に分かれていない開発が多くなっています。アジャイルや、それに類似した開発手法では、要件定義・設計・実装は明確に分かれておらず、担当者も同じだったりします。僕が関わっているプロジェクトもそうですね。

そうなると、より担当者の判断が求められるようになってきます。ウォーターフォール型開発だったら、要件定義の段階で全ての仕様について依頼者の同意を得てから次のステップへ進むという方法でしょうが、アジャイルや類似した開発手法の場合そうは行きません。そもそも仕様はどんどん変更されるのが前提ですから、担当者自身が判断して実装して実際に動く状態まで作って依頼者に見せてしまえばいいし、それしかないのです。

今後ますます、言われたとおりにやるエンジニアよりも、言われたことを上手に解釈して意図を汲み取り、実装まで行って動く形にして、依頼者を満足させられるエンジニアが評価されていくでしょう。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月23日水曜日

プログラミングは "新規" と "追加・修正" で全く異なる

最近思うんですが、プログラミングっていうのは、それが「新規」つまり「そのプロジェクトに関しての過去のコードが全く存在しない状態からコーディングする」のと、「追加・修正」つまり「そのプロジェクトに関して既にコードが存在し、それに対して追加あるいは修正を加える」のとでは、全く異なったものになりますね。もう少し詳細に言うならば、「追加・修正」の中でも、たとえプロジェクトに関しての過去のコードがあったとしても、実装しようとしている機能が他の機能から比較的独立しており、かつ、そこに関する部分のコードがまだ存在しない場合、「新規」に近いとみなすことができます。

さて、「新規」の場合、ソースコードの配置(どのファイルにどういった内容をコーディングするのか)、論理構成(どんなクラス・メソッドを作成してどのような役割を分担させるか、あるいはクラス・メソッドが既に用意されているフレームワークの選定)など、自分で骨組みを考えていきます。また、細かい話で言えば、クラス・メソッド・変数などの命名規則、空白や括弧のコーディングスタイルなども自分で決めていくわけです。

一方、「追加・修正」の場合は、上記で書いたようなことは(中途半端な状態で引き継いだのでない限り)元から全て存在しています。ですから、ソースコードの配置を勝手にできません。例えば画面描画のためのソースコードを集めて置いてあるフォルダに、いきなりDB接続用のソースコードを置くなんて暴挙は言語道断です。あるいは、すでにあるクラスと同じ役割のクラスを勝手に作ったら自分でさえ混乱しかねません。変数の命名規則を無視すると他のコードとの連携でミスを誘発し、バグの温床になります。要するに、既に存在するコードの規則に従うことが原則です。

従って、同じプログラミングとはいえ、「新規」と「追加・修正」では頭を切り替えなければいけません。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月19日土曜日

書籍「パーフェクトRuby」読了

書籍「パーフェクトRuby」(Rubyサポーターズ著、技術評論社)を読み終わりました。技術書として読み応えのある一冊であったと思います。

Rubyは基本的な文法をマスターすることはもちろんですが、次に組み込みクラスとモジュールの理解が重要です。組み込みクラスとモジュールをしっかり理解しているかどうかは、Rubyを使いこなす分かれ目にもなります。ここが網羅的に分かりやすく書いてあったのは大変勉強になりました。

加えて「パーフェクトRuby」を読むまではあまり知らなかったメタプログラミング系の知識が得られたのも大きかったと思います。Rubyにおけるクラスやオブジェクトの成り立ちや、動的なオブジェクトの操作についての理解は、現場でのOJT的な勉強だけだとなかなか身に付けづらいものがあり、こういった書籍での体系化された知識に触れることが理解に大いに役立ちます。

さらに、BundlerやYARDなどのよく使われる標準外のツールの説明や、実際のアプリケーション開発をコマンドラインアプリケーションとWebアプリケーションを具体例として解説してあるのもいいポイントでしたね。Webアプリケーションの方は、RackやSinatraといった業界標準のツールにも触れていて、僕も実際仕事で使っているものですが、知識を補完することが出来ました。

それにしても技術評論社のパーフェクトシリーズは良書が多いと思います。「パーフェクトPHP」「パーフェクトJavascript」に続き「パーフェクトRuby」もリファレンス本として手元においておく一冊にしようと思います。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月18日金曜日

SQLを久々に直接書いてWeb開発者として思ったこと

久々にSQLを直接書きました。とうのは、最近はORマッパーを使うことが多くて、直接SQLを書くことがめっきりなくなっていたからです。しかし今回は既存のコードに手を加える作業をするという状況で、既存のコードがORマッパーなど使用していないコードだったものですから、SQLを直接書くことになりました。

別にDBの専門家ではないので、パフォーマンスのチューニング方法などはあまり詳しくありません。もちろん速度は考慮して書きますが、それは基本的な部分であって、高度なチューニング(例えばDBMSの種類ごとの最適化やストレージエンジンごとの違いの考慮など)はできません。

とは言うものの、そこまで高度なチューニングが求められる場面は、Webアプリケーションにおいて少ないですし、今後も少なくなっていくように思います。基本的な原則(例えば、不要なレコードは取得しない=WHERE句でなるべく絞り込む、など)に則っていればよいと思います。以前はSQLの方で最適化しなければならなかったようなパターンも、DBMS自身の進化によって高速化している例もありますし。

Web開発者としては、そもそもSQLをチューニングしなければならないようなDB構成を避けるという方向性の方がよいような気もします(既存のシステムだとそうも行きませんが、そこはDBの専門家の出番でしょう)。

ということで、Web開発者の自分としては、SQLについては今後も基本的な原則は学んでいこうと思いますが、DBMSの種類ごとの最適化やストレージエンジンごとの違いの考慮といった事項は、DBの専門家にまかせておこうと思っています。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月17日木曜日

システム構築に必要な「統一性のセンス」

エンジニアとしてITシステムの構築を生業とするにあたっては様々な能力を必要とされますが、中でも重要な能力だと思っているのが「統一性のセンス」ですね。

これは、直接ユーザの目に触れるユーザインターフェース(UI)についても言えることですし、直接ユーザの目に触れないプログラミングやデータベース構造といったものについても当てはまることです。

例えばUIについては、ボタンの配置の方向や順番や色、アイコンの形、語彙表現など様々な要素について統一性を持たせることが、使いやすさに大きく影響します。

プログラミングについても、変数名・クラス名・メソッド名などの命名規則、論理的構造のパターンなどに統一性を持たせることで、バグの低減やメンテナンス性の向上を図ることができます。

システム構築には美的センスが求められる、と言う場合、その多くは「統一性のセンス」を意味しているのです。なぜなら、統一性のあるUIやソースコードは美しいものだからです。芸術作品では「混沌のセンス」も美的センスとしてアリなのでしょうが、システム構築にはありえないですからね。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月16日水曜日

他人のソースコードを読む際には推理能力も要る

昨日、プログラミングの際には考え方と目的も記録を残せと書いたんですが、自分はそうするよう気をつけていても、実際に仕事で扱う既存のソースコードにおいて、考え方と目的をコメントや公開サイトや付属ドキュメント等に書いていてくれているのかというと、まあ残念ながら書いてくれていない場合も多いわけですよ。

そういう時は仕方ありませんから、まるで推理小説の名探偵よろしく推理するしかありません。例えば変数やメソッドの名前も人によって微妙に用法が異なったりするので、ソースコード全体の傾向から、その名前が意味する所を推し量ったりとか。静的にソースコードを解析するだけでは分からない時は、デバッグツールを使って実際の動きを見ながら、コードの意味を分析したり、わざとエラーを起こさせてみたり。Javascirptの時なんかはよくやる手段です。

その意味では推理能力も必要ですね。つくづくプログラミングってのは思考を駆使すると思うんですよ。だから楽しいんですけどね。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月15日火曜日

プログラムを書いたら考え方と目的も記録を残すこと

プログラミングをする過程で、他人の書いたソースコードを読んでいて本当に強く思うんですけど、その実装方法に至る経緯や考え方や目的が分からないと非常に解読に苦労します。

単なる処理の動きだけならソースコードを読めば分かります。でも、例えばどういう時に使うクラスやメソッドなのかとか、以前別の方法で実装したけれど何らかのトラブルがあって直したとか、そういう情報がないときちんと理解出来ないんですよね。

だからソースコードに考え方と目的を、コメントとして残しておくか、あるいはRedmineなどのタスク管理システムを使っているならチケットに書いておくとか、何らかの方法で記録しておくべきだと思います。場合により使い分けるといいと思いますね。

これは将来そのソースコードを読む他人のためでもあり、そして後から修正をすることになった時の自分のためでもあります。忘れるものですからね。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月13日日曜日

gitのpush前にmerge --squashとpullとrebaseを

gitでどうブランチを切ってコミット・プッシュするかの運用方法については様々な意見というか流派(?)があるように思います。僕自身も複数人数のチームで開発を実際に行う中で、こうしたらいいんじゃないかって思っている方法を書いてみようと思います。

まず開発のタスク管理にはredmineを使っている、という背景があります。gitの共有リポジトリはredmineと連携させていて、共有リポジトリにプッシュしたコミットのメッセージにチケット番号を記載しておくと、自動的にredmineのチケットからリポジトリビューアにリンクされるようになっています。そのような背景から、チケットごとにコミットを1つにまとめています。

さらに、共有リポジトリへプッシュする際は、自分の名前が付けられたブランチにプッシュすることにしています。(masterへのマージはmasterブランチ管理者以外は行わない。)例えば僕はkasaiという名前のブランチを作成して、そこへ自分が担当するチケットを解決するコミットを行い、それを共有リポジトリへプッシュします。

masterブランチ管理者は、共有リポジトリへプッシュされた他の担当者のブランチをローカルリポジトリへプルしてmasterへのマージを行い、改めて共有リポジトリへプッシュします。(つまり、共有リポジトリのmasterへのプッシュを行えるのはmasterブランチ管理者だけです。)

この辺までは結構よくある運用方法でしょうね。ここまで全体的な流れの話を書きましたが、次に、各担当者が個人的に行う運用方法についてです。

僕の場合、ローカルリポジトリにはローカル用ブランチを作って作業しています。ローカル用ブランチは自分のためだけのブランチで、一度行った変更を後のコミットで元に戻したり、試行錯誤の汚い履歴が混在していて、そのまま共有リポジトリにプッシュするなんて考えられない代物です。ちなみに僕はローカル用ブランチには local/yy.mm.dd という名前を付けています(yy.mm.ddは作成時の日付、1日に複数作成した場合はyy.mm.dd-2などとする)。

とういことで、ローカル用ブランチで試行錯誤して、完成したら提出用ブランチ(前述した例ではkasai)にまとめて取り込むという方法を採っています。その際にはmerge --squashを使います。

なお、提出用ブランチにmerge --squashされた後のローカル用ブランチは消してもいいのですが、バックアップの意味もあるし、コードが動かなくなった際に履歴が残っていると原因究明にも役立ったり、元に戻したりできるので残しておくことにしています。

では、提出用ブランチをこのままpushすればいいかというと、ちょっと考えるべき問題があります。pushする前に、共有リポジトリのmasterに、自分が元にした時点から変更がいくつも加わっている場合、コミット内容がmasterと競合しないにもかかわらず、仕様変更によりコードが動かなくなってしまう可能性があります。例えば、他人の担当範囲で定義されていた関数やメソッドを呼び出してコードを書いたが、自分がローカルで作業している間に、その関数やメソッドの挙動を変えるコミットがmasterに既にマージされていた、といった場合です。(この問題に関してはGitユーザマニュアルの「マージコミットの分割が1本線の履歴の分割よりも困難となる理由」の解説が分かりやすいです。)

だから、push直前に、最新のmasterを改めてpullで取得し、その最新のmasterにこれからpushしようとする変更を統合した状態で動作することを確認しておきたいんですね。そのためにrebaseを行ます。つまりpush直前に、自分のブランチをpullで取得した最新のmaster上にrebaseするのです。

こうすることで、上記のようにmaster側に知らないうちに仕様変更が加わっていて、競合が発生しないにもかかわらずコードが動かなくなる、という事態に陥る危険性を(ゼロではないにしても)かなり減らすことができます。また、もしそのような事態になったとしても、rebaseしておくことで原因の究明はぐっとやりやすくなります(当然ながら、これはpush前のコミットだからrebaseしてもいいのであって、たとえ提出用ブランチでも、一旦pushした後のコミットは決してrebaseしてはいけません)。

まとめると、こういう流れになります。
  1. ローカル用ブランチを作成し開発を行う。コミットは適宜好きなように行う。
  2. 提出用ブランチにてmerge --squash でローカル用ブランチの変更をまとめて取り込む。まとめる単位はredmineのチケット単位とする。
  3. masterブランチにてpullで共有リポジトリの最新の状態を取り込む。
  4. 提出用ブランチにてrebaseで変更を最新のmaster上に移し替える。
  5. rebaseされた提出用ブランチにて共有リポジトリへpushする。
  6. (masterブランチ管理者のみ) 各担当者の提出用ブランチブランチをpullし、ローカルでmasterへのマージを行い、共有リポジトリへpushする。
これが今のところいいんじゃないかと思っている方法です。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月11日金曜日

オープンソース時代こそ「コメント力」を

オープンソースとしてソースコードが公開されているソフトウェアを仕事で使ってたりするんですが、その際にソースコードを読み込んで目的に合わせてコードを追加したり改造したりするんですよね。で、何が一番大変かって言うと、そのソースコードを書いた作者の"意図を読み取ること"です。

プログラムの動作自体はソースコードそのものを読めば分かります。ただ、この変数をここで加算して、この関数に引数として渡して・・・といったプログラミング言語の処理自体は分かっても、そのソースコードが"何を目的に書かれているのか"が分からなければ意味がありません。

結局、ある一部分の動作がどういう意味を持つのかを知るために、関連するソースコードがを読み漁り、相当広い範囲を調べてようやく分かったりします。ただ、そこまで時間がかかるのには理由がありまして、ソースコードに"コードの目的・意図を記述した"コメントがほとんど無い場合にそうなるのです。

前にも書きましたが、ソースコードを読めば分かるってのは嘘ですからね。プログラムの機械的動作は確かに分かりますが、コードの目的や意図まで読み取るのは簡単ではありません。もちろんソースコードの関連する部分を含め広い範囲を読めば見えてくるのですが、しかしそれもどうなんでしょうか。

やはり、オープンソース時代であるからこそ、ソースコードを読む人に対する配慮は大切だと思うし、だからこそ、コードの目的や意図を分かりやすく記述できる「コメント力」が大切だと思うんですよね。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月10日木曜日

プログラミング言語のバイリンガル以上を

現在僕が関わっているプロジェクトは1つはRuby、もう1つがPHPをメインの言語として採用しています。自分自身の経験としても、PHPとRubyは得意とする言語なので両方とも言語を使うこと自体に苦労はありません。その他にもJavascriptは両方のプロジェクトで多用していますし、補助的にPythonも少しだけ使っています。あとは汎用言語ではありませんがシェルスクリプトも駆使します。HTML・CSSの知識は言うまでもありません。

実際プロジェクトの開発を進めてて思うんですが、2つ以上の得意な汎用言語を持っておくと色々メリットが有るんですよね。別にRubyとPHPじゃなくてPythonでもC#でもJavaでもPerlでも何でもいいんですけどね。とにかく2つあれば、色々比較ができるわけで、両方の言語を実際に使って開発した体験・経験を比べることによって言語の特徴が体感覚として分かるわけですよ。

例えば片方の言語で慣れたやり方を、もう一方の言語で実装しようとした時にすんなり行かないことがあったら、そこで言語の強みと弱みが分かります。また、そこでもう一方の言語で実装するときの最適解を考えますから、これも力になります。

それに、複数の言語での実装を知っていると、より汎用的なロジックを考えられるようになります。特定の言語に依存したロジックではく、別の言語でも問題なく実装できるようなロジックを考える傾向がつきます。その方がバグも出にくく、品質の工場にも寄与すると考えられますね。

ともあれ、プログラミング言語はバイリンガルになっておくと色々得をします。もちろん2つに留まらず、3つ4つと大いに越したことはありませんが、まずは2つを目指すとよいでしょうね。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月9日水曜日

capybaraのpage.execute_scriptとjQueryの組み合わせの汎用性がすごい

Webアプリ開発のテストに便利な Capybara(+Cucumber) ですが、テストに使うdriver がJavascriptに対応していれば、テスト中にJavascriptの実行を含めてブラウザの動きをシミュレートできるという素晴らしい特長があります。Javascript対応のdriverとしては、Capybara-WebkitやPoltergeistなんかが有名です。

ボタンやリンクのクリックなどのユーザの動作で発火するイベントは、Capybaraでclickなどのメソッドで指定すれば、Javascript側のイベントの動作もそのままシミュレートしてくれるようですが、マウスオーバーなどのイベントはどうやったらテストできるのでしょうか。

実は、Capybaraには execute_script メソッドがありまして、これでJavascriptのコード片を直接記述して実行できます。この中ではページで読み込んだライブラリなどが有効です。なのでjQueryが使えます。よってjQueryを使ってイベントを発火させることにより、かなりの汎用性を持ちえます。

例えば、マウスオーバーのステップ定義はこんなふうに書けてしまいます。

もし(/^".*?\((.*?)\)" にマウスポインタを乗せる$/) do |t_css|
  page.execute_script("$('#{t_css}').trigger('mouseenter')")
end

上記ステップ定義に従い、featureファイルにはこんなふうに書けますね。

もし "メニュー1(#menu1)" にマウスポインタを乗せる

カッコ内のCSSセレクタで指定した要素にmouseenterイベントが発生し、マウスオーバーの動作テストを実行することができます。

という感じで、execute_script メソッド内でjQueryを使うと簡単な記述で様々なことが実現出来そうです。特にテスト実行上重要なイベントの発火が非常に簡潔に書けるのでいいですね。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月8日火曜日

vimdiffでより賢いアルゴリズム(patience,histogram)を使う

vimdiff使ってますか?差分を取る際には非常に便利ですよね。git difftoolに設定して使っている人も多いと思います。しかしgit diffは差分計算のアルゴリズムを選択できますが、vimdiffはデフォルトでは差分計算のアルゴリズムを選択できません。

git diffの差分アルゴリズムには標準のもの以外にpatienceやhistogramがあり、より人間に読みやすい差分を表示してくれる「賢い」アルゴリズムになっています。それぞれgit diffコマンドのオプション--patienceや--histogramを付けるか、または~/.gitconfig設定ファイルにアルゴリズムを指定することで利用できます。

具体的なアルゴリズムの詳細は僕も詳しくないですが、patienceアルゴリズムは「ファイル内でユニークかつ比較ファイル同士で一致する行をなるべく"変化していない行"と認識する」よう働きます。また、histogramアルゴリズムは「patienceアルゴリズムの基本的ルールを継承しつつ高速化を図ったアルゴリズム」で、多くのファイルでpatienceアルゴリズムと同一の結果が得られるようです。また、histogramアルゴリズムはEclipseに統合されたGitクライアントEGit(が使うJGit)の標準アルゴリズムです。僕はコマンドラインツールのgitにおいてもhistogramアルゴリズムを使ってます。

さて、vimdiffにおいてもhistogramアルゴリズムを使いたいところです。vimの設定ではvimdiffの差分計算に使用するコマンドをdiffexprという設定値で指定できます。そして、git diffコマンドも--no-indexオプションを指定することでdiffコマンドと同じようにスタンドアロンツールとして利用できます。じゃあ、diffexprにgit diff --no-indexを指定すればいいのか・・・というと実はそれだけでは失敗します。

理由は、vimがdiffexprに設定したコマンドから受け付ける差分形式が、diffコマンドのnormal形式かed形式でなければならないからです(vimのヘルプにはed形式とだけ書いてあるのですが、normal形式も受け付けます)。そして、git diffコマンドでは直接diffコマンドのnormal形式やed形式で出力することができずunified形式のみに対応しています。

そこで、unified形式をnormal形式に変換するrubyスクリプトを書いて使うことにしました。以下がその変換スクリプトです。利用にはrubyが必要です。

#!/usr/bin/env ruby
iwhite = ''
if (ARGV[0] == '-b')
  iwhite = ARGV.shift.dup << ' '
end

diffout = `git diff --no-index --no-color -U0 #{iwhite}#{ARGV[0]} #{ARGV[1]}`
diffout.sub!(/\A.*?@@/m, '@@')
diffout.gsub!(/^\+/, '> ')
diffout.gsub!(/^-/, '< ')
diffout.gsub!(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@.*/) do
  before_start = $1
  before_size = $2
  after_start = $3
  after_size = $4

  action = 'c'
  if (before_size == '0')
    action = 'a'
  elsif (after_size == '0')
    action = 'd'
  end

  before_end = ''
  if (before_size && before_size != '0')
    before_end = ",#{before_start.to_i + before_size.to_i - 1}"
  end

  after_end = ''
  if (after_size && after_size != '0')
    after_end = ",#{after_start.to_i + after_size.to_i - 1}"
  end

  "#{before_start}#{before_end}#{action}#{after_start}#{after_end}"
end
diffout.gsub!(/^(<.*)(\r|\n|\r\n)(>)/, '\1\2---\2\3')
print diffout

上記スクリプトを~/bin/git-diff-normal-formatとして保存し、~/binにPATHを通しておきます。そしたら、.vim設定ファイルに次の記述を追加します。

" diffのコマンド
set diffexpr=MyDiff()
function MyDiff()
  let opt = ""
  if &diffopt =~ "iwhite"
    let opt = opt . "-b "
  endif
  silent execute "!git-diff-normal-format " . opt . v:fname_in . " " . v:fname_new . " > " . v:fname_out
  redraw!
endfunction

最後に、git diffで使うアルゴリズムを指定します。下記記述ではgit difftoolで起動するコマンドにvimdiffを指定する設定も一緒に行っています。

[diff]
  tool = vimdiff
  algorithm = histogram

これでvimdiffやgit difftoolを実行した時にhistogramアルゴリズムが使えるようになります(patienceを使いたい場合は、上記設定のalgorithmの値をpatienceに変えてください)。

では具体的な効果を見てみましょう。サンプルとして用意した2つの比較対象のファイルをvimでウィンドウを分割して並べたものが下の画像です(クリックで拡大できます)。


まずは、今回の設定をする前、デフォルトのアルゴリズムでvimdiffによる差分をとった結果が以下です(クリックで拡大できます)。


そして、今回の設定をした後の、histogramアルゴリズムでvimdiffによる差分をとった結果が以下です(クリックで拡大できます)。


こちらのほうが、より差分内容も分かりやすく、かつ実際に手で行った変更の操作に近いものになっていますね。
※ちなみにこのvimdiffの色設定は過去に書いたこの記事を参照。

※2014/07/10更新:diffupdateを実行した際に画面の描画がおかしくなることがあったので、回避のためMydiff()にredraw!を追加

※参考記事
Making your Git Diff/Merge More Useful | The Interim Developer
Alfedenzo - Patience Diff, a brief summary
Bram Cohen's Journal - Patience Diff Advantages
HistogramDiff (JGit - Core 2.0.0.201206130900-r API)

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月5日土曜日

ググっても解決しない問題にこそ力を注ぐ

今のソフトウェア開発ってフリーソフトとかオープンソースとか皆が共通に利用できる資源が整ってまして、仕事で使うソフトウェアも手に入ります。その結果優れたソフトウェアは皆が同じものを使うようになります。得られたノウハウもウェブページやブログや各種SNSで公開していくために、困ったことがあればググればほとんど解決できるんですよね。その意味でネットが無ければ仕事になりません。

だから知識は重要だし、他人が既に見つけた問題の解決策を素早く見つけることも必要ではあることは確かです。僕も散々そう言ってますし。でも、そこには当然ながら限界がありまして、仕事をしていれば必ず、そう"必ず"いくらググっても解決策を見つけられない問題にぶちあたるものなのですね。

その時こそが本当に力を注ぐべき時です。ググって解決できるものをサッサと片付けるのは、この"いくらググっても解決策を見つけられない問題"に時間を掛けるためだと言っても過言ではありません。

ちなみに僕は"いくらググっても解決策を見つけられない問題"にぶちあたるのを、いつも楽しみにしてます。まあ、ググってサクサク問題を片付けるのもシューティングゲームみたいで楽しくはありますが、やはり本気で頭を使う時が一番楽しかったりするので。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月4日金曜日

gitでマージの事前に衝突するかどうか確認する

gitを使っていて、特定のブランチとマージしたら衝突が起きないかどうか知りたい場合があります。例えば、プロジェクトチームで共有しているリポジトリにコミットをプッシュする前に、現在作業中のブランチがmasterブランチと衝突を起こさないか確認しておきたい、なんて場合です。

そんな時は、mergeコマンドの —no-commit オプションで master をマージしてコミットせずに止めてみればいいです。あとで簡単に元に戻せます。(本来確かめたい向きとは逆向きのマージですが、衝突の確認をするだけなら結果は同じですから問題ありません。)

[user@host]% git merge master --no-commit
Auto-merging /some/file/path
Automatic merge went well; stopped before committing as requested

同一ファイルに編集があったが、自動的にマージされた場合には上記のような表示になります。衝突を起きて自動的に解決できない場合はその旨がここで表示されるはずです。

確認は終わりましたが、そのままではワーキングツリーとインデックスが変更されたままですので、元に戻します。mergeコマンドの --abort オプションを使えばいいです。

[user@host]% git merge --abort

これで元通り。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月3日木曜日

評価されないが重要なメンテナンス性

プログラミングをしていて、つくづくメンテナンス性って重要だと感じます。要するに後から修正や変更をしやすい構造にするってことなんですが、問題は、このメンテナンス性を高くするという行為がすぐに成果に直結しないため評価しにくいってことでしょうね。

まあ、評価されるかどうかはおいといて、エンジニアとしてのこだわり、あるいはポリシーとしてメンテナンス性は上げておきたいわけですよ。そのプログラムが使われれば使われるほど、メンテナンス性は重要になっていくわけです。

それに、他のエンジニアが自分の書いたコードを見るたびに文句をいうことになるか、あるいは逆に賞賛してくれるかは、メンテナンス性の良し悪しにかかっています。その意味でも、自分の書くコードはメンテナンス性は高く保つよう常に努力してます。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月2日水曜日

コーディングには自分なりのポリシーを持つ

ソフトウェア開発をしておりますと、人の個性が出る作業の代表格はプログラムのコーディングでしょう。

性格も出る気がしますし。注意すべきなのは、面と向かって話している時に感じる印象と、プログラムをコーディングしている時に、そのソースコードに現れる印象は違うことがあるということです。

ともあれ、それぞれの個性というのはありますが、その中においても、やはり各自が自分なりのポリシーを持つべきだと思います。

僕だったら、
・コードの簡潔さより、長くても読んで分かりやすい方を優先する
・コメントは積極的に入れる

などですね。自分なりのポリシーを持ち、その運用を改善していくことにおって、コーディング自体のスキルも上がると思います。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月1日火曜日

ボツになるコードを書く勇気

仕様書通りに動くプログラミングをするのが
我々ソフトウェア開発者にとって仕事の基本ですが
ただ言われた通りのものを作るだけじゃ面白くないわけでしてね。
改善提案をしたいわけですよ。

ところが、人間ってのは実際自分の目で見て動作を実感しないことには
口で行っただけでは提案した改善の効果が伝わらなかったりする、
なんてことが多いです。

そういう場合に、たまに僕がやる手段は、
ボツになるかもしれないのを覚悟で改善提案のコードを
書いてしまうことです。そして目の前で実際に動かしてみせるのです。
もちろんボツになったこともありますが、意外に採用してくれる
ことが多いですね。

言われたことだけ、仕様書に書いてあることだけを創っていては
見えてこない物があると思います。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。