潜伏バグからのロングフリーズ

Javaっぽいエンジニアの徒然草

Agile Samurai Base Camp

2013/12/8に行われた「Agile Samurai Base Camp」の参加レポートです。

http://www.agilesamuraibasecamp.org/

※2014/4に同イベントが開催されると更新されてます!!

 

会場は渋谷のサイバーエージェント

扱う内容は、「インセプションデッキ」「テスト駆動開発」の2つで、参加者はどちらに参加するか選択できます。

 

このイベントに参加するにあたって、事前準備として次の2つを行いました。

 

アジャイルサムライの購入(約2600円)&目を通しておく(10hぐらい?)

 ⇒ この本の内容を踏まえた内容なので、目を通しておくに越した事はありません。

   個人的には前半はペース遅め、後半はサクサクと読めました。

   参加登録時点では「インセプションデッキ」にしていましたが、当日は「テスト駆動開発」に参加しました。

 

②一緒に参加する人の募集

 ⇒ これは前回参加した「DevLOVE甲子園」の反省を踏まえてです。

   結論として、自分含めた3人で参加しました。

 

 

9時前に会場となるビルに到着し、案の定迷ったので警備員さんを捕まえて道を尋ねます。

本当に、東京の駅やらビルやらはどういう構造になっているか良くわかりません。

 

なんとか会場前に到着したのが9時10分ぐらい。

入れるのが9時15分とのことでしたが、すぐに入れました。

どうやら運営側を除くと1番乗りだったようです。

 

受付でQRコードを見せると、ネームプレートを渡されました。

「呼んで欲しい名前」「どっちに参加する」「理解度を☆3段階で」の3つを書くように依頼されます。

他にはtwitterアカウントや意気込みを書いている人も居ました。

 

一番前の席@スクリーン正面からパシャリ

f:id:monokurotamago:20131208093619j:plain

 

当初の予定から1時間遅れで始まります。

何やら会場トラブルとのことで、会場が他のイベントとダブルブッキングしたという...

テンション下がり気味での開幕となりました。

が、アジャイルサムライの著者Jonathan Rasmussonのメッセージ映像が流されるや否や、テンション元通りです。

よし、楽しもう。

 

 

■基調講演(10:30-11:20)@角谷信太郎氏

講師はアジャイルサムライ監訳者の方です。

 

・実際に使う人が使える状態(=動くソフトウェア)を定期的に届ける。

・手元(自分のローカル環境)でしか動かない、ではダメ。

アジャイルチームは大きく2つの人から成る

  顧客…何を作るか決める

  開発チーム…どうやって作るか決める

・Jonathanがこの本を書いた理由

  アジャイル本沢山あるから書く必要なかったのでは?

   → バラバラのものが沢山あって、色々読まないと分からない

   → 1冊にまとめたらどうだろう?

   → 7冊の良書をまとめて、オリジナル要素(インセプションデッキ)を付け足してアジャイルサムライ書いた

・ソフトウェア開発がアジャイルであるとは?

  "開発がアジャイルである"ということは、協調性を重んじる環境で、フィードバックに基づいた調整を行い続けることである。

 

 

■TDDどう始めるの?(11:30~12:10)@和田卓人氏

講師はDevLOVE甲子園でも話を聞かせていただいた方です。

 

・システムを作る ×

 システムを作り続ける ○

 

テスト駆動開発入門

 → 「動作するキレイなコード」を書き続ける

f:id:monokurotamago:20140321161039p:plain

 

 

   良い設計→ロス無くコードに落とす

    完璧主義の呪い

   →もっと良い設計があるのでは?と思い、なかなか先に進めない

  コードを書くときに

   →綺麗だけどスピードが遅い(パフォーマンス悪いよね)

   →綺麗だけど漏れがある(必要な処理が抜けてた)

  ※コードを書かないと分からない事は沢山ある!!

 

   動く汚いコード→綺麗にブラッシュアップ

    動くから良いよね

   →堕落する

  独活句コードを綺麗に出来れば…

   →そこでテスト駆動開発

 

・TDDのサイクル

1. 次の目標を考える

2. その目標を示すテストを書く

3. そのテストを実行して失敗させる(Red)

4. 目的のコードを書く

5. 2で書いたテストを成功させる(Green)

6. テストが通るまでリファクタリングを行う(Refactor)

7. 1~6を繰り返す

