2018年以降の記事はGitHub Pagesに移行しました

Windows版Redmineをサービスに登録してブート時に起動させる(宿題あり)

あらすじ

タイトル通り、サービスに登録してよろしく起動してほしい。mongrelを使えばサービスから起動できる……らしいが、名前は聞いたことあるけど、mongrelが何かは知らない……。

Ruby + C(拡張ライブラリ) で書かれた httpd

http://d.hatena.ne.jp/keyword/mongrel

なるほど。

環境

手順

前提
  • Redmineの環境構築が完了している事
    • bundle exec ruby script/server -e production で起動できる事
インストールから起動まで
  • まずはRedmineデフォルトのGemfileにmongrelを追加し、bundle install
gem "mongrel"
$ bundle install
Fetching source index for http://rubygems.org/
Using rake (0.9.2.2)
Using activesupport (2.3.14)
Using rack (1.1.3)
Using actionpack (2.3.14)
Using actionmailer (2.3.14)
Using activerecord (2.3.14)
Using activeresource (2.3.14)
Installing cgi_multipart_eof_fix (2.5.0)
Using coderay (1.0.6)
Installing gem_plugin (0.2.3)
Using i18n (0.4.2)
Installing mongrel (1.1.5)
Using mysql2 (0.2.18)
Using net-ldap (0.3.1)
Using pg (0.13.2)
Using rails (2.3.14)
Using ruby-openid (2.1.8)
Using sqlite3 (1.3.6)
Using tzinfo (0.3.33)
Using bundler (1.0.21)
Your bundle is complete! It was installed into ./vendor/bundle
  • bundle exec ruby ...で起動…しようとするとエラー
msvcrt-ruby18.dll が見つからなかったため、このアプリケーションを開始できませんでした。アプリケーションをインストールし直すとこの問題は解決される場合があります。
$ gem list
...
json (1.5.4)
...
$ gem uninstall json
Successfully uninstalled json-1.5.4
-gem "mongrel"
+gem "mongrel", ">= 1.2.0.pre2"
$ bundle install
...
Installing mongrel (1.2.0.pre2)
  • 起動! 起動した! WEBrickで起動していたのがMongrelに変わった!
=> Booting WEBrick
=> Booting Mongrel

に変わった!

サービスに登録

  • mongrel_serviceをGemfileに登録
gem "mongrel_service"
  • インストールできたらmongrel_railsというコマンドが追加される(今回はbundlerでインストールしたので、Redmineのrootまで行ってbundle exec mongrel_rails)
[C:\redmine-1.4.0]
$ be mongrel_rails
Usage: mongrel_rails <command> [options]
Available commands are:

 - restart
 - start
 - stop
 - service::install
 - service::remove
  • Serviceに追加
オプション 意味
-N サービス名
-c Redmineのルート
-p 起動ポート
-e Railsの起動モード
$ be mongrel_rails service::install -N "Redmine" -c C:\redmine-1.4.0 -p 3000 -e production
** Copying native mongrel_service executable...
Redmine service created.
  • 登録に成功したのでWin+rからservices.mscを呼び出して確認……
  • あった!
    • スタートアップの種類が手動になっていたので自動に変更
  • マシン再起動!

起動しない……だと……?

サービスから起動できなかった
  • Redmineフォルダ内のlogにmongrel.logがあるので見てみると
C:\RUBY_ROOT\bin\ruby.exe: No such file or directory -- C:/RUBY_ROOT/bin/mongrel_rails (LoadError)

うーん。RUBY_ROOTのbin下にmongrel_railsを探しに行ってる? ……でも今回はbundlerで入れたからREDMINE_ROOT/vendor/bundle下を見に行ってほしいんだけどなぁ。

ちょっと試しにbundlerからmongrel, mongrel_serviceをはずして、gemで直接Mongrelをインストールしてみる。

$ gem install mongrel --pre
$ gem install mongrel_service

これで

ということになり、RUBY_ROOTにMongrelがあるので、再起動すればサービスから起動してくれるはず……。

再々起動…起動した!

まとめ
  • 一応、サービスから起動させる事はできた
  • ただし、直接gem installしたものに限る。サービスから起動させるとRUBY_ROOTを見にいってしまうようなのでbundlerで入れるとLoadErrorになってしまう
宿題

mongrel_railsコマンドのオプションとかでbundlerから起動するように変えられないかな?

Fluentdというログ収集ツールを使ってApacheのログを取得するまで

あらすじ

  • Twitterで@tosikawaさんにこんなツールあるよ、と教えてもらった
  • …が、未見だったためすぐググる
  • とりあえずどんなものか動かしてみる事に
Fluentdとは

Log everything in JSON

http://fluentd.org/

Oh...シンプルイズベスト…。

Fluentd is a log collector daemon written in Ruby. Fluentd receives logs as JSON streams, buffers them, and sends them to other systems like MySQL, MongoDB, or even other instances of Fluentd.

Rubyで作られたログ収集ツール。ただし、JSONで……?

環境

手順

とりあえずbundlerで動かしてみるためにGemfileを作成。

$ cat Gemfile
source :rubygems
source "http://rubygems.org"

gem 'fluentd'

インストール。

$ bundle install --path ./vendor/bundle
Fetching gem metadata from http://rubygems.org/....
Fetching gem metadata from http://rubygems.org/....
Installing iobuffer (1.1.2) with native extensions
Installing cool.io (1.1.0) with native extensions
Installing http_parser.rb (0.5.3) with native extensions
Installing json (1.7.3) with native extensions
Installing msgpack (0.4.7) with native extensions
Installing yajl-ruby (1.1.0) with native extensions
Installing fluentd (0.10.24)
Using bundler (1.1.3)
Your bundle is complete! It was installed into ./vendor/bundle

OK。*1

実行

を参考に。

  • 設定ファイルなどのテンプレートを指定先に作ってくれる。
$ bundle exec fluentd --setup ./fluent
Installed ./fluent/fluent.conf.
  • コンフィグファイル指定+traceモードで起動
