Persistence

技術メモなど

Macの環境構築メモ(ターミナル/シェル)

『エンジニアたるもの使う道具にはこだわりを持て』ということでMacの開発環境を色々といじってみました。こういうのは書いておかないとすぐ忘れてしまうので備忘のためにメモしておきます。

iTerm2

今までターミナルはMacのデフォルトのを使っていました。カラースキームとかも綺麗で特に不満は無かったのですが、定番のiTerm2を使ってみることにしました。

http://iterm2.com/

今のところ使っている機能としてはこのくらいです。

機能 ショートカット
検索する Ctrl+f
ペインを水平分割する Ctrl+d
ペインを垂直分割する Ctrl+Shift+d
ペインを移動する Ctrl+Option+方向キー
ペインを閉じる Ctrl+w
タブを移動する Cltr+Shift+[またはCltr+Shift+]

まだまだ機能はたくさんあるので使っていて不便を感じたら調べるといいですね。ちなみに私は前回入力したコマンドを再入力する際にキーを連打するのですが、押す回数が多いのでもっと簡単に履歴を探せる機能がほしいなと思ったんですが、これはターミナルではなく別の機能で実現できました。

iTerm2のカラースキームはここにたくさん(たくさん!)あるので、好きなモノをダウンロードしてインポートできます。

https://github.com/mbadolato/iTerm2-Color-Schemes

oh-my-zsh

oh-my-zshzshの設定を管理するためのツールです。zshは今までも使っていたのですが、カスタマイズはほとんどしていませんでした。入力補完とかは何もしなくてもついてくるので超便利ですけどね!

https://github.com/robbyrussell/oh-my-zsh

oh-my-zshには「テーマ」と「プラグイン」という2つの便利な機能があります。

テーマ

テーマは見た目の表示をカスタマイズしたテンプレートで、あらかじめたくさん(たくさん!)の種類が備わっていて、設定を変えるだけでそのテーマが使えるようになります。また、テーマはシェルスクリプトで書かれているので、ちょっとしたカスタマイズなら簡単にできます。

https://github.com/robbyrussell/oh-my-zsh/wiki/themes

私は"wedisagree"というテーマを使っているのですが、現在時刻は行ごとに出力しなくてもいいので削除しました。このテーマはカレントディレクトリのgitリポジトリの状態を表示してくれるので、ブランチの切り替え忘れとかを防げて便利ですね。

ZSH_THEME="wedisagree"

プラグイン

プラグインはコマンドのショートカット集のようなものです。

https://github.com/robbyrussell/oh-my-zsh/wiki/Plugins

例えばbundlerというプラグインを入れてbeと打つと、bundle execが実行されます。今まではわざわざaliasを書いて設定していました。プラグインもあらかじめたくさん(たくさん!)備わっていて、設定に書くだけで使えるようになります。なお、各種プラグインの設定は、~/.oh-my-zsh/pluginsの中にある設定ファイルを見ると分かります。

plugins=(git osx brew bundler rails)

autojump

autojumpはディレクトリ移動を高速にするためのツールです。移動したことのあるディレクトリを記録し、次回以降はフルパスを入力しなくても、j [移動したいディレクトリの一部の文字]と入力するだけで移動できます。

インストールはHomebrew経由で入れてしまうのが簡単です。

brew install autojump

あとは、お使いのシェルのrcファイル(私は.zshrc)に以下を追加します。

[[ -s $(brew --prefix)/etc/profile.d/autojump.sh ]] && . $(brew --prefix)/etc/profile.d/autojump.sh

しかし、私の環境ではこのままでは以下のエラーとなりました。

$ j
usage: autojump [-h] [-a DIRECTORY] [-i [WEIGHT]] [-d [WEIGHT]] [--complete]
                [--purge] [-s] [-v]
                [DIRECTORY [DIRECTORY ...]]
autojump: error: unrecognized arguments: -l

jエイリアスが本来ならばjobsになるはずなんですが、なぜかjobs -lとなるためエラーとなります。おそらくoh-my-zshの影響かと思うのですが、なぜこのようなエイリアスになるのかは分かりませんでした。対処として、先ほど追加したautojumpの設定の下に、alias j="jobs"を追記することでエイリアスの上書きができました。