f:id:monokurotamago:20140321161102p:plain

 

 

・TDDと黄金の回転

f:id:monokurotamago:20140321161135p:plain

 

失敗パターン

 TDDの回転が回らなくなる時は、大抵の場合「時間が無い」という理由でRefactorが疎かになる。

 

リファクタリングは溜めれば溜めるほど大変になる

 → 直近で価値の薄い(リファクタリング)ものに時間をかけられない

 → TDDではリファクタリングをサイクルに組み込む事で毎日行う

 

・TDDをやる上での心得

 ・1つずつ少しずつ段を小さく行う。

  → 大きいものを小さく割る。

 ・複数を相手にしない。一人ずつ対処する。

  → 1対多では勝てない。1対1の連続にすれば勝ち続けられる。

 ・すばやくまわす。

  → TDDサイクルを早くまわせるようになる。

 ・自分が最初のユーザになる。

  → 作り易いコードと、使い易いコードは異なる。

    TDDはテスト(=使う側)から書くので、自然に使い易いコードを書くようになる。

    ※コードは書く時間よりも、使われる時間の方が圧倒的に長い。

 ・不安をテストに。

  → テストする場所は不安のある場所。

    自分達の範囲で品質を上げる。

     → TDDやっているから品質に不安はない ×

       人間の書くテストには漏れがあって当然

 ・命綱を編む

  → 急な変更に備えておく。

    一つ一つのテストコードが網目となる。

 

・TDDやDeveloper Testのメリット

 ソフトウェア工学上の理由もあるが、何よりも心理面が大きい。

 ・即座にフィードバックが得られる

 ・書いたコードに自信が持てる

 ・これから書くコードに自信が持てる

 

・テストは目的ではなく手段

 目的は?

  → TDDの真の目的は「健康」

    ・変化に対応するのは健康体のコード

      重複がない、分かり易い名前、分かり易い構造

    ・変化に対応するのは健康体のチーム

      リファクタリングのスキルUP→定時に帰って健康に

    ・不安の克服健康の維持

 

QA

Q. テストを書くと仕変のメンテの手間が増えてしまう。

A. テストのメンテに時間がかかるのはテストに問題がある可能性あり。

  仕様が大きく変われば、テストも大きく変わるのは当然ではあるが、無駄な書き換えが発生しないようにテストを書きましょう。

 

 

Javaによるライブコーディングデモ(13:15~13:45)

TDDが実際にどのように行われるか、ペアプログラミング形式によるデモ。

■アンカンファレンス(13:55~14:45)

・初心者向けコーナー

Javascript版ライブコーディング

・実践者向け質問コーナー

 

TDDの用語

・仮実装

・三角測量

・明白な実装

 

Note

テストを書く時は、Assertから書いたほうが何をするかが明確になる。

テストクラスのメソッド名は日本語にすると、eclipseの左側見たとき分かり易い。

 

QA

Q. 仮実装(return true; だけのメソッド)する意味は?

A. 仮実装でこけたら、テストコードの側に誤りがあることが分かる

 

Q. プロダクションコードとテストコード両方リファクタリングする?

A. テストコードも分かり易くしておくべきなので、両方行う。

 

 

■TDD事例

TDDメリット

・テストコードが増える

・テストが壊れにくくなる

・プロダクトコードが読みやすくなる

 

レガシーコード

・一部の変更が全てに影響

 ・ジェンガ / スパゲッティ

 ・動いているコードに触るな

 

普通の開発経験豊富な人(プロダクト書いてからテストする)はTDDを受け入れない。

→ これまでのやり方で出来てたんだから良いじゃないか

 

QA

Q. どうアプローチすれば良い?

A. TDDを経験して貰うしか無い。

  体験型ワークショップをする。

  トップダウンで社長にTDDやってもらって「これ良いよー」アピールしてもらう。

 

Q. TDD導入で生産性どのぐらい下がるものなの?

A. 体感で3割。下がった分は他でカバーする必要あり。

  レガシーコードに導入したら工数が5倍以上になった経験あり。

  5倍以上に膨れても、その後のデバッグを考えると、総工数がトントンか寧ろお得なぐらい。

 

Q. テスト書くときのコードレビューは何を見るの?

A. テストケースのレビューが必要になる。

  何をしたいテストか分かるか、とか、Assertは一つに絞られているか、とかを見る。

 

 