$ bundle exec fluentd -c ./fluent/fluent.conf -vv &
[1] 12973
2012-07-10 21:37:47 +0900: fluent/supervisor.rb:153:supervise: starting fluentd-0.10.24
2012-07-10 21:37:47 +0900: fluent/supervisor.rb:235:read_config: reading config file path="./fluent/fluent.conf"
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered buffer plugin 'file'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered buffer plugin 'memory'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered input plugin 'exec'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered input plugin 'forward'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered input plugin 'gc_stat'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered input plugin 'http'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered input plugin 'object_space'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered input plugin 'status'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered input plugin 'tcp'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered input plugin 'unix'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered input plugin 'syslog'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered input plugin 'tail'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered output plugin 'copy'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered output plugin 'exec'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered output plugin 'exec_filter'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered output plugin 'file'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered output plugin 'forward'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered output plugin 'null'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered output plugin 'roundrobin'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered output plugin 'stdout'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered output plugin 'tcp'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered output plugin 'unix'
2012-07-10 21:37:47 +0900: fluent/plugin.rb:85:register_impl: registered output plugin 'test'
2012-07-10 21:37:47 +0900: fluent/engine.rb:63:block in configure: adding source type="forward"
2012-07-10 21:37:47 +0900: fluent/engine.rb:63:block in configure: adding source type="http"
2012-07-10 21:37:47 +0900: fluent/engine.rb:79:block in configure: adding match pattern="debug.**" type="stdout"
2012-07-10 21:37:47 +0900: plugin/in_forward.rb:60:listen: listening fluent socket on 0.0.0.0:24224
2012-07-10 21:37:47 +0900: plugin/in_http.rb:74:start: listening http on 0.0.0.0:8888
  • ログを送ってみる
$ echo '{"json":"message"}' | bundle exec fluent-cat debug.test
2012-07-10 21:40:02 +0900: plugin/in_forward.rb:139:initialize: accepted fluent socket object_id=14145560
2012-07-10 21:40:02 +0900 debug.test: {"json":"message"}
2012-07-10 21:40:02 +0900: plugin/in_forward.rb:180:on_close: closed fluent socket object_id=14145560

Apacheのログを集めてみる

集めるログ……自鯖Apacheのログをfluentdで集めてみよう。

  • コンフィグファイルにはじめからコメントアウトされている設定があったので、これを利用
## File input                                                                                                                                 
## read apache logs with tag=apache.access                                                                                                    
<source>
  type tail
  format apache
  path /var/log/httpd-access.log
  tag apache.access
</source>
  • typeにはInput Pluginを指定するらしい。種類はhttp, tail, forward, execなど
  • format(必須)はLogのフォーマットを指定。今回はApacheのログなのでapache
  • path(必須)はLogのパスかな
  • tag(必須)はfluentd内で使うタグ? myapp.accessみたいにドットで分けるらしい

上記の条件にマッチしたものを、今度はmatchタグに従ってoutputしている……のかな?

## match tag=apache.access and write to file                                                                                                  
<match apache.access>
  type file
  path /home/kk_Ataka/log
</match>

では動かしてみよう。

$ sudo bundle exec fluentd -c fluent/fluent.conf

Apacheへアクセス。(Redmineがいるので、Redmineホームにアクセスしてみる)

…。

…。

結果

Apacheの方でいつもどおり作られたログ
xxx.xxx.xxx.xxx - - [10/Jul/2012:22:20:30 +0900] "GET / HTTP/1.1" 200 4371
xxx.xxx.xxx.xxx - - [10/Jul/2012:22:20:30 +0900] "GET /themes/alternate/stylesheets/application.css?1339785657 HTTP/1.1" 304 -
xxx.xxx.xxx.xxx - - [10/Jul/2012:22:20:30 +0900] "GET /javascripts/controls.js?1339785657 HTTP/1.1" 304 -
xxx.xxx.xxx.xxx - - [10/Jul/2012:22:20:30 +0900] "GET /javascripts/effects.js?1339785657 HTTP/1.1" 304 -
xxx.xxx.xxx.xxx - - [10/Jul/2012:22:20:30 +0900] "GET /javascripts/prototype.js?1339785657 HTTP/1.1" 304 -
xxx.xxx.xxx.xxx - - [10/Jul/2012:22:20:30 +0900] "GET /javascripts/dragdrop.js?1339785657 HTTP/1.1" 304 -
xxx.xxx.xxx.xxx - - [10/Jul/2012:22:20:30 +0900] "GET /javascripts/application.js?1339785657 HTTP/1.1" 304 -
xxx.xxx.xxx.xxx - - [10/Jul/2012:22:20:30 +0900] "GET /stylesheets/scm.css?1339785657 HTTP/1.1" 304 -
::1 - - [10/Jul/2012:22:20:36 +0900] "OPTIONS * HTTP/1.0" 200 -

見慣れたもんが出ました。

fluentdで作られたログ
2012-07-10T22:20:30+09:00       apache.access   {"host":"xxx.xxx.xxx.xxx","user":"-","method":"GET","path":"/","code":"200","size":"4371"}
2012-07-10T22:20:30+09:00       apache.access   {"host":"xxx.xxx.xxx.xxx","user":"-","method":"GET","path":"/themes/alternate/stylesheets/application.css?1339785657","code":"304","size":"-"}
2012-07-10T22:20:30+09:00       apache.access   {"host":"xxx.xxx.xxx.xxx","user":"-","method":"GET","path":"/javascripts/controls.js?1339785657","code":"304","size":"-"}
2012-07-10T22:20:30+09:00       apache.access   {"host":"xxx.xxx.xxx.xxx","user":"-","method":"GET","path":"/javascripts/effects.js?1339785657","code":"304","size":"-"}
2012-07-10T22:20:30+09:00       apache.access   {"host":"xxx.xxx.xxx.xxx","user":"-","method":"GET","path":"/javascripts/prototype.js?1339785657","code":"304","size":"-"}
2012-07-10T22:20:30+09:00       apache.access   {"host":"xxx.xxx.xxx.xxx","user":"-","method":"GET","path":"/javascripts/dragdrop.js?1339785657","code":"304","size":"-"}
2012-07-10T22:20:30+09:00       apache.access   {"host":"xxx.xxx.xxx.xxx","user":"-","method":"GET","path":"/javascripts/application.js?1339785657","code":"304","size":"-"}
2012-07-10T22:20:30+09:00       apache.access   {"host":"xxx.xxx.xxx.xxx","user":"-","method":"GET","path":"/stylesheets/scm.css?1339785657","code":"304","size":"-"}
2012-07-10T22:20:36+09:00       apache.access   {"host":"::1","user":"-","method":"OPTIONS","path":"*","code":"200","size":"-"}

自動で全部jsonにparseされている! さすがLog everything in JSONと公式に書いているだけの事はある!

こうなってくると、MongoDBとかの知識も必要になってくるな。

*1:CentOSはこれでよかったんだけど、はじめにWindowsで挑戦したらエラッタ。。