他にzという同様のツールがありますが、こちらは[移動したいディレクトリの一部]が充分でない(候補がたくさんある)時でも、優先順位が一番高いディレクトリへ移動してしまうので、autojumpの方が使い勝手が良さそうです。

percol

percolは"対話的なgrepツール"だそうです。

https://github.com/mooz/percol

これを使って色々と便利なカスタマイズをしているブログ記事が見つかりましたが、今回はコマンド履歴の検索をしてみました。設定方法は以下のサイトで説明されている通りです。

http://blog.zoncoen.net/blog/2014/01/14/percol-autojump-with-zsh/

例えば、20回前に入力した長いコマンドを再度入力したいとき、今まではを20回押してましたが、これを使うとCommand+rインタラクティブモードになった後にコマンドの一部を入力して検索すると絞り込まれていきすぐに見つけることができます。

参考

http://qiita.com/bird_nitryn/items/bd063f0d7eb18287fec1

node.jsの環境構築メモ

Yeomanを使ってみようと思って、Macにインストールされているnode.jsをすごい久しぶりに触ろうとしたらエラーが起きたので、nodebrewを使って再構築したメモ。

node.jsのアンインストール

まずはじめに、Macにインストールされているnode.jsをアップデートし、npmパッケージを入れていこうと思ったら、node.jsをアップデートした後にnpmコマンドが使えなくなってしまいました。node.jsをアップデートする前から使えてたかどうかは不明です。(かなり長い間使っていなかったので。)

$ node -v
v0.8.16

$ n stable

     install : v0.12.2
       mkdir : /usr/local/n/versions/0.12.2
       fetch : http://nodejs.org/dist/v0.12.2/node-v0.12.2-darwin-x64.tar.gz
   installed : v0.12.2

$ node -v
v0.12.2

$ npm
module.js:338
    throw err;
          ^
Error: Cannot find module 'are-we-there-yet'
    at Function.Module._resolveFilename (module.js:336:15)
    at Function.Module._load (module.js:278:25)
    at Module.require (module.js:365:17)
    at require (module.js:384:17)
    at Object.<anonymous> (/usr/local/Cellar/node/0.8.16/lib/node_modules/npm/node_modules/npmlog/log.js:2:16)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Module.require (module.js:365:17)

npmコマンドを叩くと上記のエラーが起きます。モジュールが足りないと言われるがそもそもnpmコマンドが使えないのでモジュールを入れる事ができませんでした。また、npmをアンインストールするにもnpmコマンドを使うので詰んでしまった。。

なので、node.jsから入れなおすことにしました。

ところで今使っているnode.jsはどうやって入れたものか?それがわからないと消し方もわからないのですが、まず一番ありそうなところで、Homebrewを確認してみます。

$ brew list node
...

brew経由でnodeが入っていた事は分かりましたが、フォルダ名が現在使っているバージョンとは違いました。これはアップデートする前のバージョンが表示されるのかもしれませんが、この時のログが流れてしまってもう確認できません。なんにせよもう必要がないのでアンインストールします。

$ brew uninstall node

もう一つの方法として、nodeをインストーラからインストールした場合の削除方法というのもありましたので、念のためこちらもやっておきます。また、あわせてnpmのグローバルでインストールしたパッケージも削除しました。手順は以下のサイトを参照しました。

http://whiskers.nukos.kitchen/2014/09/25/nodebrew.html

これでもまだnodeの実行モジュールが残っていてパスが通るので、手動で実行モジュールを削除しました。(たぶん正しい手順ではないです。)

$ which node
/usr/local/bin/node

$ sudo rm /usr/local/bin/node

nodebrewのインストール

nodebrewはnode.jsやio.jsのバージョン管理ツールです。Rubyでいうrbenvみたいなものですね。他にもnode.jsのためのバージョン管理ツールが色々とありますが、nodebrewが一番環境をクリーンに保てて良いというのを目にしたのでこれにしました。実際、使うのは~/.nodebrewだけで、あとはパスを通すだけです。とってもクリーンですね!