■基調講演@市谷聡啓氏

講師はDevLOVE創始者。

 

"リーン開発の現場"という本を出した。

P109にこんなことが書いている。

 "理想とは辿り着くべき場所のところではなく、ありたい姿に向かい続けることなんだ!"

 

ソフトウェアを創り上げるもの

・プロジェクト

・ユーザ

・顧客

・チーム

 

1日1個何か学べ→1年で365個学べる

とあるSQLにおけるSQLパフォーマンスチューニング LEFT JOIN句で条件指定 vs WHERE句で条件指定

抽出したい情報

・A_TBLにあって、B_TBLのCODEが'XXX'であるレコード

・A_TBLにあって、B_TBLにはないレコード

 

抽出したくない情報

・A_TBLにあって、B_TBLにもあるがCODEが'XXX'ではないレコード

 

(1)

select *

from A_TBL

  left join B_TBL

  on A_TBL.KEY=B_TBL.KEY

where (B_TBL.CODE='XXX' or B_TBL.CODE is null)

 

(2)

select * 

from A_TBL

left join B_TBL

  on A_TBL.KEY=B_TBL.KEY

  and B_TBL.CODE='XXX'

where 〜

 

Oracle SQL Developer の自動トレース機能でSQL処理にかかった時間を調べる。

LAST_ELAPSED_TIME

前回の実行中の、この操作に対応する経過時間 (ミリ秒単位)

 

とあるSQLの計測結果

(1)

コスト: 4181

1回目: 2317288

2回目: 2293505

3回目: 2355084

 

(2)

コスト: 4191

1回目: 2191518

2回目: 2210278

3回目: 2193193

 

今回のケースでは、

 (1)より(2)の方がコストは微増してしまうが、(2)の方が処理時間は若干早い

という結果になった。

 

コストと実測速度が反対の結果になるのは良くあること。

パフォーマンスチューニングは奥が深い。

FreeNAS 最新版(9.2.1.2)を導入しようとしてコケた件

自宅の既存ストレージが、

 ・10年以上前のマシン

 ・OSはFreeNAS-8.0.3-RELEASE

 ・USBブート非対応のためFDからPLoP Boot Manager経由でUSBブート 

という古い構成だったので、マシン&OSの入替を行おうとしたメモ。

 

①ISOダウンロード

公式サイトから必要なISOファイルをDL。
http://www.freenas.org/

今回は32bit版のx86を利用。
FreeNAS-9.2.1.2-RELEASE-x86.iso


②ISOイメージをCD/DVDに焼く

通常のファイルコピーではダメなので、ISOイメージを焼くソフトを使う事。
今回はDeepBurnerを利用。
ISOイメージの焼き方は割愛。


③インストール
対象マシンのCDドライブに②で作ったCD/DVDを入れる。
インストール先となるUSBメモリを対象マシンに刺しておく。
この状態でCDブートでマシンを起動して、USBメモリにOSをインストールする。

 

嫌なエラーが発生

Guessed BIOS device 0xffffffff not found by probes, defaulting to disk0.

can't load 'kernel'

 

更に読んでみると、/boot/defaults/loader.confが読めないとかなんとか。

ためしに該当ファイルをエディタで開こうとすると、なるほど読み込みエラーで開けない。

 

ISO焼きに失敗したかと思い、再度焼いてみる。

今度はloaderは読めた。

が、その後の起動ロジックでスタックオーバーフローが発生してコケる。

 

以前導入した8.0.3のCDが残っていたので、

ためしにブートしてみるとインストール画面まで進めた。

うーん。

(今回使おうとしたマシンには)最新版ダメだこれ。

 

かといって、このままメジャーバージョン8を使う気にはなれない。

少しバージョンを落としてみよう。

「FreeNAS-9.2.1-RELEASE-x86.iso」をDLして再度ISOを焼く。

 

特に問題も起きずにインストール成功。

やっぱり(今回使おうとしたマシンには)最新版ダメだこれ。

 

 

お次はUSBブート。

BIOSの設定を変えるだけの簡単なお仕事。

そう、簡単なおしg…?

うわー、このBIOS、USBブート対応してないじゃないですか!

 

結局また PLoP Boot Manager のお世話に。

http://www.plop.at/en/bootmanager/download.html

 

今回はFDではなくCDに焼いて利用。

BIOSのブート設定をCDに変えて準備OK。

 