JenkinsでAdmin権限を持つユーザのパスワードを全て忘れた時の復旧方法

あらすじ

  • ローカルで動かしているJenkinsでAdministrator権限を持っているユーザ、およびそのパスワードを忘れたので、色々な事ができなくなった
  • また、Administrator権限を持つユーザがいない = Jenkinsの管理画面が開けなくなった事で権限復旧もできなくなった

環境

  • Windows XP
  • Jenkins 1.470
    • ユーザ情報: Jenkinsのユーザデータベース
    • 権限管理: 行列による権限設定
    • ローカルで運用している
    • JenkinsはWindowsサービスに登録している

原因と解決手順

気づき
  • プラグインを入れようと思ったら、なんでかJenkinsの管理リンクが見当たらなくなった
  • 管理画面のアドレスは /manage なので直にアクセスしてみる
  • Firefoxだとこんなエラーが出た*1
! 内容符号化 (Content-Encoding) に問題があります
  不正または不明な形式で圧縮されているため、ページを表示できません。

 ・この問題を Web サイトの管理者に報告してください。
 [再試行]
  • 試しにChromeでもやってみたがこう
このウェブページにアクセスできません

http://localhost:8080/manage のウェブページは一時的に停止しているか、
新しい http://localhost:8080/manage に移動した可能性があります。

エラー 330 (net::ERR_CONTENT_DECODING_FAILED): 不明なエラーです。
  • まさかのIE6。ログイン画面からレイアウト崩れてて(さすがにサポートしてないよなぁ)とか思いつつアクセスすると…
アクセスできません
kk_Ataka には、Administer パーミッションがありません。

なんだと!? …でも管理画面にいけないんだから、権限も振れないよ。どうしよう。

解決策
  • とりあえず、Jenkinsのディレクトリをユーザ名(kk_Atakaなど)で検索してみた…*2
  • すると引っかかったのはJenkinsのルートにある config.xml と大量の build.xml
    • build.xml は実行したユーザを情報として持っているらしい。が、今回は関係ない
  • config.xml を見てみる
    • authorizationStrategy タグの中に permission タグがあり、ここに hudson.model.Computer.Configure:kk_Ataka みたいに権限を設定してそうな箇所を発見!
    • 同じ設定(ユーザ情報、権限管理など)で安定稼動している他のJenkinsのconfig.xmlと目grepをかけてみる
    • いかにもAdministrator権限を司っていそうな設定を発見! そして、これが書かれていなかった!
<permission>hudson.model.Hudson.Administer:USER</permission>
  • 念のため、サービスからJenkinsをいったん停止し、上記タグを追加後、起動
  • アクセスできた!
最後に
  • 上述の権限管理の所、全体のAdministratorを全てチェック空にすると今回の状況が再現できるらしい(イメージはプロジェクト単位の権限設定)

  • Administrator権限を持つユーザが0のJenkinsって運用的には有りなんだろうか
    • プラグイン増やさない、アップグレードしない場合とかなら有り?
  • 今回の復旧手段はかなり荒業っぽいなぁ
    • 第三者がひょいひょい己にAdministrator権限付加できて良い?
      • Unixとかならファイルのパーミッションとかきちんと設定できるから大丈夫?
      • ローカルならでは?

*1:なので、はじめは格納しているデータが壊れちゃったのかと思った

*2:権限設定などを記載しているファイルがある可能性を願って。

