2015年の振り返りと2016年に向けて
2015年
2015年はRailsをやってる時間が長かった。Androidを少々書いていた時期もあり、ほんの僅かな時期iOS(Objective-C)をちょろっとやってた。Rails自体への意識を高めていこうとした時期もあり、その結果として初のrails本体へのコミットも果たした。ただ、コードを書くこと自体よりも、チーム全体の成長や開発効率を高めることに集中していたように思う。どれか一つに注力していたわけではなかったので、外部イベントで話せるような深い話がまったくできなかったのが歯がゆかった。
関数型プログラミング、DDD、Go言語など新しい分野の勉強もしていた。特にGo言語は、自分用の小さいツールをたくさんGoで書いたことでそれなりに書けるようになってきたと思う。一番驚いたのは、naoty/Timepieceがなぜかバズって、海外からStarをたくさんいただいたことだった。
開発以外のトピックとしては、7、8年かけてたメガネをやめてコンタクトにしたこと、卓球ハウスが解散して練馬区に引っ越したこと、いろいろあって"社会的状況"になりつつあることがある。
開発以外の時間が充実しすぎてあんまり開発してなかったが、最高の一年となった。開発してても幸せにはなれない、そこに幸せはない、という数年来の想いが確信へと変わった一年だった。
2016年
今年こそはiOSアプリ開発に専念できたらしたい。Railsはいい加減コリゴリなので。アプリ開発に専念するからには、UI設計などのデザイン業務にも徐々に慣れていきたいなーと欲が出てきている。
前述のTimepieceの保守も継続させて☆1000を突破したい。ただ、これ以外にも他のジャンルで新しいiOS開発関連ライブラリを作っていきたい。できれば、少し大きめのイベントでも発表できるようになっていきたい(これまではあまり外部での発表に重きを置いてなかったけど、なんだかいろいろ心配になってきたので)。
あとは、12月の引っ越しを期に人生初の自炊生活を始めたので、ちゃんと自炊を習慣にしていきたいというのが大きな目標。
本年も何卒宜しくお願い致します。
「エンジニアのための時間管理術」を読んだ
- 作者: Thomas A. Limoncelli,株式会社クイープ
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2006/10/19
- メディア: 単行本(ソフトカバー)
- 購入: 11人 クリック: 322回
- この商品を含むブログ (153件) を見る
この本を読もうと思った背景は2つある。1つは、前回のエントリーでも書いた通り、最近は仕事を効率的に終わらせてプライベートの時間をちゃんと確保しようとしていることだ。もう1つは、7月から新卒のメンターを担当しており、作業の割り込みが増えたことだ。新人には分からないことがあればどんどん割り込んでほしいと伝えているため、メンターが割り込みを処理しつつ普段の業務もそつなくこなす必要がある。
この本は「エンジニアのための」と書いてあるが実際はシステム管理者をターゲットとしており、プログラマーである僕とは少し事情が異なるかもしれない。それでも、割り込みへの対処法やタイムマネジメントなど、その他の職業にとっても有用なノウハウがたくさん書いてある。
本書を通して感じたことは「考えることを減らして、目の前の作業に集中しよう」というメッセージだ。良い習慣を身につけたり、外部記憶装置やカレンダーのようなツールを使ったり、単純で頻繁に行う作業を自動化したりすることで、考えることを減らすことができ、割り込みやタイトスケジュールによって作業効率が落ちるのを避けられるという話が多かったように思う。
その中で特に印象に残ったのは、とにかく外部記憶装置を多用しようという話だ。本書ではPDAがその例として出てくるが、若者はPDAなんて使わないと思うので、仕事でよく使うツールに置き換えて読んでいた。本書で言われていた通り、頭のなかで覚えておく作業が増えてくるとだんだん目の前の作業に集中できなくなってくる気がする。
僕の場合、会社ではメール、スケジュールはすべてOutlookで管理されているので、やるべき作業もすべてOutlookで管理するようにしてみた。その日のTODOリストは自作のtodo管理ツール*1で管理しているが、1日の始まりにOutlookからやるべきことを棚卸ししてTODOリストに追加している。逆に、すべてのTODOをTODOリストで管理してしまうと、TODOリストがいつになっても空にならず達成感がもてなくなってしまう。すべてのタスクを記録する外部記憶装置と短いTODOリストに分けることでうまく機能しそうだ。
その他にも今すぐ実践できそうなノウハウがたくさんあったので試行錯誤して効率的に仕事をこなせるようになりたい。
近況
最近大きな環境の変化があったり先日行ってきたYAPCで影響を受けて心境が変わってきたので、近況という形でブログに残しておきたい。
大きな心境の変化として、プライベートの時間の使い方を変えようと思っている。より優先度の高いことに時間を使うようにして、プライベートでプログラミングする時間は以前より少なくなりそう。あれこれ手を出すというよりは1つのことに集中して時間を充てる方が効果的なんじゃないかと思うようになったので、何にしようか考えている。
- 仕事で使う可能性がありそうなScalaとPlayFrameworkに興味がある。以前にすごいH本を読んで関数型プログラミングを実践してみたい気持ちがある。
- あとは、いま仕事ではRailsプロジェクトに携わっているけど、リファクタリングを喫緊の課題として感じていて、プライベートの時間でいかに対処すべきか本を読んで考えてみたり、必要なライブラリの開発に時間を充てるのもいいかもしれない。
- JavaScriptをキャッチアップしたい気持ちもちょっとある。YAPCのセッションでES6の話を聞いて、ちゃんと学んで既存のプロジェクトに手を加えたい気持ちが湧いてきた。ただこれは上のリファクタリングが済んだ先の話だと思った。
- 「ドメイン駆動設計」をずっと読んでたけど、引き続き「実践ドメイン駆動設計」も読んでみようかなという選択肢もある。ただ、まだ仕事で使えるような段階にはない気がする。
- naoty/Timepieceの開発は停滞しているけど、どうしようかなと思っている。仕事でSwiftが書けるのであればまだモチベーションを維持できるのだけど、残念ながらそのような環境にはいない。
こう整理してみると、リファクタリングについてプライベートでも時間をとるのがよさそうだなと思う。それが一段落ついたらJavaScriptのリファクタリングとかDDDとかに移っていけそう。もっと余裕が出てきたらScalaやろうかなぁ。
なんとなくあと2, 3年先までの見通しが立ってきた。仕事ではとりあえず今のプロジェクトを地道に改善していくことになりそう。自分の成長というよりはプロダクトの成功やチームの成長にフォーカスしていきたいという気持ちに移ってきている。Rubyの上にも3年、という感じ。iOS/Androidもやるけど。プライベートでも、今の生活の先に明るい未来が見えてきている。堅実に仕事を進めつつ、貴重な時間を大切にしていきたい。
Timepieceを0.4.0にアップデートした
Timepieceを0.4.0
にアップデートした。ぶっちゃけブログの記事にするくらいならちゃんとCHANGELOGにしろという話なんだけど、技術的な詳細も少し話したいのでブログの記事にした。軽微なバグの修正と以下の2点が今回の変更点だ。
タイムゾーンのサポート
これがメインの変更になる。「サーバー側から受け取る時間のタイムゾーンとiOSアプリケーションのタイムゾーンが異なっており、それらを比較したい」みたいなissueをもらったので対応した。「こういう感じのインターフェイスはどう?」みたいなのを聞いてたら「Sweet!」だのと褒められたので、その気になって実装してしまった。けっこう大変だった。
iOSでは、NSDate
オブジェクトそのものにタイムゾーンは存在しない。システムで設定されるタイムゾーンをNSCalendar
経由で取得することになる。
NSCalendar.currentCalendar().timeZone
なので、今回のようなケースだと、NSDate
オブジェクトそれぞれにタイムゾーンが存在するように見せる必要がありそうだった。なお、オフセットを調整することも考えられるが、時間を足し引きしてしまった段階でそれは別の時間となってしまう。同じ時間で別のタイムゾーンを持つNSDate
オブジェクトが必要だった。実装方針としては、
ということを念頭に置いた。
ところで、TimepieceはNSDate
を始めとするいくつかの既存のオブジェクトのextensionとして実装されている。extensionでNSDate
オブジェクトにtimeZone
のようなプロパティを追加することは普通はできない。しかし、Objective-CのランタイムAPIを使って動的にプロパティを追加することで、これをなんとか実現させることができる。Swiftの場合でも、ランタイムAPIを使うことは可能だ。
import ObjectiveC public extension NSDate { var timeZone { return objc_getAssociatedObject(self, &AssociatedKeys.TimeZone) as? NSTimeZone ?? calendar.timeZone } func change(#timeZone: NSTimeZone) -> NSDate! { // ... objc_setAssociatedObject(newDate, &AssociatedKeys.TimeZone, timeZone, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)) // ... } }
objc_
から始まる関数がランタイムAPIだ。これらの関数によって動的にオブジェクトにプロパティを読み書きしている。change(timeZone:)
で生成されたNSDate
オブジェクトのみ動的に追加されたプロパティを持つ。タイムゾーンが異なるNSDate
同士の計算も問題なく行われている。これは上述の通りオフセットの調整による実装ではないためだと思う。
playgroundの追加
機能というわけじゃないけど、リポジトリにplaygroundを追加した。それに伴ってプロジェクトからワークスペースに変更した。実際にTimepieceを試してもらうには、サンプルのアプリケーションを作ってPodfileを書いて…みたいなことをする必要がありとても面倒だったので、Timepieceが使えるplaygroundを用意した。
Pull request大歓迎
タイムゾーン周りの実装は正直あんまり自信はないんだけど、テストはちゃんと通ってるしまぁいいかくらいの気持ちでリリースした。観点が漏れている可能性は大いにありうるので、ぜひPull requestしてもらいたい。
コマンドラインを拡張しやすくするヤツ書いた
gitなど既存のコマンドラインを拡張して新しいサブコマンドを追加する方法はいくつか考えられる。
git alias
gitの場合はgit alias
を使うことで簡単にサブコマンドを追加できる。gitのとき限定。
ラッパー
github/hubのような既存のコマンドラインをラップしたスクリプトを書き、alias hub=git
のようにalias
することで既存の機能を保ちつつ機能を追加できる。
問題点としては、複数のラッパーによる拡張が難しくなる。例えば、ここでbub
というgit
のラッパーを書いたとする。git
にhub
の機能とbub
の機能を拡張したい。hub
は入力されたサブコマンドがhub
になければgit
にフォワードしている。なので、hub
とbub
を同時に拡張するにはbub
をhub
のラッパーとして実装することになってしまう。依存関係をハードコーディングすることになるため、まったくスケーラブルじゃない。
命名規則とext
command subcommand
と入力されたらcommand-subcommand
を実行するように名前解決する仕組みがよさそうだと思う。例えば、git pr
というコマンドはまずgit-pr
を探し、あれば実行し、なければgit pr
を実行する(そしてエラーになる)。gem uninstall all
というコマンドはgem-uninstall-all
、gem-uninstall all
、gem uninstall all
の順に探索されて見つかり次第実行される。
$ go get github.com/naoty/ext $ go get github.com/naoty/gem-uninstall-all $ alias gem="ext gem" $ gem uninstall all # Run gem-uninstall-all
正直、いろんな問題がありえそうだが、昨日思いついたままに書いたものなので、まだ想定できてない。gem-uninstall-rails
というコマンドがあったらrailsをアンインストールできないとかありそう。
上の例で、hub
とbub
を同時に拡張したい場合にext
を使うと以下のようにできる。
$ go get github.com/naoty/hub-bub $ alias git="ext hub" $ git bub # Run `hub-bub`
残念ながら、hub
を使いたい場合はこうするしかないような気がする。
追記(2015-07-23)
gitには、git subcommand
をgit-<subcommand>
として名前解決して実行する機能があったことをさっき知った。なので、gitに限って言えばextのようなツールは不要だと思う。
$ cd $HOME/bin $ vi git-hello #!/bin/sh echo "Hello, world!" $ chmod +x git-hello $ git hello Hello, world!
Pocketのもう読んでない記事を掃除するヤツ書いた
普段、Pocketを使って「あとで読む」記事を管理している。ちょっとした時間に見つけた記事をPocketに追加しておいて、通勤時間などにiOSアプリで消化している。ただ、長い記事が増えてくるとだんだん消化しきれなくなってきて、消化しようというモチベーションが失せてくる。そこで、一定期間が経っても消化できていない記事を自動的に削除するツールを書いた。
使い方
まず、Pocketのdeveloperサイトに行ってアプリケーションを作成する。すると、Consumer keyが得られる。次に、Access tokenが必要なのだけど、これはmotemen/go-pocketを使ってOAuth認証を行い取得した。
Herokuボタンからデプロイする。ここで、上で取得したconsumer keyとaccess tokenを環境変数としてセットする。さらに、削除対象とする期限を環境変数で指定できる。デフォルトは24時間となっている。僕は72時間にしている。
Heroku schedulerのダッシュボードで
sweep
を実行するタイミングを設定する。
所感
先日、Herokuが公式にGoをサポートしたので、さっそくテストを兼ねてこういうものをGoで書いてみた。tools/godepの使い方を覚えなくてはいけないことを除けば、いつもどおりにHerokuにアプリケーションをデプロイできた。
個人的にちょっとしたCLIツールをGoで書くことが増えたが、ちょっとしたジョブを定期実行させるときにGoでちょっとしたツールを書いてHeroku schedulerにやらせるという手法は非常にお手軽なので今後も機会がありそうだなと思った。
コミット数が多いファイルを表示するコマンドを書いた
インストール
$ go get github.com/naoty/hot
使い方
$ cd src/github.com/naoty/Timepiece $ hot 24: README.md 17: Sources/NSDate+Timepiece.swift 15: Tests/NSDate+TimepieceTests.swift 10: Timepiece.xcodeproj/project.pbxproj 9: Timepiece.podspec 7: Sources/Duration.swift 7: Tests/DurationTests.swift 7: Tests/Int+TimepieceTests.swift 6: Sources/Int+Timepiece.swift 4: Sources/NSDateComponents+Timepiece.swift 2: .travis.yml 2: Tests/NSTimeInterval+TimepieceTests.swift 2: Timepiece.xcodeproj/xcshareddata/xcschemes/Timepiece OSX.xcscheme 2: Sources/NSTimeInterval+Timepiece.swift 1: Timepiece.xcodeproj/xcshareddata/xcschemes/Timepiece iOS.xcscheme 1: Timepiece.xcworkspace/contents.xcworkspacedata 1: .gitignore 1: LICENSE 1: Sources/NSCalendar+Timepiece.swift 1: Sources/NSCalendarUnit+Timepiece.swift 1: Sources/String+Timepiece.swift 1: Tests/NSCalendarUnit+TimepieceTests.swift 1: Tests/String+TimepieceTests.swift 1: Timepiece.playground/Contents.swift 1: Timepiece.playground/Sources/SupportCode.swift 1: Timepiece.playground/contents.xcplayground 1: Timepiece.playground/playground.xcworkspace/contents.xcworkspacedata 1: Timepiece.xcodeproj/Timepiece-Info.plist 1: Timepiece.xcodeproj/TimepieceTests-Info.plist 1: Timepiece.xcodeproj/project.xcworkspace/contents.xcworkspacedata
表示件数を-n <表示したい件数>
で指定したり、パターンを指定してマッチしたファイルだけ表示することができる。
$ hot -n 5 "**/*.swift" 17: Sources/NSDate+Timepiece.swift 15: Tests/NSDate+TimepieceTests.swift 7: Sources/Duration.swift 7: Tests/DurationTests.swift 7: Tests/Int+TimepieceTests.swift
動機
仕事で1年以上開発が行われているコードベースを引き継ぐことになった。僕の仕事は既存のコードを理解しつつ、新たに機能を追加していくことだ。そこで、効率的に既存のコードベースの全体像を把握するため、このようなツールを作ることにした。どれが主要なファイルなのかコミットログから把握できる。
他の使い方としては、例えば各ファイルのコミット数、循環的複雑度、テストカバレッジ等から、プロジェクト全体のバグの出やすさみたいなものを可視化できるかもしれない。