これで、

 1. マシン起動でCDブートする

 2. PLoP Boot Manager起動、マニュアルでUSBを選択

 3. USBメモリからFreeNASを起動

という、高々OS一つ起こすには大仰なロジックが完成。

 

早速やってみると、FreeNAS起動中にコケた。

エラー文などは発生せずに、ブラックアウトしてマシン再起動状態に...

 

色々と面倒なので「マシンとOSの相性が悪かった」と決め付けて導入中止。

とは言え、ストレージの再構築は必須なので、近々何か手を打たないといけない。

 

Railsを導入してmysqlを利用したプロジェクトを作成

rubyを導入した前回の続き。

今回はいよいよRailsを導入。

 

Railsの導入】

とりあえずgem updateしたら早速エラーが発生した。

$ gem update

Updating installed gems

Updating CFPropertyList

Fetching: CFPropertyList-2.2.7.gem (100%)

ERROR:  While executing gem ... (Gem::FilePermissionError)

    You don't have write permissions for the /Library/Ruby/Gems/2.0.0 directory.

 

書き込み権限が無いらしい。

カモン管理者権限。

$ sudo gem update

ok.

 

巷ではシステムのgemに直接railsを入れるのではなく、プロジェクトごとにbundlerなるものでgemを管理するのが流行っているらしいが、手順が増えるので利用せず。

railsをバージョン指定でインストール。

今回は4.0.2を使用。

$ gem install rails --version="4.0.2"

ERROR:  While executing gem ... (Gem::FilePermissionError)

    You don't have write permissions for the /Library/Ruby/Gems/2.0.0 directory.

 

書き込み権限が無いらしい。

カモン管理ry

$ sudo gem install rails --version="4.0.2"

途中でなんか出た。

rake's executable "rake" conflicts with /usr/bin/rake

Overwrite the executable? [yN]  

既に"rake"があるとな。上書きしちゃえ。 y enter

またなんか出た。

railties's executable "rails" conflicts with /usr/bin/rails

Overwrite the executable? [yN] 

なんと"rails"も入っているとな? ええい、ままよ。 y enter

しばらく待つと…

30 gems installed

ok.

railsに紐づいて29個のgemが入ったっぽい。

 

念のためちゃんと入っている事を確認。

$ rails -v

Rails 4.0.2

Rails導入完。

 

 

Railsプロジェクト(DBはMySQL)を作ってみる】

適当なディレクトリを作成してカレントをそこに移動。

オプションでDBを指定してプロジェクト作成。

ちなみにこの時点ではまだMySQLをインストールしていない。

 ↖︎注記:読み進めれば分かりますが、予め入れておく事をオススメします。

 

$ rails new test -d mysql

Invalid application name test. Please give a name which does not match one of the reserved rails words.

予約語「test」と一致してるから別の名前を使えとな。

 $ rails new test_rails -d mysql

なんか色々createしたあと、こんなのが出た。

Your user account isn't allowed to install to the system Rubygems.

You can cancel this installation and run:

    bundle install --path vendor/bundle

to install the gems into ./vendor/bundle/, or you can enter your password

and install the bundled gems to Rubygems using sudo.

Password: 

管理者パスワード入れたら動いた。

 

ディレクトリを確認すると、ちゃんと初期ファイルが作られている。

プロジェクト作成成功。

 

 

【ブラウザからアクセス 前編】

先ずはサーバ起動。

$ rails server

Usage:

  rails new APP_PATH [options] 

作成したディレクトリに移動しないと駄目ですよねー。わかってましたよー。

では改めて、

$ rails server

Could not find gem 'sdoc (>= 0) ruby' in the gems available on this machine.

Run `bundle install` to install missing gems.

bundleインストールしろと怒られた。

素直に従いましょう。

パスワード求められるので入力。プロジェクト作成時と同じ。

再発するパーミッションエラー。

Errno::EACCES: Permission denied - /Library/Ruby/Gems/2.0.0/build_info/coffee-script-source-1.7.0.info

An error occurred while installing coffee-script-source (1.7.0), and Bundler

cannot continue.

Make sure that `gem install coffee-script-source -v '1.7.0'` succeeds before

bundling.

困ったときの管理者権限。

$ sudo bundle install

中略

An error occurred while installing mysql2 (0.3.15), and Bundler cannot continue.

