upinetree's memo

Web系技術の話題や日常について。

転職します

今月中旬にSIerを退職します。新卒で入社してから今まで2年半、あっという間でした。

今度は神保町でWeb系のお仕事する予定です。皆さま、よろしくお願いします。

転職エントリ、知らないおじさんが「で、誰?」って言いに来るイメージあるのでこわかったのですが、同じ状況の人と共有できたら素敵だなって思ったので書くことにしました。

なぜ?

端的に言えば、技術者として楽しく、アジャイルに働きたかったからです。 その上で、興味のあった分野がWebで、Rubyでした。

労働時間やSI業界的な問題に関してはよくある話と大体同じです。 でもここでは不満はあんまり書きません。 ただ、疲れ果て、好きだったプログラムも書かなくなってしまった時期もありました。

以下、転職までに何をしてどう判断したか書きます。

出会い

幸いにも、僕は出会いに恵まれていました。

社内アジャイルコミュニティとの出会いがきっかけで、 アジャイルサムライという素晴らしい書籍を読み、 ようやく自分のやりたいことと向き合う気になりました。

そこで3年という期限を設けて、自分がどう進むすべきか決めることにしました。

そして、勉強会文化、Rubyコミュニティと出会います。

技術が好きで、自主的に組織しているコミュニティがあり、 そこで集まっている人々がとても楽しそうにしている。 目の当たりにして衝撃をうけるとともに、僕の周りにもこんなコミュニティが欲しいと思いました。

※社内アジャイルコミュニティには所属していたが、僕は新潟の支社におり、距離的な制約があった

やったこと

ということで、新潟支社内でアジャイル勉強会を立ち上げることにしました。 せっかくなので支社全体に通知。この立ち上げには、下記のような狙いがありました。

  • 新潟で仲間を作りたい
  • 自分がやりたいことを発信することで、自分の立場、環境を変えたい
  • 自分と同じ事に興味を持っている人がどのくらいいるか知りたい

とはいえ、最初からうまくいくはずもなく、ひとりぼっちで心が折れそうなときもありました。 でも続けているうちに、徐々に仲間になってくれる人や、助けてくれる人が出てきてくれました。 LT大会したり、本社とリモートで勉強会をやったり、TDDワークショップしたり、色々な試みもできて楽しかったです。

お得だったのは、自分の名前が広く知られたことです。 懇親会で知らない人の集まるテーブルに座っても、「あー、アジャイルの人かー」って感じで自己紹介の手間が省けました。

また、プロジェクトチームにも勉強会で得られたものをフィードバックしました。 朝会やタスクボード、ふりかえり等を、チームの特性に合わせて取り入れてみました。

わかったこと

以上のような試みを続けてみて、自分の環境は少し変わりました。 抱えていた不満は相変わらずでしたが、前より居心地が良くなりました。

わかったのは、自分の立場や環境は自分で変えることができるということです。 もちろんコントロールできる範囲には限りがあります。でも、愚痴だけ言って腐るよりはマシです。

一方で問題なのは、変える内容によっては、とても長く時間がかかるということです。

とりわけ、僕がやりたかった「技術者として楽しく、アジャイルに働く」ことを実現するには、ずっと地道な活動を続けなければならなそうでした。 制度や人事上の関係もあり、社内政治的な手続きが必要となります。 そのためにはコントロールできる範囲を地道に増やすしかない。

もしそれらをクリアした時、僕は技術者としてどんな立場にいられるのか? もしかしたらコードを書ける立場にないかもしれません。それでは本末転倒です。

そもそも、僕の目的は会社を変えることではないのです。なので、勇気を出して外に飛び出すことにしました。 そしてありがたくもご縁があって、次の職場で働くことになりました。

※勇気を出せたのにも色々な理由がありましたが、長くなるので別の機会に

まとめ

偉そうに長々と書きましたが、実際は悩んで死にそうになってた時期もありましたし、技術者としても未熟極まりないです。後者は本当に反省すべき。

でも、もし僕と同じように悩んでいる方がいれば、まずできることから始めてみて欲しいと思うのです。 始めてみれば、何かが少し変わるはずです。一方で、すぐには変えられないことも明らかになります。その状態をどのくらいの期間許容出来るか、もひとつの判断の指針になるはずです。