インストール方法もこちらのサイトを参考にしたので、自分が改めて書くまででもないですね。

http://whiskers.nukos.kitchen/2014/09/25/nodebrew.html

基本的なコマンドだけメモしておきます。

  • nodebrew ls-remote
  • nodebrew install-binary [バージョン]
  • nodebrew uninstall [バージョン]
  • nodebrew list
  • nodebrew use [バージョン]

nodebrew install [バージョン]でもインストールできますが、ソースからコンパイルするため非常に時間がかかります。通常はinstall-binaryを使うといいですね。

参考

ちなみに、今から使うんだったらio.jsじゃない?って思ってちょっと調べてみたら、こんな記事が見つかりました。内容は記事を見ればわかるのでここには書きませんが、自分は特に最新機能が必要でない限りはnode.jsを使いつつ様子見しようと思います。

http://yosuke-furukawa.hatenablog.com/entry/2015/03/05/171527

『関数型プログラミングに目覚めた! IQ145の女子高校生の先輩から受けた特訓5日間』を読んだ

関数型プログラミングに目覚めた! IQ145の女子高校生の先輩から受けた特訓5日間』を一読したので感想を書いていきます。

この本の感想を3行でまとめると

パラダイムシフト

本書の前半半分は、命令形プログラミングと関数型プログラミングパラダイムの違いを非常に分かりやすく説明されています。自分が今まで書いていた命令形プログラミングはフローを作成して機能毎に分割して作っていましたが、関数型プログラミングはフローや状態を排除し論理毎に機能を作成し、必要になった時に必要な分だけ計算する(イベント駆動)という方法を取ります。「論理」と「計算」を分けて考えるという説明はわかりやすかったです。

一方の後半半分は、FRP(関数型リアクティブプログラミング)の説明になるのですが、アリストテレスピタゴラスプラトンデカルト、などの哲学思想(これはこれで読み物としては面白かったですが)とFRPを対比させて説明が進んでいくのですが、正直最後の方はついていけなくなりました。まあこの辺は、FRPだけを説明するのはもっと簡単だけど、筆者としてはその根本的な思想を伝えたかったのだと思います。なお、これらの大部分は著者のブログの記事(量子コンピュータ関連のエントリー)にも書いてありますので、興味があれば読んでみるとよろしいかと。

歴史的背景

会話形式で説明が進んでいく中でいくつものプログラミングに関する歴史が説明されており、読み物として面白かったです。例えばJavaScriptの生い立ちの話とか、命令形プログラミングから関数型プログラミングへのパラダイムシフトやの歴史、そして次のパラダイムシフトは何かなど。

本を読む姿勢

本書を買う前から著者のブログ等で著者の関数型プログラミングの説明に対する否定的な意見があることは知っていましたが、元々の意見が交わされていたサイトは削除されてしまい、今は罵り合いみたいな情報しか残っておらず、遅れて知った身としては何が正しいのか分かりません。ですから、果たして「この本を信頼して読んでよいのか?」という不安がありました。

しかしそもそも、正しい本の読み方としては、本を100%信用して読むのではなく、疑問を持ちながら読むことも必要だということを、『本を読む本 (講談社学術文庫)』という本の中でアドラーが言っていたのを思いだしました。本書を通じて関数型プログラミングに興味が湧いたので(この点に関しては間違いなく読んでよかったと言える)、他の関数型プログラミングに関する本や情報も今後調べて身につけていきたいと思います。

全体を通して

本書は科学哲学史の観点から関数型プログラミングの根本に迫るというアプローチを取っています。このへんは好き嫌いが別れるところかと思いますので本を購入される前に立ち読みをするなり著者のブログに目を通してみることをオススメします。しかし事実として、関数型プログラミングパラダイムシフトは既に起きており、オブジェクト指向に変わる次のスタンダードになりうるということは大いに共感できたし、実際に世の中の動向もここ数年で「イベント駆動」という方式を取るプロダクトがどんどん生み出されていますので、自分も今のうちに関数型プログラミングを勉強しておかないとなーと思いました。

次にやること

gem yankのポリシーが変わったそうです

たまたま目に止まったのでメモ。