Make sure that `gem install mysql2 -v '0.3.15'` succeeds before bundling.

やっぱりMySQL必要ですよねー。わかってましたよー。

 

 

 【いったんrubyから離れてhomebrewでMySQLを導入するお話です】

$ brew update 

$ brew install mysql

問題なくインストール完了。

コンソールにmysqlの起動方法について説明が表示された。

OS起動時に自動起動するように設定をする or 毎回手動で起動する のどちらからしい。

WindowsMySQL使う時もサービス切って手動起動しているので、今回も手動起動しましょう。

 

1. mysqlフォルダに移動 (設定に移動は不要かも?とりあえず場所確認の意味で)

$ cd /usr/local/Cellar/mysql/5.6.16

 

2. 初期設定

2014/3/3追記-----

最初にunsetを実施

unset TMPDIR

追記ここまで-----

$ mysql_install_db --verbose --user=`whoami` --basedir="$(brew --prefix mysql)" --datadir=/user/local/var/mysql --tmpdir=/tmp

FATAL ERROR: The parent directory for the data directory '/user/local/var/mysql' does not exist.

If that path was really intended, please create that directory path and then

restart this script.

If some other path was intended, please use the correct path when restarting this script.

--datadirオプションの設定は色んなサイトでuserってなってたけど、自分の環境ではusrだった。

 $ mysql_install_db --verbose --user=`whoami` --basedir="$(brew --prefix mysql)" --datadir=/usr/local/var/mysql --tmpdir=/tmp

ok.

 

3. パスワード設定

 3.1 mysql起動

$ mysql.server start

 

 3.2 パスワード設定

$ mysqladmin -u root password NEW_PASSWORD

 

 3.3 確認

$ mysql -u root -p

  Enter password:

  パスワード入力でmysqlに切り替わればok.

mysql> show databases;

  で作成されたDBを確認してみる。問題なし。

mysql> exit

  でmysqlモード終了。

 

 3.4 mysql停止

$ mysql.server stop

 

mysqlの導入完了。

railsの設定再開。

 

 

【ブラウザからアクセス 後編】

$ sudo bundle install

ok.

 

railsサーバ起動。

$ rails server

 

次のように表示されればok.

ちなみにサーバ起動中はターミナルが下記状態で固まる模様。

=> Booting WEBrick

=> Rails 4.0.2 application starting in development on http://0.0.0.0:3000

=> Run `rails server -h` for more startup options

=> Ctrl-C to shutdown server

[2014-03-02 14:19:55] INFO  WEBrick 1.3.1

[2014-03-02 14:19:55] INFO  ruby 2.0.0 (2013-06-27) [universal.x86_64-darwin13] 

[2014-03-02 14:19:55] INFO  WEBrick::HTTPServer#start: pid=44155 port=3000

 

 

【 いよいよブラウザアクセス】

http://localhost:3000/

 

エラー発生

Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

 mysqlが起動していないのが原因だった。

 ︎別のターミナルを立ち上げて、mysqlを起動して再チャレンジ。解決。

 

エラー発生

Access denied for user 'root'@'localhost' (using password: NO)

 エラー文でぐぐるとパスワード設定のやり直しすれば良いと出てきたので、やってみたものの解決せず。

 少し考えて、今回のケースでの意味を悟った。

 「接続にパスワードが使われていない」だけ。

 作成したrailsプロジェクトディレクトリ/config/database.ymlファイルを開く。

 development、test、productionのpasswordが空になっているので設定する。

 ユーザはとりあえずrootのままで。

 このエラーはこれで解決。

 

エラー発生

Unknown database 'test_rails_development'

 DBが無いとな。

 mysql入ってとりあえず中身は空のDBを作成して解決。

mysql> create database test_rails_development default character set utf8;

 

ようやく眼前に広がる「Welcome aboard!」の文字。

よし、動いた。

 

最後にraildサーバを control+c で停止して終了。

 

 

参考

 Ruby on Rails環境構築と、Rails is not currently installed on this system. (略) の謎

 http://ryoichi0102.hatenablog.com/entry/2014/01/31/090722

 

 gemでバージョンを指定してインストールする方法

 http://d.hatena.ne.jp/cybaron/20110924/p1

ORA-00060とORA-02049

デッドロックについて問い合わせを受けたのでメモ。

 

デッドロック ORA-00060

分散トランザクション待機 ORA-02049

 