そして大事なのは、自分で行動したことによって、結果的にどういう選択をとるにしてもそれを納得できるようになることだと思います。

以上、転職エントリでした。

Happy working :)

長岡でScalaに入学した

9/28に新潟県長岡市でScala入学式に参加しました。 長岡IT開発者勉強会(#NDS33)の一環として開催されたハンズオン形式の勉強会です。 id:nkgt_chkonkさんが講師をしてくれました。

ScalaはおろかJavaすら普段いじってないレベルだったので不安でしたが、やってみるととてもおもしろかったです! 以下、簡単にレポートします。

ちなみに、資料はこちらにアップされています。

https://gist.github.com/Shinpeim/6740436

環境

Better JavaとしてのScala

写経したりしてScalaの動きを確認していきました。 お題となったのはドラクエ風RPGの戦闘。

PlayerからKnight、Magicianと継承させてみたり、 traitでWeaponを作ってLongSword object(static的なやつ)を作ったりしてました。

traitはRubyのmoduleみたいなやつで、ホント便利です。

trait Weapon
trait KnightWeapon extends Weapon

trait HasWeapon {
  protected var weapon: Weapon = NullWeapon
}
trait CanEquipKnightWeapon extends HasWeapon {
  def equip(w: KnightWeapon) = weapon = w
}

class Knight extends Player with CanEquipKnightWeapon

とかできる。 RubyいじったあとにJavaやろうとしてぐぬぬってなった記憶があったので、これがあると断然違います。 また、型をコンパイラがチェックしてくれるので、たとえばMagicianWeaponを装備しようとする怒られます。

型パラメータを使ってテンプレート的なやつを試したりもしました。 上記のCanEquipKnightWeaponだとCanEquip[T <: Weapon]みたいにできます。 scalaはいい感じに型で縛ってくれるので安心感ありますね。

モナド

Listの構造やmatchによる強力なパターンマッチ、再帰構造の利点など、手を動かして実際に確認していきました。 ここらへんからちょっとペースがきつくなっていきましたが、なんとかついていけました。 でも理解はふわっとした感じだったので、復習が必要ですね。

foreachとかmap、filterなどの高階関数Rubyで触ってたのですんなり理解出来ました。 Ruby使っているうちに、自然と関数型っぽい脳みそになっていたらしいです。

Optionモナドはすごくクールでした。 型で包み込んで忌まわしきnullチェックをコンパイラに任せられます。 Java8でも取り込まれるらしいので、ぜひ使いたい。

Futureモナドは遅延評価っぽいんだけどそうじゃないみたいでした。 このあたり理解が追いついてなくて、細かい部分でどう動作するのかってのがわかってないので復習したいです。

モナドって言葉が怖くてなかなかさわれなかったんですけど、今回はじめてやってみて、そんなに怖くないものだと理解できました。 モナディック!モナディック!

Twitter Bot

まとめとして、Twitter Botをみんなで作りました。 TLにぬるぽ見つけるとガッするやつ。

twitter4jを使ったのですが、gen-ideaってやるとsbtがダウンロードまでしてくれてとっても楽でした。

最終的にはTLがガッで埋まったのが良い思い出。

LT

マインドストームのPID制御の話が熱かった! 制御系出身で、マインドストームやったりもしてたのでテンション上がりました。

あと東京勢の発表は最初から最後まで草を回避できませんでした。 草を回避できないダメ人間ですみません。

僕も発表したんですが、内容を校正して、タイミングを見てブログ記事にしようと思いますー。

まとめ

とても満足度高い一日でした。

Scalaは日ごろネットで情報を見てもメリットが良く分からなかったのですが、 入学式では丁寧に「こんなところがカッコいいよ!」と教えてもらえたので魅力がよく分かりました。

積極的に、適材適所で使えるようになりたいです。

NDS32 GitHubハンズオンにいってきた

7/6(土), NDS32 GitHubハンズオンに参加して来ました。

Gitはコマンドである程度は使えていたのですが、SourceTreeも以前から気になっていました。 あと、人にGit勧めたりチームに展開するときにGUI環境があると説明しやすいかなーと思いつつ参加しました。

当日はあいにくの天候にもかかわらず満席で、NDSすげーって思いました。 また、大学の後輩が参加していたのもとてもびっくりでした。

GitHubハンズオン

やったこと

  • VCS, SCMとは
  • SourceTreeの使い方
  • GitHubの使い方
  • GitHub Pagesでホームページ作成
  • ペアを組んでフォーク、プルリク

SourceTreeは結構使いやすくて、画面もきれいで見やすくてよかったです。 操作も特に迷うことなく使うことができました。 ただ、Windows版のローカライズがまだのようだったので、 他の人に教えるときには注意が必要そうです。

また、GitHubの使い方も勉強になりました。 今まで使う機会のなかったGitHub Pagesに触れたのと、 ペアを組んでPull Requestもできたのが良かったです。

あと、GitHubで画像の差分を見られると知って目からうろこでした。 サンプルのドラえもんの差分がカオスで笑ってしまった。

講師の@dictavさん、ありがとうございました。

LT

LTして来ました。 軽い気持ちでネタLTしようと思ってたのがまさかの満席だったので、予想外に緊張しました。

※応用例を増やすためにワタクシの密かな趣味を大公開してましたが、恥ずかしいのでここでは消してます(・ω・)

一応このLTには意図がありまして、本編がSourceTreeでの初心者向けのGit勉強会だったので、 Gitをもっと気軽に使っていこうよ、というのと、コマンドライン版もこんな感じでつかえるよ、 というような、補足的なLTにしようかと思っていました。

すべるかなーと思っていたのに結構良い反応をいただけたので嬉しかったです。

他の方のLTも多種多様で、楽しく聞かせて頂きました。 ジャンルを超えたLTはNDSならではだなーと思います。

懇親会

ビアバッシュ!

買い出し班だったのですが、雨に打たれて大変でした。 外に出るタイミングで雨が強くなるという理不尽さでしたが、それも含めたのしかった。

オードブルはとても肉々しかったです。 ガッツリお腹いっぱいおいしい食べ物を食べられて満足でした。 写真取ればよかったなと今更後悔してます。

学生にSIerのリアルなこわい話をして若干やりすぎたかなーと思いました。 でも反省はしていない

まとめ

とても充実してたのしかった一日でした。

これを機に、社内でもSourceTreeを使ってGitいいよって話をしようかなーとも思ってます。

あと、学生すごいなーと改めて思いました。 僕も頑張らなきゃダメですね。

ということで、以上、遅くなったレポートでした。

TDD Boot Camp 長岡 1.0 に参加してきた

05/18 (土) に長岡で開催された、TDDBCに参加して来ました!

自分一人でTDDやってみてもよく分からず、前々よりTDDBCに参加したいと思っていたのですが、この度ついに長岡で開催とのことで、念願の参加となりました。

簡単にですが、まとめます。

大事だと思ったところ

  • 気づきは、「動かない→動く」で得られることが多く、早い段階で気付きを得ることが重要
  • 黄金の回転のうち、リファクタリングには意思が必要。意思がないと、回転の円が潰れてくる
  • 複数の問題、大きな問題を一度に相手にせず、小さく分割して連続的に倒していく
    • それを素早く繰り返すことが大事
  • 不安をテストにする。形骸化したテストにはしない
  • TDDの真の目的は健康。変化に対応できるのは健康なコードと健康なチーム

気付き

  • 今まで書いたテストは粒度がバラバラだった、テストを積極的にリファクタリングすることもなかった(特に粒度)。TDDBCで大体の感覚がつかめたので、どんどん書いて痛い目にあって学習しようと思う

  • ペアで作業すると、考えこんで先に進めないということがない。一人でやっているときは半分意地で悩み続けてしまうこともあるが、その前にペアからハッとする意見をもらって解決したり、ある程度のところで切り上げるということができた

  • ペアでのリファクタリングは本当に効果的。それを支えるのがテストコード。テストで振る舞いが保証されていて、安心してコードを良くしていけるのを実感

  • コードレビューで他の方々のコードを眺めて、なるほどと思うことがいっぱいあった。同じ問題をみんなで解いて、みんなでレビューし合うってのは楽しい

  • 新潟にもいろいろな技術者がいて、みんな頑張ってるんだってことが分かった。やっぱ外に出ないとダメだな

反省

  • 慣れてきたとき、段階を踏まずにテストをしてしまい、'Development Testing'でなくなってしまったケースがあった。「明白な実装」かそうでないかの感覚を練習でつかむ必要がある

  • US配列のMBAペアプロしてしまった。入力デバイスとか、エディタはペアとのスムーズなやりとりを妨げないよう配慮が必要だなーと実感した

  • レビューの時、MBAのディスプレイ出力をプロジェクタに出せなくてあたふたしてしまった

  • きのこ本持っていくのを忘れた

これから読みたい本まとめ

ニコレポをスクレイピングするスクリプトとライブラリ書いた

ニコ動って楽しいけど、ニコレポにずっと不満があった。

  • 1ページ20ログしか出ない。ページめくるのめんどくさい
  • ログの種類が絞り込めない。動画だけチェックしたいのにすぐ流れていく
  • ブラウザ開くのめんどくさい。ターミナルでチェックしたい

じゃあスクリプト書けばいいじゃんって思って、書きました。

http://github.com/upinetree/nicorepo

詳しくはGithubのREADMEをお読みください。

ふりかえり

まじめにTDDやったの初めてだったけど、どう考えてもテスト足りない。 でもどうやってテストしたら良いのかわからないところもあって、結局先に進むために諦めた部分も多かったです。

テストのコードリーディングもっとする必要があるなと実感しました。

でも、RSpec Mocksの使い方を学べたのは良かったです。

コードは、対話モードのopenコマンドと他のコマンドは意味的に違うのに同じとして扱ってるとか、気持ち悪い感じ。

再帰でページ送りできたのはちょっと良かったかなと思います。

ちょいちょい改善していこう。

Mechanizeでニコ動スクレイピングしようとしてコケた

ニコ動スクレイピングしたら楽しそうだなーと思ってやってみたら、 2回ほどコケたのでメモ。

homebrewで入れたopensslの証明書でコケる

opensslのバージョンが古かったので、homebrewでopenssl入れたら ruby2.0.0で証明書エラーでました。

http://qiita.com/items/12457815d5cee3723b97

こちらを参考に、証明書を入れて無事解決。

$ ruby -ropenssl -e "p OpenSSL::X509::DEFAULT_CERT_FILE"
"/usr/local/etc/openssl/cert.pem"

$ brew install curl-ca-bundle
$ brew list curl-ca-bundle
/usr/local/Cellar/curl-ca-bundle/1.87/share/ca-bundle.crt
$ cp /usr/local/Cellar/curl-ca-bundle/1.87/share/ca-bundle.crt /usr/local/etc/openssl/cert.pem

追記(2013/05/01)

WindowsでRubyInstallerを使ってRubyをインストールした場合、下記で対応します。

$ wget http://curl.haxx.se/ca/cacert.pem
$ cp cacert.pem /c/Ruby193/
$ export SSL_CERT_FILE=/c/Ruby193/cacert.pem

参考:Root certificates? · Issue #148 · oneclick/rubyinstaller

SSLバージョンでコケる

さて、Mechanizeを使ってみましょー。

ニコニコ動画にアクセスしてログインしてみます。

require 'mechanize'

LOGIN = 'https://secure.nicovideo.jp/secure/login?site=niconico'

agent = Mechanize.new
agent.post(LOGIN, 'mail' => mail, 'password' => pass)

が、ここで怒られます。

Errno::ECONNRESET: Connection reset by peer - SSL_connect
from /Users/upinetree/.rbenv/versions/2.0.0-p0/lib/ruby/2.0.0/net/http.rb:917:in `connect'

どうも、ニコ動はSSLv3じゃないとダメっぽいです。

http://stackoverflow.com/questions/11855324/ruby-mechanize-https-error

ここを参考に。

agent = Mechanize.new
agent.ssl_version = 'SSLv3'
agent.post(URL::LOGIN, 'mail' => mail, 'password' => pass)

これでOK!

追記(2013/05/01)

SSLv3は脆弱性が発見されたので、TLSv1以上にしましょう。

agent.ssl_version = 'TLSv1'

Rubyのwin32oleでWordファイルをPDFに一括変換する

WORD→PDF→結合という変換は結構な頻度で定期的に発生する作業だったのですが、 いい加減めんどくさいので自動化します。

Office2007以上であればPDF保存できるので、Win32OLEを使ってやりましょう。

下記エントリがとても参考になりました。

と、単に自動化したいのであれば上記エントリだけで済んでしまうので、ここでは僕がやったことを載せてみます。

やりたいこと

  • 指定したWordファイルを全てPDFに変換
  • 変換したら一つのPDFに結合

Word → PDF変換

WordはnewしたらQuitしないと開きっぱなしになるので、おっちょこちょいな僕としては怖いところです。 なので、確実にQuitできるようにちょっと細工します。

EAM(Execute Around Method)というのがあるらしいので、それを使いましょう。

※define_finalizerを使う手もありましたが、こっちのほうが面白そうだったので

require "win32ole"

class WordUtil
    def initialize
        @word_app = WIN32OLE.new("Word.Application")
    end

    def quit
        if @word_app then @word_app.Quit end
    end

    def to_pdf(doc_name)
        doc_fullpath = File.expand_path(doc_name)
        pdf_fullpath = doc_fullpath.gsub(/\.doc$/, ".pdf")

        begin
            doc = @word_app.Documents.Open(doc_fullpath)
            doc.ExportAsFixedFormat({
                "OutputFileName" => pdf_fullpath,
                "ExportFormat" => 17,            # wdExportFormatPDF
                "OpenAfterExport" => false
            })

            puts "success: #{doc_fullpath}"

        rescue
            puts "fail: #{doc_fullpath}"

        ensure
            doc.Close unless doc.nil?

        end
    end
end

class WordManager
    def WordManager.run_during(&block)
        begin
            word = WordUtil.new
            block.call(word)

        ensure
            word.quit

        end
    end
end


input_docs = ARGV[0]
input_docs = "*.doc" if input_docs.nil?

output_pdfs = input_docs.gsub(/\.doc$/, ".pdf")

puts "input docs: " + input_docs
puts "output pdfs: " + output_pdfs

# convert to pdf
WordManager.run_during do |word|
    Dir.glob(input_docs) do |fn|
        word.to_pdf(fn)
    end
end

WordManagerにブロックを渡して変換してもらっています。 これなら解放漏れしないね!

PDFを結合する

出力したPDFを結合するにはいくつか方法がありそうでしたが、今回は一番簡単そうだったpdftkを呼び出します。

今回やりたいPDFの結合はちょっと注意が必要でして。

  • 指定した順番で結合
  • ファイル名は毎回一定パターンで変わる

なので、yamlにキーワード並べて、その順番でパターンマッチングして結合、ということをしてます。 なんとめんどくさい。

require "yaml"

class PDFCat
    def initialize(pdf_names, pdf_keys)
        @sorted_pdf_names = pdf_keys.map do |key|
            Dir.glob(pdf_names) do |fn|
                break fn if /#{key}/ =~ fn
            end
        end
    end

    def concatenate(export_fname)
        cat_list = @sorted_pdf_names.join(" ")
        puts "files to be concatenated:\n    " + cat_list.split(" ").join("\n    ")
        puts "export file name: #{export_fname}"

        `"C:/Program Files/PDF Labs/PDFtk Server/bin/pdftk" #{cat_list} cat output #{export_fname}`
    end

end


# concatenate pdf files
yaml_fname = ENV['HOME'] + "/bin/pdf_keys.yaml"
yaml_data = YAML.load_file(yaml_fname)
pdfcat = PDFCat.new(output_pdfs, yaml_data['sorted_keyword_list'])

export_fname = 'catcatcat.pdf'
pdfcat.concatenate(export_fname)

もうちょいリファクタリングできそうですね。

でも疲れたから寝る。

参考サイト