TDD Boot Camp 大阪 1.0( #tddbc ) に参加しました

概要

  • TDD Boot Camp 大阪 1.0( #tddbc ) : ATND
  • なかなかスケジュールの都合がつかず、近場で開催されても参加できないことが多かったので、「次こそは!」と思った矢先の大阪開催だったので参加しました

まとめ

以下、時系列にそったまとめ

TDDのこころ @Takuto Wada (@t_wada) op Twitter さん

BootCampとは
  • 新兵に教官が優しく教える
  • しかしスライドの画像*1は2012年現在もはや厳しい…
今日やること
  • ペアプログラミングを体験してみる
  • コードレビュー大会
    • 同じコードを同僚と解くという機会はほぼない
    • 同じお題を他の人はどう考えるのか、他の言語ではどうなるのか
ふりかえり
  • KPT形式でフィードバック
ソフトウェア開発の三本柱
  • バージョン管理、テスティング、自動化
    • RPGのノーセーブクリア=バージョン管理なしの開発
    • 今コードが動いているのか動いていないのか=テスティング
    • 人間が手作業でやっているものをシェル化、Jenkinsで回したりで機械に任せる=自働化、自動化
      • 機械がうまくいってない時だけ教えてくれる
「テスト」とは
  • 誰が、なんのためにテストをするのかで簡単に分類
    • Developer Testing
      • 開発者が開発促進のため
    • Customer Testing
    • QA Testing
      • 品質保証担当者が品質保証のため
「TDD」とは
  • テスト駆動開発入門 ケント・ベック
  • 動く、きれいなコードへ
    • そこに至るための道へは?
      • きれいな設計をして、それを実装して、それが動作する…きれいな設計とは?
  • 動かすことで初めてわかることがソフトウェア開発にはとても多い
    • なら早く超えよう(ただしここで止まると技術的負債になる)
TDDのサイクル
  • テストを書き
  • テストを実行して失敗させ(Red)
  • 目的のコードを書き
  • テストを成功させ(Green)
  • そのテスト通るまま中を綺麗にしていく(Refactor)
  • これを繰り返す
TDDのやり方
  • 大きな問題は切り分けて1つずつ
  • たくさんの問題も1つずつ
  • 何をテストすればよいのか
    • 開発を進めにくくする要因→何かわからないもの、不安
TDDをすることにより
  • 即座にフィードバックを得る
  • 書いたコードへの自信持つ
  • これから書くコードに自信を持つ
TDDの真の目的
  • 不安の克服
  • 健康
    • コードの健康=仕様変更に対応できる
    • チームの健康=仕様変更に備える事ができる

ペアプロ デモ(FizzBuzz)

  • ゴールから書く!
    • Fizzの場合
      • 何がゴール?
      • Fizzが返る
      • どうなった時Fizz?
      • …としていく
  • テストコードのテストってどうするの?
    • テストコードと実装コードを互いにテストしあう!
      • そのタイミングは実装する前にやってしまう、仮実装してしまう
  • 実際にペアプロのデモを第三者視点で見て、以下のようなことを思った
    • 文化の違いをどう解決していくか
    • 細かなTipsが共有されていく
      • 「xxはyyっていうショートカットで出せますよ」「知らんかった…」
    • ナビゲータって一人で仕事をしているときはやる事がないので結構難しそう…

ペアプロ

  • Ruby島は4人でした
  • お題はこれ。結構複雑 TDD Boot Camp(TDDBC) - TDDBC大阪1.0
  • テーブルにバリバリ使ってるぜ! という人がいなかったのでどう組もうかー相談していたら、なんとよしおかさんと関さんが「Ruby席に混ぜて」という状況に
    • 恐れ多くも関さんとペアプロさせて頂く事態に((((;゜Д゜)))
  • RSpecでどうテスト書こうかというところで、どういう単位でテストを作るかのような話になり、色んな書き方があるのだなと感じました。
    • 僕は「小さい自前のスクリプトに対してのテスト」くらいの使い方しかしていなかったから一個一個の振る舞いに対して1つずつit "〜できる、it "〜する"と実装していこうと考えていた
    • 対して、関さんは一つのテストをシナリオで考えていたので、はじめにこうしてこうやって最後にこうという感じ

昼休み

  • 楽天デリバリによるお弁当サービス
    • 結構種類が豊富だった

昼休み2 実際の事例(和田さんの午前セッションの続き)

  • TDDを採用したときのTDDを採用していない類似プロジェクトと比較
    • 例えばIBM、15%~20%くらいテストコードのための実装時間が増えたが、4割くらい欠陥が減った
    • Visual Studioがすごい!欠陥密度0.09
  • テストコードを書く時間は増えるが、軽微なミスが減るため、デバッグの工数は減る→トータルで開発工数を減らす事ができると考えられる

午後の部開始 QA

  • テストメソッドの名前はどうやって考えているか
    • 日本語で書いている、英語の場合はxx is … when …
  • テスト名のテストの中身が重複していたらDRY的にはどう?
    • RSpecの場合構造だけでテストの意味がわかるようにしている
    • 入れ子構造で意味がわかるようにするのが最近のテストのトレンド
    • 状況は詳しく書くけど何をの部分はサッパリと書く
    • enclosed
  • プライベートメソッドのテストをしたい…
    • プライベートメソッドはパブリックメソッド経由でテストできるはずなので、プライベートメソッドをテストしたいといっている時点で設計がおかしい

開発者の皆さん、テストを書こう よしおかさん

事例 Oracle8の開発現場
  • 95年~2000年
  • Sun Workstation〜
  • ファイルの仮想化、一人で複数のブランチを持てる
  • 開発プロセス
    • 開発者は要求を自分で定義する
      • リファレンスマニュアルのベース
    • 設計する
    • 実装する
    • デイリービルド、リグレッションテスト
    • 安定化プロセス
    • コードフリーズ(重大なバグ以外変更しない)
  • プログラマ
    • 設計者が実装者でテスタ
      • 一つの機能に関して世界で一番知ってる
  • デイリービルド
  • リグレッションテスト
  • 安定化プロセス
    • バグ修正だけ
    • バグや不具合はリリースノートに
  • 学んだこと
    • デイリービルドによって常に動作が確認できる
事例2 DEC Rdb
  • 米国で開発されたソフトウェアを日本語へ
  • ソフトウェア国際化のあるべき姿の議論
事例3 日本語COBOL
  • チェックインの数やバグの数、修正済みバグの数を手書きで書いていた
  • 新人(よしおかさん)のしつけ
    • 「プログラム書きました」「チェックインした?」「あ、してません」「」など
  • デバッグの仕方、質問の仕方も教わった
Samba3.0国際対応
  • 2.xから3.0での日本語の問題
  • テストをどんどん作ってバグを登録しまくり、コミュニティに入り込んでいった
  • 小さいパッチをちょこちょこと
  • OSSでもテストファーストで出来た

ペアプロ午後の部

  • 後ほど発表があるということで関さん離脱。ありがとうございました
    • なんとバトンタッチは和田さん((((;゜Д゜)))
  • 和田さんが午前中に書いていたテストをガンガン洗練させていく!
    • 黄金の回転で一番難しいと思っているRefactorの部分を間近で見ているのでマジでためになる!
  • 今回教えて頂いたのはitの中は簡潔になるように心がけるというもの
    • テストのための準備をbeforeで書く!
    • contextでは「この時、これを確認、これを確認」レベルで済ませるように書く。
      • contextの中身はlet, its, itsで!
  • という事らしい。確かに見やすい
  • これで、他の状態の時にこうあるべきというのも一行追加でいける
describe "投入金額に注目" do
    before do
      @vending = Vending.new
      @change = @vending.enter(input)
    end
    subject { @vending }

    context "だめな硬貨だけのとき" do
      let(:input) { [1,5,2000] }
      it { @change.should == [1,5,2000] }
      its(:show) { should == 0 }
    end

    context "1000円札を入れたとき" do
      let(:input) { [1000] }
      it { @change.should == [] }
+     its(:show) { should == 1000 } #この状態の時にも
    end

レビュー

  • C++, C#, Groovyのチーム
    • 他の言語でこうやってますとあったものがRSpecで出来るか

TDDとは 関さん@seki at druby.org (@m_seki) op Twitter

  • XP10年
  • The dRuby Book
  • Legendary Japanese Ruby hacker
TDDのおさらい
  • 今日楽しかった?
TDDのサイクル
  • 次の目標を考える
  • その目標を示す
  • 黄金の回転…
    • これを繰り返す
TDDはなんだっけ
  • テストによって導かれた開発の事
  • 今日のは実装例の一つかも
TDDの変形
  • 何かを引く
    • xUnitを引いてみる、どうなるか
      • すぐに準備出来ない複雑なUIなど
    • 顧客テストをxUnitなしで
      • JaSST'04
      • 毎日増えるテストを毎日飛び越える(忍者の修行)
  • 何かをたす
もうひとつのテスト
  • Checking
    • 既知の情報の確認
  • Testing
    • 新しい情報、未知の情報を探す
ご提案
  • Red Green Refactor
    • ちょっとずつ仮設の上に仮設を重ねる
  • Destroy
    • この実装ならバグが出るだろみたいなのを
    • たまに破壊的な思考を持ち込む

QA

  • assertなんとかの効率的な探し方
  • レガシーコードに対するTDD
    • レガシーコード改善ガイドおすすめ
    • 外側から攻める。Sambaの時はそうやった(よしおかさん)
  • 荒い粒度のテストとは
    • 画面に近いところ、とか入出力とか
    • 単体テストやりにくいテスト(レガシーコード)にたいしてやりやすい表面から攻めていく
  • テストの期待値を作るのに困ったこと
  • TDDの文化がないところでどう根付かせるか
    • 毎日テストが僕らを守ってくれると提唱した
    • まずは自分から、自信をつけてから広めよう
KPT
  • 会場よかった
  • 会場盛り上がってた
  • TDD体験できてよかった
  • ペアプロも体験できてよかった
  • TAがたくさんいて聞きやすかった
  • Groovy
  • 知らない言語のテストコード、フレームワークを見れてよかった
  • 社内に広める自信がついた>Groovy?
  • Groovy楽しかった
  • Vimに詳しくなった
  • Groovyいいよ
    • などなど

Groovy人気がすごい。

終わりに 和田さん

  • ペアプログラミングをやってテストのサイクルを回す
  • コードレビュー大会
    • 「あの言語でこんな事出来るんだ」発見→「俺の言語でもできんじゃん!」
  • 黄金の回転
    • 各象限を越えるときの心持ち
  • 本をたどる
  • 2人目がいないので広めるのに心が折れちゃう
    • まず一人でやって見せて背中を見せる
  • 量は質に転化する

そして懇親会へ…

  • ピザが一瞬でとけた

Jenkins,Redmine使いこなし勉強会に参加しました と、ちょっとプラグイン作ってみた #jen_red

概要

前半は発表のメモ。後半は実際にプラグイン作ったりインストールしたりのメモ。

Redmineプラグイン活用入門 - @Kokawa Takashi (@Kokawa_Takashi) op Twitterさん

注意:Redmine開発環境が安定していないので、すぐ陳腐化してしまう事がある!

Redmineにおける問題
  • Redmineの設定で解決
  • 運用で解決
  • ツール自体を拡張して解決
    • プラグインの探し方・おすすめ
    • REST APIを使って外部から
    • プラグインを作る
プラグインの探し方・おすすめ
  • Redmineプラグイン集 - r-labs
  • Plugins - Redmine
  • 一つだけおすすめを… Wiki Extensions Plugin
    • オートプレビュー
    • 任意のページをメニューに
    • 任意のページを埋め込み 等々…
  • 他のおすすめ
    • CodeRevirew
    • Backlogs
    • TimeTracker
REST API
  • 自動でチケットを作ったりできる
  • チケット一覧を取得できたり
  • この一連の流れができたらJenkinsに任せる事ができる
    • 期日が間近のチケットのメール通知などもできる
プラグインを作る
  • Redmine1.4 or 2.0が対象(Ruby1.9,Bundler対応している/これ以前はしていない)
  • プラグイン開発環境構築がつらいので
Ruby環境
Redmineインストール
bundle install -without development test rmagick -path vendor/bundle
Rubyデバッグ環境
  • ruby-debug-ide…だがこの環境ではうまく動かなくなってしまった
  • ruby-debug-base19が必要らしいが、そのまま落としてきても動かない
    • preオプションを入れる
gem install ruby-debug-base19 --pre
gem install ruby-debug-ide --pre
NetBeans
  • ただし、公式サポートは6.9.1が最終
一つだけシンプルなプラグインを
  • Redmineのメニューからヘルプを消す
  • スケルトンを作ってinit.rbに一文足すだけ
    • 最後に試してみるよ

Jenkinsプラグイン活用入門- @さぼてん(さぼ福)しんざき 佐藤太一 (@cactusman) op Twitterさん

Jenkinsとは
  • 高性能Cron
プラグインの探し方
  • 探す前に…
  • shやbatなどをうまく組み合わせられないかなどをまず考える
  • Jenkins自体の昨日もうまく使う
  • プラグイン自体は本家に登録されている
  • Jenkins Plugin Hub
    • ソフト、ツール名などでとりあえず引っ掛けてみる
プラグインの使い方
  • すごくメンテされているものとほったらかされているものでまちまち
  • コミットやDL数を見てみる
  • TackScanerPlugin
    • キーワードを拾う(TODOなど)
    • 最後に入れてみる
  • DickUsagePlugin
    • Jenkinsのディスク使用量を見る
  • JobConfigHistoryPlugin
    • 設定ファイルのバックアップ、差分表示
プラグインのハック
  • エクステンションポイントを継承する
    • Notifierを継承すれば通知系の事ができる
  • mvnにおまじないを追加する
  • Jenkinsの公式Pluginが参考になる

実際にやってみる(Redmine)

メニューの一部を消してみる。

環境
手順
  • はじめにRedmine Pluginのスケルトンを作成する。名前はdelete_menuとした
$ cd REDMINE_ROOT
$ ruby script\generate redmine_plugin delete_menu
./script/../config/../vendor/rails/railties/lib/rails/gem_dependency.rb:119:Warning: Gem::Dependency#version_requirements is deprecated and will be removed on or after August 2010.  Use #requirement
      create  vendor/plugins/redmine_delete_menu/app/controllers
      create  vendor/plugins/redmine_delete_menu/app/helpers
      create  vendor/plugins/redmine_delete_menu/app/models
      create  vendor/plugins/redmine_delete_menu/app/views
      create  vendor/plugins/redmine_delete_menu/db/migrate
      create  vendor/plugins/redmine_delete_menu/lib/tasks
      create  vendor/plugins/redmine_delete_menu/assets/images
      create  vendor/plugins/redmine_delete_menu/assets/javascripts
      create  vendor/plugins/redmine_delete_menu/assets/stylesheets
      create  vendor/plugins/redmine_delete_menu/lang
      create  vendor/plugins/redmine_delete_menu/config/locales
      create  vendor/plugins/redmine_delete_menu/test
      create  vendor/plugins/redmine_delete_menu/README.rdoc
      create  vendor/plugins/redmine_delete_menu/init.rb
      create  vendor/plugins/redmine_delete_menu/lang/en.yml
      create  vendor/plugins/redmine_delete_menu/config/locales/en.yml
      create  vendor/plugins/redmine_delete_menu/test/test_helper.rb
  • vendor/pluginにredmine_delete_menuというフォルダができている
$ ls
...
redmine_delete_menu/
...
$ cd redmine_delete_menu
$ ls
README.rdoc assets/     db/         lang/       test/
app/        config/     init.rb*    lib/
  • init.rbに例の一文を挿入
 Redmine::Plugin.register :redmine_delete_menu do
   ...
   
+  delete_menu_item :top_menu, :help
 end
  • そして起動
$ cd REDMINE_ROOT
$ ruby script\server -e production
=> Booting WEBrick
=> Rails 2.3.5 application starting on http://0.0.0.0:3000
./script/../config/../vendor/rails/railties/lib/rails/gem_dependency.rb:119:Warning: Gem::Dependency#version_requirements is deprecated and will be removed on or after August 2010.  Use #requirement
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2012-05-28 19:15:50] INFO  WEBrick 1.3.1
[2012-05-28 19:15:50] INFO  ruby 1.8.7 (2010-12-23) [i386-mswin32]
[2012-05-28 19:15:50] INFO  WEBrick::HTTPServer#start: pid=4640 port=3000
環境その2

Ruby1.9、Redmine1.4でもやってみるかー。

手順その2
  • いきなりgenerateしようとしたらbundle installしろと言われた
$ ruby script\generate redmine_plugin delete_menu
Some gems may need to be installed or updated.
Please run `bundle install --without development test`.
  • なのでbundle install
$ bundle install --without development test --path ./vendor/bundle
Fetching source index for http://rubygems.org/
Installing rake (0.9.2.2)
Installing activesupport (2.3.14)
Installing rack (1.1.3)
Installing actionpack (2.3.14)
Installing actionmailer (2.3.14)
Installing activerecord (2.3.14)
Installing activeresource (2.3.14)
Installing coderay (1.0.6)
Installing i18n (0.4.2)
Installing mysql2 (0.2.18)
Installing net-ldap (0.3.1)
Installing pg (0.13.2)
Installing rails (2.3.14)
Installing rmagick (2.13.1) with native extensions
  • rmagickが入らず止まりっぱなし……そういえば、rmagickは使わなければwithoutしてしまってもいいです的な事を言われていた気がするのでそれをプラス
$ bundle install --without development test rmagick --path ./vendor/bundle
Fetching source index for http://rubygems.org/
Using rake (0.9.2.2)
Using activesupport (2.3.14)
Using rack (1.1.3)
Using actionpack (2.3.14)
Using actionmailer (2.3.14)
Using activerecord (2.3.14)
Using activeresource (2.3.14)
Using coderay (1.0.6)
Using i18n (0.4.2)
Using mysql2 (0.2.18)
Using net-ldap (0.3.1)
Using pg (0.13.2)
Using rails (2.3.14)
Installing ruby-openid (2.1.8)
Installing sqlite3 (1.3.6)
Installing tzinfo (0.3.33)
Using bundler (1.0.21)
Your bundle is complete! It was installed into ./vendor/bundle
  • 再度。先ほどbundlerを使ったのでbundle exec
$ bundle exec ruby script\generate redmine_plugin delete_menu
C:/redmine-1.4.0/vendor/bundle/ruby/1.9.1/gems/activesupport-2.3.14/lib/active_support/inflector.rb:3:in `<top (required)>': iconv will be deprecated in the future, use String#encode instead.
NOTE: Gem.source_index is deprecated, use Specification. It will be removed on or after 2011-11-01.
Gem.source_index called from C:/redmine-1.4.0/vendor/bundle/ruby/1.9.1/gems/rails-2.3.14/lib/rails/gem_dependency.rb:21.
NOTE: Dependency.new w/ a regexp is deprecated.
Dependency.new called from C:/redmine-1.4.0/vendor/bundle/ruby/1.9.1/gems/rails-2.3.14/lib/rails_generator/lookup.rb:211
NOTE: Gem.cache is deprecated, use Gem::source_index. It will be removed on or after 2011-08-01.
Gem.cache called from C:/redmine-1.4.0/vendor/bundle/ruby/1.9.1/gems/rails-2.3.14/lib/rails_generator/lookup.rb:212.
NOTE: Gem.source_index is deprecated, use Specification. It will be removed on or after 2011-11-01.
Gem.source_index called from C:/rubies/Ruby-193-p0/lib/ruby/1.9.1/rubygems.rb:1154.
NOTE: Gem::SourceIndex#search is deprecated with no replacement. It will be removed on or after 2011-11-01.
Gem::SourceIndex#search called from C:/redmine-1.4.0/vendor/bundle/ruby/1.9.1/gems/rails-2.3.14/lib/rails/vendor_gem_source_index.rb:119.
NOTE: Gem::SourceIndex#search is deprecated with no replacement. It will be removed on or after 2011-11-01.
Gem::SourceIndex#search called from C:/redmine-1.4.0/vendor/bundle/ruby/1.9.1/gems/rails-2.3.14/lib/rails/vendor_gem_source_index.rb:119.
NOTE: Gem.cache is deprecated, use Gem::source_index. It will be removed on or after 2011-08-01.
Gem.cache called from C:/redmine-1.4.0/vendor/bundle/ruby/1.9.1/gems/rails-2.3.14/lib/rails_generator/lookup.rb:234.
NOTE: Gem.source_index is deprecated, use Specification. It will be removed on or after 2011-11-01.
Gem.source_index called from C:/rubies/Ruby-193-p0/lib/ruby/1.9.1/rubygems.rb:1154.
NOTE: Gem::SourceIndex#each is deprecated with no replacement. It will be removed on or after 2011-11-01.
Gem::SourceIndex#each called from C:/redmine-1.4.0/vendor/bundle/ruby/1.9.1/gems/rails-2.3.14/lib/rails/vendor_gem_source_index.rb:123.
NOTE: Gem::SourceIndex#each is deprecated with no replacement. It will be removed on or after 2011-11-01.
Gem::SourceIndex#each called from C:/redmine-1.4.0/vendor/bundle/ruby/1.9.1/gems/rails-2.3.14/lib/rails/vendor_gem_source_index.rb:124.
      create  vendor/plugins/redmine_delete_menu/app/controllers
      create  vendor/plugins/redmine_delete_menu/app/helpers
      create  vendor/plugins/redmine_delete_menu/app/models
      create  vendor/plugins/redmine_delete_menu/app/views
      create  vendor/plugins/redmine_delete_menu/db/migrate
      create  vendor/plugins/redmine_delete_menu/lib/tasks
      create  vendor/plugins/redmine_delete_menu/assets/images
      create  vendor/plugins/redmine_delete_menu/assets/javascripts
      create  vendor/plugins/redmine_delete_menu/assets/stylesheets
      create  vendor/plugins/redmine_delete_menu/lang
      create  vendor/plugins/redmine_delete_menu/config/locales
      create  vendor/plugins/redmine_delete_menu/test
      create  vendor/plugins/redmine_delete_menu/README.rdoc
      create  vendor/plugins/redmine_delete_menu/init.rb
      create  vendor/plugins/redmine_delete_menu/config/locales/en.yml
      create  vendor/plugins/redmine_delete_menu/test/test_helper.rb
  • deprecateがやまほど出たけど、一応スケルトンは作れたみたい。で、init.rbを編集。ここは同じ
 Redmine::Plugin.register :redmine_delete_menu do
   ...
   
+  delete_menu_item :top_menu, :help
 end
  • で、起動。ここでもbundle exec
$ bundle exec ruby script\server -e production
C:/redmine-1.4.0/vendor/bundle/ruby/1.9.1/gems/activesupport-2.3.14/lib/active_support/inflector.rb:3:in `<top (required)>': iconv will be deprecated in the future, use String#encode instead.
=> Booting WEBrick
=> Rails 2.3.14 application starting on http://0.0.0.0:3000
NOTE: Gem.source_index is deprecated, use Specification. It will be removed on or after 2011-11-01.
Gem.source_index called from C:/redmine-1.4.0/vendor/bundle/ruby/1.9.1/gems/rails-2.3.14/lib/rails/gem_dependency.rb:21.
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2012-05-28 20:03:32] INFO  WEBrick 1.3.1
[2012-05-28 20:03:32] INFO  ruby 1.9.3 (2011-10-30) [i386-mingw32]
[2012-05-28 20:03:32] INFO  WEBrick::HTTPServer#start: pid=3248 port=3000

1.4台でもいけた!

実際にプラグインを入れてみる(Jenkins)

Task Scanner Pluginを入れてみよう。

環境
手順
  • Jenkinsの管理 => プラグインの管理 => 利用可能タブ => Task Scanner Pluginをチェックしインストール
    • Static Code Analysis Plug-insも同時にDLされるみたい
  • 再起動
  • Jenkinsプロジェクト => 設定 => ビルド後の処理 => 未解決タスクの集計*1にチェック
    • 集計対象: source/*.rst
      • 今回はSphinxのドキュメントソース内のTODOを拾うので
    • 集計対象外: source/*.py
      • conf.pyなどは除外する
    • タスクタグ 優先度 Normal: //TODO
      • ドキュメント内の//TODOを探してもらう。優先度は適当
    • 高度な設定を開きデフォルトのエンコーディング: UTF-8
  • 保存してビルド
  • 一度ビルドするとJenkinsプロジェクトのメニューに【未解決タスク】のリンクが表示される
    • 今回設定した//TODOがまとめられてる!
    • 後、//TODO hogehogeとキーワードの後ろに何か書いておくとメッセージとしてどんなTODOなのかも表示される!

*1:ローカライズされてた

SlideShareのAPIを叩いてスライドをDLするRubyスクリプトをHerokuにデプロイした

あらすじ

slideshareを社内から閲覧する事を禁じられているので、ワンクッションおいてスライドのpptを落とせるようにしたい

参考サイト

とりあえず公式サイトを抑えておけばいけそう。

流れ

API申請
  • slideshare -> Developer & APIのページからApply for API keyに移動
  • ログイン or 新規アカウント作成
  • Name、E-Mail、How do you want to use the API?を入力し送信。頑張って英文書く。
I want to get slideshare's slide from API.
  • 送信されたメールに貼られているAPI KeyShared Secretを控える
パラメータ
  • slideshare -> Documentationを見ながら必要なパラメータを調べる
api_key さっきのAPI Key
ts タイムスタンプ*1
hash さっきのShared Secretとこれから取得するtsでハッシュを作る*2
(username) 登録ID
(password) パスワード

全然関係ないけど、Documentationのページ内にあるi.e.って単語を初めて見たのでググってみた。論文中の「e.g.」「i.e.」の意味は何? - Diary@一色政彦WebSite that is ... すなわちとかそういう意味らしい。e.g.で例えば、for example的な。

ソース

ソースはこんな感じ。

require 'openssl'
require 'uri'
require 'net/http'

url = 'http://www.slideshare.net/api/2/get_slideshow'
param = Hash.new
param["slideshow_url"] = 'http://www.slideshare.net/gishi/wicket-presentation'
param["api_key"] = 'XXXXXXXX'
param["sharedsecret"] = 'XXXXXXXX'
# ts
param["ts"] = Time.now.to_i.to_s
# hash
param["hash"] = Digest::SHA1.hexdigest(param["sharedsecret"]+param["ts"])

uri = URI.parse(url)
Net::HTTP.new(uri.host).start do |http|
#Net::HTTP.new(uri.host, 80, ENV["PROXY"], 8080).start do |http|
  uri_param = param.sort.map {|i|i.join('=')}.join('&')
  
  res = http.get(uri.path + '?' + uri_param)
  puts res.body
end

成功するとこんな感じの内容が返ってくる。

<?xml version="1.0" encoding="UTF-8"?>
<Slideshow>
  <ID>579496</ID>
  <Title>Wicket&#20307;&#39443;&#35527;</Title>
  <Description>&#31532;1&#22238;Wicket&#21193;&#24375;&#20250;&#12398;&#12521;&#12452;&#12488;&#12491;&#12531;&#12464;&#12488;&#12540;&#12463;&#30330;&#34920;&#36039;&#26009;</Description>
  <Status>2</Status>
  <Username>gishi</Username>
  <URL>http://www.slideshare.net/gishi/wicket-presentation</URL>
  <ThumbnailURL>http://cdn.slidesharecdn.com/wicket-1220375587470160-8-thumbnail</ThumbnailURL>
  <ThumbnailSmallURL>http://cdn.slidesharecdn.com/wicket-1220375587470160-8-thumbnail-2</ThumbnailSmallURL>
  <Embed>&lt;div style=&quot;width:425px&quot; id=&quot;__ss_579496&quot;&gt;&lt;strong style=&quot;display:block;margin:12px 0 4px&quot;&gt;&lt;a href=&quot;http://www.slideshare.net/gishi/wicket-presentation&quot; title=&quot;Wicket&#20307;&#39443;&#35527;&quot;&gt;Wicket&#20307;&#39443;&#35527;&lt;/a&gt;&lt;/strong&gt;&lt;object id=&quot;__sse579496&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=wicket-1220375587470160-8&amp;stripped_title=wicket-presentation&amp;userName=gishi&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;/&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot;/&gt;&lt;param name=&quot;wmode&quot; value=&quot;transparent&quot;/&gt;&lt;embed name=&quot;__sse579496&quot; src=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=wicket-1220375587470160-8&amp;stripped_title=wicket-presentation&amp;userName=gishi&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; wmode=&quot;transparent&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style=&quot;padding:5px 0 12px&quot;&gt;View more &lt;a href=&quot;http://www.slideshare.net/&quot;&gt;presentations&lt;/a&gt; from &lt;a href=&quot;http://www.slideshare.net/gishi&quot;&gt;Hiroto Yamakawa&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;</Embed>
  <Created>Tue Sep 02 10:14:12 -0500 2008</Created>
  <Updated>Tue Sep 02 10:16:15 -0500 2008</Updated>
  <Language>ja</Language>
  <Format>ppt</Format>
  <Download>1</Download>
  <DownloadUrl>http://s3.amazonaws.com/ppt-download/wicket-1220375587470160-8.ppt?response-content-disposition=attachment&amp;Signature=ABs151smgWZ9213%2FyFq81fnMc6A%3D&amp;Expires=1328606581&amp;AWSAccessKeyId=AKIAJLJT267DEGKZDHEQ</DownloadUrl>
  <SlideshowType>0</SlideshowType>
  <InContest>0</InContest>
</Slideshow>

おー取れた。んで、xmlの中のDownloadUrlからpptをゲットできた! これをSinatraでWebアプリケーションにしてHerokuにデプロイすれば職場から行けるかな!?

→いけた! 自分の中ではお役立ち。

*1:Set this to the current time in Unix TimeStamp format, to the nearest second(?).

*2:Set this to the SHA1 hash of the concatenation of the shared secret and the timestamp (ts). i.e. SHA1 (sharedsecret + timestamp). The order of the terms in the concatenation is important.

BPStudy#57に参加しました #bpstudy

詳細: BPStudy#57 - connpass

  • 例の特許庁最適化計画プロジェクトを通してITビジネスの仕方を変えよう

というなかなかに興味深い内容だったので参加。

第一部 新たな価値観へのITビジネス視点での転換 萩本順三さん

  • 政治的な話は無し
  • 私が技術顧問として最適化計画を見た時、「古いな〜」と思った
    • 問題があるプロジェクトに入り込んで、どうするかというのが仕事
      • 火を吹いた時に入り込んでいく => はじめにオフィスへ入り込んで資料を見た時「これやめないんですか?」と聞いたほど
  • かなりはじめの段階からダメと周りの人にも言っていたが……
何が問題か?
  • 技術を特許庁の業務にどう活かすかの具体性がない
    • xml使ったからどうなんの?
  • 業務モデルを1000名で書いてどうすんの?
  • むしろ主役は特許庁なのでは? => 放り投げ主義
  • 業務モデルは発注者の理解と覚悟の元作成するはずなのに!
根底の問題は?
  • IT業界の負のビジネス慣習
    • ユーザ、開発両者のスキル不足
      • お客さんに教えながらモデル化をしていくものなのに
  • コスト配分が開発者寄りになり、たとえいいものを作ったとしてもユーザさんが使いこなせない
  • うまく要件を引き出せないと、正しくないシステムができてしまう
  • 是正しなければ
意識改革 コタツモデル
  • ユーザから話を聞いてシステム開発に入るが、ユーザは必ず正しいのか
  • 以下の3つから"将来"の価値を取りに行く視点を持つ
    • 戦略的視点(偉い人)
    • 業務問題解決の視点(業務担当の偉い人)
    • IT活用の視点(開発の出来る人)
  • しかし、偉い人は現在の価値を取りに行きがちだし、業務担当の偉い人は業務問題解決の視点しか持っていないことが多い
  • 戦略的視点から業務解決、IT活用をしていくと、偉い人も「あ、俺業務知らなかったな」と感じで同じコタツに入ってくれる => 要求が収束する
  • Howの手探り
    • ビジネス戦略から
  • Howの突き上げ
    • テクノロジーを使うともしかしたら業務がいらなくなるかもしれない => 戦略に結びつける
  • 最適化
    • 切ってつなげて並行でスピーディに走らせる
  • 常に価値で問う
    • 設計ドキュメントなどは誰に対して価値があるのかを問う。説明できなければいらないじゃない?(ただし、技術的に説明できない場合もある)
  • 自分が持っている知識をお客さんに魅力的に見えるものとする
  • 自分のやりたいこと(How)を実現していこう(What)
    • 自動車メーカ、ファッション業界ではできているのになぜソフトウェア業界でできない
    • システム要求の牢屋に閉じ込められていたらできっこない
5年後のIT業界
  • 巨大システムの開発(一枚岩)からアクセサリ化に
    • コーディネート化する必要がある
    • 開発者が一番強い。なぜならHowを握っているから
  • ピラミッド型組織から分散自立型組織に
    • 優秀な人は残して優秀じゃない人は返す、返された人は価値に敏感になれるように
  • 学び、勇気を持って行動してください

第二部 執筆プロジェクトの継続的ビルド @shimizukawaさん、@cactusmanさん

この本はSphinxで書きました
  • 執筆はreST
  • 社内レビューはhtml
  • 社外レビューはpdf
    • 見た目を自由に変えられる
    • 見た目を変えると誤記などに気づける
編集さんに提出
  • 執筆者から編集さん(秀和システム)に渡すときに、秀和システムさんのフォーマットに合わせる必要がある
    • Sphinxで要求されたフォーマットでビルドする(作るのに2日かかったが使いまわせるかなと思ったのでまあいいかな?)
  • が、結局お蔵入りに
まとめ
  • 提出現行の明確な仕様を決めておけばよかった
  • 編集と差分管理しやすいテキストで
  • レビュは別のビューで
  • 環境は自動化で
Jenkins
  • Jenkinsのプラグインで文中のTODOを拾える
    • TODOの状態がグラフでわかる!

■■のススメ @urasokoさん

  • 以前高橋メソッドを使いLTで10分、今回は5分を切る
  • SIer(大規模)につとめ、普段は調整等のお仕事をしていた……が、4/末日に「選職」しました
    • 「小さなチーム、大きな仕事」に感銘を受けた
    • 社会に何を求めるか、どうありたいか、何を成したいか
    • 会社の上でではなく、社会の上で選び続ける
    • 作りたいのは技術集団なのか、役人集団なのか
  • 結局LTは10分近く……

懇親会で萩本さんから、「御社の偉い人にも今回と同じような話する機会があったよ、結構感銘を受けてた(意訳)」と聞き衝撃を受けた。多分ホントにエライ人しかしらないんじゃないかなぁ。

ともあれ、萩本さんがFacebookで要求開発アライアンスの資料も公開(要求開発の発展と展開、そして課題)されています。BPStudyの資料もアップされるとの事だった。これ読んで下から突き上げてみようかなぁ。