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に投稿したことで、誤りや曖昧さについて指摘をいただき、より理解を深めることができました。Blogではよほど有名人でない限りこんなにコメントを貰えることはないので、Qiitaならではの良いところですね。一方、上級者から見るとQiitaにゴミを増やすな!という気持ちもあると思うので、なるべく見る人にとって有益になるように心がけないといけないですね。
- 作者: Rubyサポーターズ,すがわらまさのり,寺田玄太郎,三村益隆,近藤宇智朗,橋立友宏,関口亮一
- 出版社/メーカー: 技術評論社
- 発売日: 2013/08/10
- メディア: 大型本
- この商品を含むブログ (20件) を見る
メディア芸術データベースのラッパーGemをリファクタリングしました
これまでの流れ
- メディア芸術データベースのラッパーGemを作ってみました - Persistence
- 俺、Rubyについて全然分かってないじゃん
- 『Rubyによるデザインパターン』を読み終えて - Persistence
- イマココ
クラス設計
Before
Beforeでは、検索した結果をHashオブジェクトで返すだけという単純な機能だったので、クラス自体は多くありませんでした。それにしても、ComicがHttpBaseを継承しているのは不自然極まりないです。委譲でしょ、委譲。
After
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(サマリー情報)と詳細情報をマージします。このようにして必要になった時に情報を取得するようにすることができました。
まとめ
デザインパターンを意識することで、複雑な構造を持つクラス群をわかりやすくまとめることができました。オブジェクト指向を勉強したら、その次にデザインパターンを勉強すると、より実践的なクラス設計の方法がわかると思いますのでオススメです!
- 作者: Russ Olsen,ラス・オルセン,小林健一,菅野裕,吉野雅人,山岸夢人,小島努
- 出版社/メーカー: ピアソン桐原
- 発売日: 2009/04/01
- メディア: 単行本
- 購入: 13人 クリック: 220回
- この商品を含むブログ (64件) を見る
また、作っていて気づいたことですが、このGemは他のサイトで同じことをやろうとした時でもクラス名とかパーサ部分を変えればほとんどこのまま使えます。クラスを疎結合にしたことで再利用性が高いコードになったんじゃないかと思います。
ソースはGitHubで公開していますので、ご意見をいただけたら喜びます!ブランチは「v1.0.0」です。まだmasterにはマージしていません。
RubyGemsの方はしばらくしたらアップデートします。
次のステップ
安定か挑戦か(今後を考える)
昨年の転職活動を振り返りつつ、今後の行動方針をまとめてみます。(その時、自分がどう考えていたかを書き残しておくのって大事ですね。)
振り返り
昨年春頃に、技術系の転職エージェントにお世話になりつつ転職活動をしていました。結果としては条件に合う3社くらいに転職エージェントのサイトを通じてエントリーしてみましたが門前払いといったところでした。後から考えると、全てそこそこ名の知れたベンチャーで、私のような実績もない半端者を雇うわけないですね。
そのエージェントの担当の方に言われたことは、転職活動をするには、会社選びで重要となる4つの要素について優先順位を決めることだということです。その4つの要素とは、仕事内容・報酬・人・付加価値(会社が安定しているかなど)の4つです。これを私の現状に当てはめると次のようになります。
要素 | 評価 |
---|---|
仕事内容 | ×:日本でも最大級のシステムを開発/運用しているが、開発はほぼすべて下請けで技術者としてのスキルアップができない。また、私は派遣社員として親会社に派遣されているので、将来的なキャリアパスがない。 |
報酬 | ◯:普通の暮らしをするには困らない程度にはある。子供を国立の大学に通わせることはできるが、私立はゴメン無理ってレベル。 |
人 | △:いい人ばかり。ただ、安定という"ぬるま湯"に浸かりきっている人が多い。(自分も9年勤めている時点でかなり浸かっている。) |
付加価値 | ◎:会社としての安定度はかなり高い。また、残業も月平均で10〜20時間と少なく、有給休暇も消化できる。 |
ということで、現状では「報酬」「付加価値」については概ね満足しているが、「仕事内容」に不満がある。つまり、この状況で転職を考えるということは、現状の優先度としては「仕事内容(技術力)」が一番高いということになります。とは言え、所帯持ちなので報酬や付加価値を今より落とすのもためらわれるため、これらを天秤にかけるのは本当に難しいです。
また、転職するべきか否かをリスクとリターンの観点で評価すると以下の通り。
リスク | リターン | |
---|---|---|
転職しない場合 | 取得できる知識は業務知識ばかりで技術者としてのスキルアップがない。だから歳をとってから会社が倒産したり縮小した場合に外に放り出されたら生きていくすべがない。 | 高い確率で、定年まで安定した収入を得られる。 |
転職した場合 | 今よりもハードワーク(体力的にも精神的にも)になった場合、健康を損なうことになる。その結果、収入も大きく減る。 | 技術者としてスキルアップすることで、どんなことがあっても技術者として食っていけるようになる。また、より高い報酬が得られる。 |
ここからは転職しない場合はローリスク・ローリターン、転職する場合はハイリスク・ハイリターンという、すごく当たり前の結論が見えました。もう少し丁寧に言うと、現状のリスクに対する対策が転職なのですが、転職した場合のほうが高いリスクがあるということです。(転職後のリスクが"高い"と評価したことについては後ほど詳しく触れます。実はこれこそがもっとも重要な課題だと今では思っています。)
今後の行動方針
前回の転職活動から1年が経ちました。転職に関しての考え方は変わっていません。条件に合う会社があれば行きたいです。またこの1年で、マイプロジェクトを幾つか遂行したり、他の人のプロジェクトのお手伝いをしたりして、技術的には幾らかレベルアップしました。(まだまだ自信があるとは言えない)。そして今は育児休職中なので、この機会に以下のことにチャレンジしようと思います。
- 自分の武器を持つ
自分の武器となりそうなスキルといえば、RubyOnRailsです。これを、ちゃんと使えますと証明するためにRailsシルバーの資格を取ります。またその後に、Railsを使ったサイト構築・運営をして実績を作ります。(構築は何度もやっていますが、運営していますと言えるサイトがないので。。。)
- 体を鍛える
自分が転職に踏み切れない一番の理由は、体調・体力に自信がない事です。そんなこと?と思われるかもしれませんが、私にとっては非常に重要なことです。これさえ解決すれば、もっといろんなことに挑戦できるようになると思います。また、転職活動や仕事をする上でも、"健康に見える"ことは相手にいい印象を与えるために大事ですよね。
- つながりを大事にする、そして広げる
今は育児休職中でただでさえ人と合うことが少ないので、今までのつながりには積極的につながっていき、更に広がりを増やしていきます。つながりを持つ上で必要なことは、"まずは与える"の精神かなと思います。例えばOSSに貢献したり、便利なものを作って人の役に立ったり。そういうところから人脈を増やしていきたい。
この3つをクリアできた時に、次のステップに移行します!目標は4ヶ月以内!
おまけ
最後に、とても勇気づけられる記事を見つけたので記念に貼ってく。ダニーさんのことはCultureJapanの放送のあたりからずっと見てるけど本当にすごい人。Mirai株式会社、超楽しそう!
社内勉強会を10回開催して感じたこと
このブログにもいくつかエントリーを書きましたが、昨年下期あたりから社内勉強会を開催していました。途中、開催が途絶えかけた時期もありましたが、なんとか10回まで継続して開催することができました。現在は、私が育児休暇に入ったので主催を後輩に引き継ぎましたが、勉強会を開催して感じたことを残しておきたいと思います。
勉強会の趣旨
私の勤務している会社は、システムを開発・運用していますが、開発はほぼ全て下請けに任せているのが現状です。そのため、開発をしたくて入社した一部の人にとっては開発者としてのスキルアップができないことにジレンマを抱えていました。(私もそのうちの一人)。そういう人を部署の垣根を超えて集めて、切磋琢磨しようというのが勉強会の趣旨です。
良かった点
- 通常の業務では関わらない部署やグループの人と交流や情報交換ができた。
- 私と同じようなジレンマを抱えている人が意外と多くいたことが分かった。また、そこまで強い想いではないものの、勉強したいという想いを持っている人もいた。
- それぞれの人に得意分野があるので、いろいろな分野の知識を得ることができた。
- 勉強会で発表をすることで今まで自分が理解していると思っていたけど意外と分かっていないということがわかった。
- 新しいことをするモチベーションを得られた。
見えてきた課題
- 主体的な人と受動的な人がいる。
主体的な人は、自分の成果をLTしてくれたりするが、受動的な人は「勉強したいので教えてください」スタイルなのでこちらから積極的なアクションを起こさないと動いてはくれない。こういう人に対して「はじめての◯◯」的なことを手取り足取りしてあげるのは、私はあまり好きではない。なぜなら、勉強したいと思っているのならネットで「はじめての◯◯」と検索すれば、ある程度の勉強はできるのだから、自分の仕事ではないと思っているし、やったとしてもすぐに忘れてしまうのがオチだと思っている。
では受動的な人が勉強したいと思っていないのかというとそれは違うと思う。勉強したいという気持ちはあるけど、その先の目標がないから「はじめての◯◯」を検索することすらしないんだと思う。つまり、プログラムを修得することは目標ではなく、あくまで目標を達成するためのツールを得るということなので、受動的な人には目標を立ててもらい、目標を達成するには何が必要かを考えてもらうところから始めてはどうかという仮設を立ててみた。残念ながらこの仮説の検証はタイムオーバーとなってしまい実施できなかった。
何人かにこの話をしたら、肯定的な反応が多かったが、もし別の意見があれば頂きたい。なんとなく、私の考えは本当に良いのだろうかとモヤモヤしている。
勉強会のページ
今までやってきたことや発表したスライドなどはここにまとめている。
『Rubyによるデザインパターン』を読み終えて
前回の記事で、"まだまだRubyが分かっていない"と思い知らされたので、2年半ほど前*1に購入して積み本になっていた『Rubyによるデザインパターン』を1週間ほどで読みました。
Amazon.co.jp: Rubyによるデザインパターン: Russ Olsen, ラス・オルセン, 小林 健一, 菅野 裕, 吉野 雅人, 山岸 夢人, 小島 努: 本
また、読んだだけではすぐに忘れてしまうので、後から必要なパターンを探し出せるように本書の内容をまとめておきました。
本書が一貫して伝えていること
- 良いプログラムを書くには、プログラムの結合度を小さくして柔軟性を高める必要がある。そのためには、「継承よりも委譲を使う」「関心事を分離する」「変わるものと変わらないものを分離する」などをすると良い。
- 必要になるまで作るな(YAGNIでお馴染み)。
- パターンの使いどころを誤るな。誤った使い方をしたパターンはよりプログラムを複雑にする。
感想
- 私のように、Ruby(あるいはオブジェクト指向言語)の継承や委譲、ポリモーフィズムの説明的な知識はあるが、実際にどう使えばよいか分からないという人には非常に参考になりました。
- 1つ1つのパターンを、最小の実装から徐々にリファクタリングしていくので理解しやすく、フルスタックではなく必要最小限で再利用することもしやすく書かれています。
- 元祖デザインパターンのGoF本をただなぞるのではなく、Rubyの場合はこういう書き方ができるということを説明しているので、「より高度なRubyの機能」や「Rubyらしい書き方とは何か」ということも同時に分かるようになっています。
次のステップ
メディア芸術データベースのラッパーGemを作ってみました
はじまり
数日前、こんな記事を目にしました。
なんともすごいデータベースが公開されました。しかも利用規約によると、データベースの情報は自由に使うことができて商用利用もOKとのこと。このデータベースを使って何かのサービスを作ろうと考える人も多いのではないでしょうか。しかし、今のところ情報を取得する手段がサイトから検索するしかないので、データベースの情報をスクレイピングするRubyGemを作ってみることにしました。
メディア芸術データベース
簡単にサイトの説明と、今回作成したgemでアクセスできる範囲を説明します。
サイトには大きく分類して次のデータがあります。
- マンガ
- アニメ
- ゲーム
- アート
この中で、今回対応したのは「マンガ」のみ(資料、原画を除く)です。また、蔵書情報など我々が使う上では必要性が低そうな情報は対応していません。
マンガ情報の内容として、次のデータがあります。
- マンガ単行本作品情報・・・あるマンガの単行本や掲載雑誌などの全体的な情報
- マンガ単行本全巻情報・・・あるマンガの単行本全巻の情報
- マンガ単行本情報・・・あるマンガの単行本1巻の情報
- マンガ雑誌掲載作品情報・・・あるマンガの掲載雑誌全巻の情報
- マンガ雑誌全巻情報・・・ある雑誌の全巻の情報
- マンガ雑誌情報・・・ある雑誌の1巻ごとの情報
- 著者情報・・・ある著者の作品などの情報
- 資料情報・・・あるマンガの資料の情報
- 原画情報・・・あるマンガの原画の情報
- その他情報・・・その他の資料(同人誌など)の情報
また検索方法としては大きく分けて次の方法があります。
- マンガタイトル検索
- 雑誌タイトル検索
- 著者名検索
- 詳細検索
はじめてのRubyGem
RubyGemを作るのは初めてですが、スクレイピングは得意技なので簡単にできるだろうと軽い気持ちで作り始めました。しかし、このデータベース、サイトもデータも意外と複雑な構造になっていて、gemのインターフェイス設計にかなり悩みました。
例えば、1つの検索方法から得られる結果が1種類だけではなく複数種類が混在している場合があることや、検索の詳細条件がたくさんありインターフェイスとしてどう表現するか、返された値をどのように表現するか、など。
ぱっと思いついたのは、ActiveRecordのようにそれぞれの情報をそれぞれのClassにして、あるデータの小データをメソッドで取得したり、その逆であったり横方向であったり・・といった機能までできればと思いましたが、まずは単純に検索してハッシュデータを取得だけの機能をサイトやデータの構造にそって作ることにしました。(こういう時に、他の人のコードを読むって大事だなと思います。)
Rubyが分かってない
作り始めてすぐに、Rubyの基本的なことが分かっていない(または忘れている)ことに痛感しました。やっぱりRailsだけやっててもRubyを書けるようにはならないですね。ふだんRailsで使ってるあの機能はどうやって作られているんだろうとか色々と関心が湧いてきました。ソースを見てもらえるとRuby力が低いのがすぐわかると思うので、色々とご指摘を貰えたらと思います。
あと、Rspecを書くのも久しぶりだしRailsでしか書いたことがなかったのでどうしたものかと思いましたが、公開するならさすがに書かないとダメだろうと思い、他のgemのspecなどを眺めながらなんとか書いていきました。これは本当に書いて良かったです。というのも、最初から最後まで色々とインターフェイス設計を試行錯誤していたのでspecがあることで修正漏れが見つけられたのは非常に安心感がありました。テスト大事、テスト大事。
RubyGemsへリリース!
ということでリリースしました。使い方はGithubの方に書いてありますが、詳細なDocument(YARD)は書きませんでした。やっぱりインターフェイスを見なおしてActiveRecordのようにしたいので、書くならその時に書きます。あとは、Travis CIで自動テストさせるようにしました。他にもGithubと連携してくれるツールがたくさんあるので調べてみたら面白そうです。