Policy change about gem yank | RubyGems.org

gem yunkは、RubyGemsに公開したgemを公開停止にするコマンドです。

記事の内容を要約すると

いままではgem yankしたら公開停止にするだけでファイルは消さなかった(サイトからはダウンロードできた)んだけど、どうしても消す必要がある物はサポートの人たちがボランティアで削除の対応していて、それに結構な手間がかかっていた。だから今度からは、gem yankしたらRubyGemのストレージからは勝手に消すようにしたけど、非公式のミラーサイトにアップされたものやwebhook経由で公開したものは消せないから気をつけてね。

って感じだと思います。

ちなみにgem yankを取り消す(公開停止を解除する)時は、gem yank --undoが使えたんだけど、これは使えなくなるのかな?

なんにせよ、gem pushするときはくれぐれも慎重にやりましょう。

Array#eachからRubyのブロックを理解する

Rubyのブロックについて、『パーフェクトRuby』を読んで調べました。内容はQiitaに投稿してあります。

qiita.com

Qiitaに投稿したことで、誤りや曖昧さについて指摘をいただき、より理解を深めることができました。Blogではよほど有名人でない限りこんなにコメントを貰えることはないので、Qiitaならではの良いところですね。一方、上級者から見るとQiitaにゴミを増やすな!という気持ちもあると思うので、なるべく見る人にとって有益になるように心がけないといけないですね。

パーフェクトRuby (PERFECT SERIES 6)

パーフェクトRuby (PERFECT SERIES 6)

メディア芸術データベースのラッパーGemをリファクタリングしました

これまでの流れ

クラス設計

Before

f:id:bisque3311:20150405122900j:plain

Beforeでは、検索した結果をHashオブジェクトで返すだけという単純な機能だったので、クラス自体は多くありませんでした。それにしても、ComicがHttpBaseを継承しているのは不自然極まりないです。委譲でしょ、委譲。

After

f:id:bisque3311:20150405122912j:plain

Afterでは、検索した結果をその要素のオブジェクト(例えば、Comicを検索した場合はComicオブジェクト)の配列で返すようにしました。これにより、関連する項目(例えば、Comicの著者の詳細情報)を取りたい時に、利用者はidを使って再度検索する必要がなくなり、メソッドチェーンで取り出せるようになりました。

パターン

次に、意識したパターンについて解説します。

Builderパターン

Builderパターンは、次のようなパターンでした。

複雑なコンポーネントの組み立てを簡単に使えるようにするとともに、内部ロジックを隠蔽する。また、コンポーネントの組み立て方に誤りはないか、不足はないかなどのチェックを設けることもできる。

このGemではコンポーネント(クラス)の組み立てはありませんが、検索条件がたくさんありますので、検索条件を設定するためのクラス(SearchOptionBuilder)を作りました。これにより、利用者はどんな検索条件があるかは.methodsを見れば分かりますし、.buildメソッドは検索条件の必須項目をチェックしてから検索クラス(Search)が使うオブジェクトに整形して渡すことができます。

Template Methodパターン

Template Methodパターンは、次のようなパターンでした。

処理全体の流れは同じだが、一部が異なる処理が複数ある場合に用いる。

このGemでは、検索(Search)系の機能と、取得(Find)系の機能があります。FindはSearchで得た各要素のidを用いて詳細情報を取得するための機能です。これらはどちらも「HTTPリクエストをする」「結果を解析する」という同じ流れの処理をしており、これらをまとめた抽象クラスをRetrieveTemplateクラスとしました。Findの方はさらに共通処理が加わるため、FindTemplateを追加しました。XXXとYYYはそれぞれの機能や要素が入りますので複数あります。

Strategyパターン

Strategyパターンは、次のようなパターンでした。

全体の流れは同じである複数の処理があり、一部の処理を変更する必要がある場合。委譲にすることでクラス間の結びつきを疎結合にしたい場合。

このGemでの使い方が厳密にStrategyパターンかと言われるとちょっと自信がないですけど、委譲により解析処理を分けて必要なところで呼び出すようにしています。SearchやFindのクラスに解析処理を入れてしまうと、本来の検索するという目的とは関係のないメソッドがたくさんあって気持ち悪いんですよね。なんでFindクラスにHTML解析のメソッドがあるのって思ってしまいます。