デッドロックは発生した瞬間エラーとなり、タイムアウト設定不可。

→ ORA-00060が発生したら設計を見直し。

 

WAIT句対象レコードにロックがかかっていた時に、指定時間待機する。

→ ORA-02049は状況次第でこれで対処できそう。

  もちろんいくら待ってもロックが解除されないような設計であれば見直し。

 

ORA-02049が発生してとりあえずロックを解除したい場合は過去記事で書いた通りにプロセスをkill。

コンパイルエラー「\65279は不正な文字です。」

Eclipse上で問題なく動いていたJavaコードに対して、コマンドラインからビルドをかけたところ表題のエラーが発生した。

 

\65279 = UTF-8のBOM(Byte Order Mark)

 

どうやらソースファイルの中に、エンコードUTF-8でBOMありのものが紛れ込んでいるらしい。

 

Windows機を使用していたので、手っ取り早い対処法にて対応した。

 

【対処方法】

 1. サクラエディタで対象ファイルを開く

 2. 名前をつけて保存を選択

 3. 文字コードセット、改行コードの右側のBOMチェックをOFFにする

    f:id:monokurotamago:20140301150305p:plain

 4. 保存する(上書き)

 

 

Eclipseでエラーにならなかったのに、なんでjavacだとエラーになるの?】

EclipseではJDTコンパイラを使用していて、コマンドラインではOracle純正コンパイラを使用していることが原因。

 

マシンの環境パスで指定するjava.exeは、普通はOracle公式サイトから落とした純正のものを利用する。コマンドラインコンパイルする時はこれが使われる。

一方で、Eclipseコンパイルする時には、Eclipseの中のjava.exeが使われる。このjava.exeはEclipse独自のもの。

 

そして重要な事は、

 eclipseコンパイラは純正コンパイラよりもコンパイルエラーとする条件が緩い。

ということ。

 

調べてみるとこんなのがあった。

 

 JDTコンパイラならOKだけど、純正コンパイラじゃ通らない記述

 http://d.hatena.ne.jp/eyamane/20061212/1165892799

 

 ECJ (Eclipse Compiler for Java) は面倒見が良すぎ…

 http://d.hatena.ne.jp/imatake/20100702/1278038592

 

知っていればたいしたことないけど、知らないとハマる罠。

 

 

オマケ

 JDT(Java Development Tools)の概要

 http://ossforum.jp/node/985

 

 なぜ EclipseJRE を使っているのにコンパイルできるの?

 http://www.hitachi.co.jp/Prod/comp/soft1/cosminexus/useful/tips/090606_eclipse-jre-compile.html

継続的Webサービス改善ガイド 第2章

継続的Webサービス改善ガイド

第2章 開発環境の改善~技術的負債の返済と,レガシーコードの仕様化テスト

http://gihyo.jp/dev/feature/01/webservice-guide/0002

 

【概要】

webサービスの成長とともに大きくなる「技術的負債」を返済するために、

筆者が所属する会社で取り組んでいる方法について紹介されている。

 

 

以下、1ページ目、および2ページ目前半の内容要約を記載する。

 

 

■技術的負債

 アプリケーション層とハードウェア層、それぞれに存在するが、

 ここではアプリケーション層の技術的負債を対象とする。

 

 具体的には、

  ・障害対応のためにテストを書かずにその場しのぎで入れたコード

  ・「TODO: あとで直す」といったコメント付きのコード

  ・とりあえず動くことを目的とした適当な設計のコード

  ・コピペコード

  ・脆弱性が存在するライブラリを使用しているコード

 など。

 

 もちろん、障害発生時は「奇麗なコードを時間をかけて書く」よりも

 「汚くてもとりあえず動くコード」を書くことが求められるが、

 その「汚いコード」を放っておくと、

  ・システムの複雑性が増すことによるリリースサイクルの長期化

  ・システム障害の発生や長期化

 などの問題に繋がってしまう。

 そしてこの「汚いコード」は、エラーで処理が止まるわけではないので、

 改善に着手されにくい。

 

 