Proxyパターン(仮想プロキシー)

Proxyパターン(仮想プロキシー)は、次のようなパターンでした。

本物のオブジェクトと同じ振る舞いをし、オブジェクトの実体が生成させるのをできるかぎり遅らせるためのプロキシーを仮想プロキシーという。

このGemでは、Searchの検索結果にその要素のオブジェクト(例えば、Comicオブジェクト)が返されますが、検索した時点ではサマリー情報しかありません。全部の情報を取るには、Findを使って詳細ページを取得する必要があります。そこで、Proxyパターンを使って、必要になった時に詳細情報を取得するようにしました。

    class Component
      attr_reader :id

      def initialize(id, content = {}, retrieved = false)
        @id = id
        @content = content
        @retrieved = retrieved
      end

      def [](key)
        if @content.has_key?(key)
          @content[key]
        else
          unless retrieved?
            @content.merge!(@retriever.execute.content)
            @retrieved = true
            @content.has_key?(key) ? @content[key] : nil
          end
        end
      end

      def method_missing(name, *args)
        self[name.to_sym]
      end

      def content
        unless retrieved?
          @content.merge!(@retriever.execute.content)
          @retrieved = true
        end
        @content
      end

      def content_cache
        @content
      end

      private

      def retrieved?
        @retrieved
      end
    end

    class Comic < Component
      def initialize(id, content = {}, retrieved = false)
        super(id, content, retrieved)
        @retriever = FindComic.new(@id)
      end
    end

    # 以下同様に続く... #

例えば、SeachComicがComicオブジェクトを作るときには、idとcontent(サマリー情報)を渡します。idとcontentは検索結果を解析して取得しています。また、Comicのinitializeでは@retriverに詳細情報を検索するためのクラスを設定します。

Componentクラスの[]メソッドとmethod_missingメソッドはいずれもcontentへのアクセサです。[]メソッドの場合はcomic[:title]で取り出せますし、method_missingメソッドの場合はcomic.titleで取り出せます。method_missingは存在しないメソッドが指定された時に呼ばれるメソッドで、それをオーバーライドしています。

また、まだ取得していない詳細情報を取得しようとすると、@retrieved(詳細情報を取得したかどうか)がfalseであれば一度だけ@retriverを実行して詳細情報を取得してcontent(サマリー情報)と詳細情報をマージします。このようにして必要になった時に情報を取得するようにすることができました。

まとめ

デザインパターンを意識することで、複雑な構造を持つクラス群をわかりやすくまとめることができました。オブジェクト指向を勉強したら、その次にデザインパターンを勉強すると、より実践的なクラス設計の方法がわかると思いますのでオススメです!

Rubyによるデザインパターン

Rubyによるデザインパターン

また、作っていて気づいたことですが、このGemは他のサイトで同じことをやろうとした時でもクラス名とかパーサ部分を変えればほとんどこのまま使えます。クラスを疎結合にしたことで再利用性が高いコードになったんじゃないかと思います。

ソースはGitHubで公開していますので、ご意見をいただけたら喜びます!ブランチは「v1.0.0」です。まだmasterにはマージしていません。

github.com

RubyGemsの方はしばらくしたらアップデートします。

次のステップ

  • Railsブロンズ試験(4/25)の勉強
  • Rspecの勉強

安定か挑戦か(今後を考える)

昨年の転職活動を振り返りつつ、今後の行動方針をまとめてみます。(その時、自分がどう考えていたかを書き残しておくのって大事ですね。)

振り返り

昨年春頃に、技術系の転職エージェントにお世話になりつつ転職活動をしていました。結果としては条件に合う3社くらいに転職エージェントのサイトを通じてエントリーしてみましたが門前払いといったところでした。後から考えると、全てそこそこ名の知れたベンチャーで、私のような実績もない半端者を雇うわけないですね。