■継続的な現場改善

 技術的負債の蓄積 ▶︎ サービスの負債

 では、技術的負債を抑えるためには何が出来るか?

 

 ・毎日の作業の一環に組み込む

   毎朝30分間、技術的負債の返済を行うための時間を確保する。

   ここでテストが無いコードにテストを書いたり、リファクタリングを行う。

 

 ・CIの導入

   Jenkins, Travis CI, Coveralls, Gemnasiumなどのツール、サービスを用いて、

   自動的にテストの実行、失敗の検知といった作業を自動化する。

 

 ・コードレビュー

   チーム内コミュニケーションを促し、結果としてコードの品質向上や

   不具合の検出が期待できる。

   全てのコードは、書いた本人以外によるコードレビューを通すべき。

   GitHub(無償でもEnterpriseでも)のpull requestを用いたレビューにて、

   書いた本人が気づかない点に気づけるしくみを作っている。

 

 

■開発環境の改善

 技術的負債の返済には、環境に問題がある場合もある。

 例えば、

  ・本番環境で動いているコードの中に、バージョン管理されていないものがある

  ・テスト環境、ステージング環境が存在しない

  ・開発を行う環境が物理サーバ、仮想サーバ上にしか存在せず、

   開発者個人のマシンで確認できない

 といった場合は、技術的負債を返すためのコード変更が行いにくいと言える。

 

 バージョン管理

  サービスを運用していると、

   ・サーバ上でコードや設定ファイルを直接編集して対応

   ・メンテナンススクリプトをサーバ上で作成して実行

  といったことが発生する。

  これらもすべてバージョン管理システムに保存する必要がある。

  Railsのようにデータベースのマイグレーションスクリプトフレームワーク

  内包されていれば、意識せずに上記バージョン管理が行われている。

  そうでない場合は、少なくともデータベースに発行するSQL

  すべてバージョン管理しておくべき。

 

 開発環境の仮想化

  サーバ設定作業の自動化 ▶︎ Puppet, Chef

  VM作成ツール ▶︎ Vagrant

  本番環境を気軽・高速に開発環境として再現できることは重要。

 

 

■レガシーコードの継続的な改善

 『レガシーコード改善ガイド』による言葉の定義

 テストがないコードはレガシーコード

 

 1時間前に書いたコードもレガシーコード?

 ▶︎ テストが無いとリファクタリングできないので遅かれ早かれそうなる。

 

 レガシーコードを改善するためには?

 ▶︎ 仕様化テストがオススメ

    既にあるプロダクトコードの挙動が仕様であるとして書くテスト。

    リリース済みのサービスは、仕様の変更は慎重に行う必要がある。

    

    

  

【感想】

開発の現場では「動いているコードは触るな」という言葉が度々叫ばれる。

例えそれが汚いコードであっても、デグレを恐れて改修しないことは多々ある。

一方で、TDD実践者として有名な@t_wada氏が言うように、

「動いているコードだからと言って触らなければ、そのコードは死んでしまう」

というのは、まさにこの技術的負債のことだろう。

つまり、改修する/しないの決定は状況に応じて判断する必要がある。

 

直近を平和に収めるためには「動いているコードは触らない」

 例えば「3ヶ月後にサービスの終了が決まっている」といった場合であれば、

 敢えて危険を冒す必要はないだろう。

 

未来の安寧を求めるならば「積極的リファクタリング

 企業の基幹システムで長期間の使用が予測される場合であれば、

 技術的負債を抱えたまま運用をすることは考えたくない。

 リファクタリングしやすい環境づくりは急務と言える。

 もちろんこれらの作業には多大な工数がかかり、

 顧客から見たらコストの増大に他ならないが、

 最終的なコストを考えると事前に手をうっておいた方が良いことも多いだろう。

  ※個人的には最終的なコストが例え安く収まらないとしても、

  ※必要経費としてこれらの導入は行うべきだと考える。

 

最後に、テストコードについて少しだけ言及する。

テストコードは、ただ書けば良いというものではないと思っている。

現場で「使えないテストコード」を見かける事が多いが、

これらは二重メンテになるため邪魔な存在でしかないからだ。

 

使えないテストコード

 ・メンテされていなくて動かない

 ・データ依存で、データが少し変わると動かない

 ・クラスを呼ぶだけ(1パターンしかない)

   ※もちろん呼ぶだけでテスト出来るクラスもあるのでそれは例外とする

 

使えるテストコード

 ・可読性が高くメンテしやすい

 ・再利用性が高い(データが変わっても動く)

 ・パターンが網羅されている

 

かく言う自分も、気づけば使えないテストコードを書いていることがある。

実践はなかなか難しい。