そのエージェントの担当の方に言われたことは、転職活動をするには、会社選びで重要となる4つの要素について優先順位を決めることだということです。その4つの要素とは、仕事内容・報酬・人・付加価値(会社が安定しているかなど)の4つです。これを私の現状に当てはめると次のようになります。

要素 評価
仕事内容 ×:日本でも最大級のシステムを開発/運用しているが、開発はほぼすべて下請けで技術者としてのスキルアップができない。また、私は派遣社員として親会社に派遣されているので、将来的なキャリアパスがない。
報酬 ◯:普通の暮らしをするには困らない程度にはある。子供を国立の大学に通わせることはできるが、私立はゴメン無理ってレベル。
△:いい人ばかり。ただ、安定という"ぬるま湯"に浸かりきっている人が多い。(自分も9年勤めている時点でかなり浸かっている。)
付加価値 ◎:会社としての安定度はかなり高い。また、残業も月平均で10〜20時間と少なく、有給休暇も消化できる。

ということで、現状では「報酬」「付加価値」については概ね満足しているが、「仕事内容」に不満がある。つまり、この状況で転職を考えるということは、現状の優先度としては「仕事内容(技術力)」が一番高いということになります。とは言え、所帯持ちなので報酬や付加価値を今より落とすのもためらわれるため、これらを天秤にかけるのは本当に難しいです。

また、転職するべきか否かをリスクとリターンの観点で評価すると以下の通り。

リスク リターン
転職しない場合 取得できる知識は業務知識ばかりで技術者としてのスキルアップがない。だから歳をとってから会社が倒産したり縮小した場合に外に放り出されたら生きていくすべがない。 高い確率で、定年まで安定した収入を得られる。
転職した場合 今よりもハードワーク(体力的にも精神的にも)になった場合、健康を損なうことになる。その結果、収入も大きく減る。 技術者としてスキルアップすることで、どんなことがあっても技術者として食っていけるようになる。また、より高い報酬が得られる。

ここからは転職しない場合はローリスク・ローリターン、転職する場合はハイリスク・ハイリターンという、すごく当たり前の結論が見えました。もう少し丁寧に言うと、現状のリスクに対する対策が転職なのですが、転職した場合のほうが高いリスクがあるということです。(転職後のリスクが"高い"と評価したことについては後ほど詳しく触れます。実はこれこそがもっとも重要な課題だと今では思っています。)

今後の行動方針

前回の転職活動から1年が経ちました。転職に関しての考え方は変わっていません。条件に合う会社があれば行きたいです。またこの1年で、マイプロジェクトを幾つか遂行したり、他の人のプロジェクトのお手伝いをしたりして、技術的には幾らかレベルアップしました。(まだまだ自信があるとは言えない)。そして今は育児休職中なので、この機会に以下のことにチャレンジしようと思います。

  • 自分の武器を持つ

自分の武器となりそうなスキルといえば、RubyOnRailsです。これを、ちゃんと使えますと証明するためにRailsシルバーの資格を取ります。またその後に、Railsを使ったサイト構築・運営をして実績を作ります。(構築は何度もやっていますが、運営していますと言えるサイトがないので。。。)

  • 体を鍛える

自分が転職に踏み切れない一番の理由は、体調・体力に自信がない事です。そんなこと?と思われるかもしれませんが、私にとっては非常に重要なことです。これさえ解決すれば、もっといろんなことに挑戦できるようになると思います。また、転職活動や仕事をする上でも、"健康に見える"ことは相手にいい印象を与えるために大事ですよね。

  • つながりを大事にする、そして広げる

今は育児休職中でただでさえ人と合うことが少ないので、今までのつながりには積極的につながっていき、更に広がりを増やしていきます。つながりを持つ上で必要なことは、"まずは与える"の精神かなと思います。例えばOSSに貢献したり、便利なものを作って人の役に立ったり。そういうところから人脈を増やしていきたい。

この3つをクリアできた時に、次のステップに移行します!目標は4ヶ月以内!

おまけ

最後に、とても勇気づけられる記事を見つけたので記念に貼ってく。ダニーさんのことはCultureJapanの放送のあたりからずっと見てるけど本当にすごい人。Mirai株式会社、超楽しそう!

www.dannychoo.com