読者です 読者をやめる 読者になる 読者になる

プログラマとコミュニティ あるいは SD8月号に記事を書かせてもらいました

programming 雑文 日記

表題にあるとおり、Software Design8月号の特集記事を書かせていただきました。GitHub入門的な記事です。

今書店で売ってる号は7月号ですので、今売ってるやつには載ってません(でももちろん買ってくださってもいいんですよ?)。発売日は7/18ですので、その後書店で購入したり、Amazonなどでお求めください。

www.amazon.co.jp

今年に入ってから、web+DB Pressの91,92号、SD8月号と、技術評論社さんの雑誌に記事を書かせていただく機会を立て続けにいただけて、ほんとうにありがたい限りです。

ところで、web+DB vol. 91の記事はYAPC::Asiaでの発表がきっかけでチャンスをいただいたのでした。92はPerlコミュニティつながりで頂いたお話でした。今回の記事に関しては、「Gitをはじめからていねいに」というドキュメントをGitHub上で公開しているのを目にとめていただいてお声がけいただくという経緯でした。

立て続けにこういう機会をいただき、拙いながらもアウトプットを続けていると、目にとめてくださるひとたちはいるのだなぁ、続けるというのは大事だなあというのを実感しています。ありがたいことです。

さて、このあとは壮大な蛇足です。

アウトプットのモチベーションの話

ところで、話が急に変わるようですが、わたしは文学部出身プログラマです。学生時代にきちんとコンピュータサイエンスを学んだことはなく、プログラミングは独学でやってきている人間です(そのため、きちんとしたコンピュータサイエンスのバックグラウンドに支えられた「基礎体力」のある方々に対するコンプレックスが結構強くあるのですが、それはまた別の話なのでおいておきます)。

「独学で」と言いましたが、それは決して「独力で」学ぶことはできないものです。わたしが主戦場としているいわゆるweb系は特にそうだと思うのですが、インターネットには、プログラマコミュニティが書き残してくれた膨大な数の知見が積み重なっています。もちろん、書籍から学ぶことも多かったのですが、それと同じくらい、インターネット上にアーカイブされた素晴らしい情報たちに、わたしはプログラマとして育てられてきましたし、現在も育てられています。

中でも、勉強会のスライドや発表には質の高いものが多いと感じます。これは、プログラマコミュニティがオープンにしてきてくれた、プログラマコミュニティの財産だと感じています。この財産を分けてもらうことで、独力ではできない独学が可能になっているとわたしは強く感じています。

さらに、インターネット上の情報だけではなく、なまのコミュニケーションも、わたしをとても育ててくれています。特に、Hachioji.pmで出会った方々、Niigata.pmで出会った方々、NDSで出会った方々、@9mさんを通じて知り合った方々とは、心理的に近い位置で技術的な相談をしたりされたりする中で、互いに切磋琢磨することができていて、この関係もまたわたしをプログラマとして現在進行形で育て続けてくれています。(この前のヤパチーでもshiba_yuさんやninjinkunさんとコミュニケーションできたことは大きな喜びでした!)

実は、わたしが技術的なアウトプットするモチベーションは、わたしを育ててくれているそんなコミュニティに対する恩返しがしたい、という気持ちが支えています。まあ、とはいえぶっちゃけ、そんなきれいごとだけじゃなくて、承認欲求にドライブされてる部分もめちゃめちゃ多くあるんですけど。でも、それだけではやっぱりやっていけないんですよね。クソリプ的な反応に心折れるし。わたしは、「ほんとうに多くのものをコミュニティや友人たちから受け取っているわたしが、自分の力でできることってなんだろう」という気持ちがなければ継続したアウトプットはできません。

アウトプットをしてたらいいことがあった

で、そうやってアウトプットを続けていたら、いいことがたくさんわたしに降りかかりました。

会社を超えて、プログラマ仲間がたくさんできました。その仲間たちは力強くて、わたしの知らないことをたくさん知っていて、しかもわたしが相談すると惜しみなくその知恵を貸してくれます。

転職や就職ができました。「コネ」ってわけではないけれど、アウトプットをたくさんした結果、「このひとはこれこれこういうことが得意でこういうことはあんまり得意ではないんだな」というのを分かった上で声をかけてくれるので、お互いにミスマッチをあまり心配せずに転職活動や就職活動を行うことができ、これはかなりありがたいことです。

そして、最初の話にようやくつながるのですが、雑誌の記事を書かないか、とお声がけいただくことができました。以前このブログにも書いたことがありますが、昔の夢が思わぬところでかなったりもしました。ありがたい話です。

でも、こんなの全部副次的なものです(とはいえ実際、かなり大きなメリットも享受しているのは無視できない事実だけれど、まあ、気持ちの問題として)。わたしにとっていちばん大きな喜びは、コミュニティから得た財産を、新しいだれかに渡すチャンスをたくさん得られるようになったことです。わたしの大好きな小沢健二の楽曲のワンフレーズに「愛すべき生まれて育ってくサークル 君や僕を繋いでる緩やかな止まらない法則」というのがありますが、まさにその法則のほんの一部にでも自分がなれているという実感こそが、わたしがアウトプットを経て得られているいちばんの果実です。

もし燻ってるひとがいたら、ぜひ一歩を踏み出してみたらいいんじゃないかという話

ようやくこの文章の結論にたどり着きました。だから、もし今この文章を読んでくれてるあなたが、プログラミングが好きで、なおかつアウトプットすることに興味があったりコミュニティに興味があるんだけど、それでもなんか一歩が踏み出せない、なんて状態で悶々としてるなら(そうじゃないならごめんなさい)、心配せずにその一歩を踏み出してみたらいいと思います。

もちろん、わたしはかなり運と縁に恵まれた例であるということは否定できません。なので、生存バイアス的なあれがそれしてる部分もあると思います。でも、プログラミングしてたら、みんな多かれ少なかれコミュニティから何かをもらってるんじゃないでしょうか。だったら、コミュニティからなにかをもらい、自分も誰かになにかを与えるというサークルの中に、一歩踏み込んでみるのは、単なるメリット云々を超えた意味があるとわたしは思います。

ブログを書く、というのもひとつの方法ですが、勉強会に登壇して仲間を見つけるという、ちょっと勇気が必要だけど大きな一歩を、この文章を読んだだれかが踏み出してくれて、上述のようなサークルがまたひとつどこかで産まれて育っていくようなことがあったら、わたしはとても嬉しく思います。

なんか大した実績があるわけでもなければロックスターでもないのに偉そうな言い方になってしまったけれど、「そういうの興味ねーよ」とか「お前に言われるようなことじゃねーよ」ってなってたらごめんなさい。エモいおっさんの戯言だと思って聞きながしてブコメあたりにでも「黙ってコードを書けよハゲ」「で、誰?」とでも書き残して叱責しておくれ。

#yapc8oji 行ってきた

yapcasia8oji-2016mid.hachiojipm.org

YAP(achimon)C::Asia Hachioji 2016 mid in Shinagawa という、八王子なのか品川なのかよくわからない名前(正解は「品川は八王子(哲学)」という態度です)のカンファレンスに、スタッフ、そしてスピーカーとして参加してきました。

スタッフとして

飛び入りトラック、通称Dルームを担当させていただきました。なんかのときに「今回アンカンファレンス的なことやりたいです」とわたしが発言したため、わたしが担当になったといういわゆる「言いだしっぺの法則」というやつですね。

飛び入りトラックは、事前トーク応募には応募しなかった(あるいは、したけどリジェクトされてしまった)方が「それでも俺は喋りたいんだ!」という熱い気持ちをぶつけるための枠として、当日トークを受け付けて当日話してもらう、という枠でした。

飛び入りトラックはその他の部屋に比べるとだいぶ狭い部屋で行ったのですが、発表者と聴衆の距離が狭いため、発表中にもバンバンと質問が飛んだり、逆に発表者が「どうですかね、○○さん」と聴衆に対して投げかけたりという、いい意味でのゆるさがあったように思います。

また、最初からかちっとタイムテーブルが決まっていたわけではないので、ゲリラライブ的な発表が突然始まったり、なかなかエキサイティングな感じで進んでいきました。

当日になるまでだれがトークしてくれるかわからないので、胃に悪かったですが、蓋を開けてみたら「Yet Another」なトラックとして非常に良いものになって安心しています。わたしのわがままを全力でサポートしてくれたuzullaさんとmyfinderさん、D部屋スタッフのみなさん、そして、最高の発表をしてくれた飛び入り参加のみなさん、聞きに来てくださったみなさんに圧倒的感謝 🙏

スピーカーとして

メイントーク

github.com

こういうトークをしてきました。今回はベストトーク賞取りに行くつもりで準備してきました。内容的には尾上さんが以前新潟で喋ってくれた内容に多くを依っていて、その時のトークから学んだこと + わたしがその後日々の開発の中で実践してきたこと + 書籍で学んできたことを全部放出するような内容となっています。スライドには喋った内容の3割くらいしか情報がないというか、むしろ大切なことは全て口頭で喋っているので、ぜひビデオをお待ち下さい。

と思いましたが、ビデオの公開を待たずにプレゼンを実況中継形式でブログに再現するというパワープレーを行いましたのでらこちらをご参照ください!

http://techblog.reraku.co.jp/entry/2016/07/06/070529

午前中の結構早い時間で、想定通り来てるひとが少なかったので、喋り始めた瞬間にベストトーク賞は諦めていました。実際、ベストトーク賞には入れなかったのですが、クロージングで得票数4位だったことが聞けて、本当に嬉しく思っています。聞いてくださった方、投票してくださった方、本当にありがとうございます。

飛び入りトーク

github.com

自分が担当する部屋で自分がしゃべるという掟破りで、同僚と一緒に飛び入りトークで喋りました。事前に打ち合わせ一切ない状態で漫談を始めたのですが、いつも会社で話してることの延長を人前でやるというだけだったので、楽しくしゃべることができました。結構いろんなひとが聞きに来てくれて、なおかつ聞きに来てくれている方からも活発に意見がでてきて、飛び入りトークをやってよかったなぁ(スタッフとしても登壇者としても)と思えてよかったです。

聴衆として

Dルームスタッフなので、基本的にDルームにいましたが、Dルーム初日一発目の ninjinkun さんのトークが最高でした。問題に対してチームで誠実に向き合い、チームがそれぞれの専門性を活かして協働して解決する。プログラマとしての誠実さをビンビン感じる最高のトークでした。

トークだけではなく、普段話せないひとたちと議論できたことも大きな楽しみでした。とくに ninjinkun さんと shiba_yu さんとはかなり熱く設計トークができて最高でした。Fluxアーキテクチャの話はもっとたくさんしたかった。絶対にまたやりましょう。

まとめ

とにかく最高だった。uzullaさんの人徳すげえ。

あと、みなさん、やぱちーのブログを書いたらここに報告しましょう。

docs.google.com

書き忘れてた!!!!MSの会場まじで最高だったのでMSに圧倒的感謝🙏

WEB+DB PRESS vol.92感想

会社のほうのブログでも書きましたが、WEB+DB PRESS vol.92に記事を書かせていただきました。

techblog.reraku.co.jp

見本誌をいただいたので、感想を書きます。

今回は新人さん応援号ということで、新人さん向けの記事が多い感じですね。個人的には新連載陣がかなりアツいですね。kazeburoさんによる「大規模インフラ運用最前線」ではメルカリが米国向けサービスと日本向けサービスで異なったインフラ基盤を使っているのが知れて「へー!」って感じでした。「Javaの新定石」もめっちゃよかったです。わたしは最近なぜか主にiOS向けアプリ開発でSwiftを利用していますが、本業(?)はScalaでの開発です。ScalaJavaの親戚みたいなもん(?)なのでJavaのこともある程度知っている必要があるのですが、わたしがJavaを書いていたのは遠い昔の話なので、こういう「Javaの最近」にキャッチアップできる連載は嬉しいですね。

全体的に、今回の号は適度に広く浅くという感じで、この「適度に」の部分が本当に適度で、「役に立たないほど浅い」というわけではないし、「深入りしすぎて厳しくなる」みたいな感じでもないので、一家に一冊というか一社に一冊買っておいて損はない号だなーという感想をもちました。みんなも買おう!Amazonなら予約受付中、本屋ならば今月23日発売です!

www.amazon.co.jp

遠く離れたところで昔の夢が叶ってしまった話

なんだか久しぶりの投稿です。前の記事を投稿してからしばらくかなり忙しい日々が続いており、仕事の進捗は出ているのですがブログの進捗がお亡くなりになっていました。逆よりいいと思うことにします。

ところで、「かなり忙しい日々」の中に実は「雑誌への記事の執筆」というものが入っておりました。先に結論をいうと、WEB+DB PRESS Vol.91に「[すぐに使えてずっと役立つ!]データ構造の基礎知識 ── 配列、リスト、ハッシュテーブル、木構造」という特集記事を書かせていただきました。なんと!特集記事です。まじかよ。

www.amazon.co.jp

記事の内容について

WEB+DB PRESSは、プログラマとして働き始めてからほとんど毎号購入して読んでいる雑誌で、そのような雑誌の特集を執筆させていただけたことは本当にありがたいことだと感じていますし、とても嬉しく思っています。内容としてはデータ構造と計算量についての内容で、知っているひとから見たらたいしたことは書いていないのですが、なんとなくしか知らなかった方や、知っているけど日々の業務となんだか結びつかないなあという感じになっている方、あるいはデータ構造についてほとんど知らないけど興味はあるというような方にとって、10年20年先までちゃんと活かせるような内容の記事になったと自負しております。良いと自負できるものが書き上げられたのは、編集の村下さんによるところが大きいです。ありがとうございます。ぜひ読んでいただければなと思います。

壮大な蛇足、またはこの記事の本文

わたしは様々なところで「文系プログラマ」を名乗っていますが、その理由として、自分が文学部出身である、ということがあります。わたしはわたしなりのありかたで自分の仕事に誇りを持っていて、プログラマとして一流でありたい、といつも思っています(実力が追いつかないのが悲しい!がんばるしかない)。なので、文系卒である、ということを自分の無能の言い訳にだけはしたくないと思っているのですが、その一方で、大学時代に文学部で学んだことがわたしの人格の半分以上を作り上げているという実感も持っています。プログラマであることと、文学部卒であることは、わたしのアイデンティティにおいてどちらも重要なことです。

そんなわたしですから、もちろん、「本」というものに対してはそれなりの思い入れのようなものがあります。文学部にいたときには、漠然とではありますが「商業誌になんらかの形で関わりたい」という思いも、もちろん持っていました。そんな中で、大学の友人のうち何人かは実際に編集者としてバリバリ働いていたり、いわゆる「批評家」としてそれなりに名前を売ってたりとかするんですが、やっぱりそういう友人たちは学生のころから彼らのやりたいことに対して真摯であり、真剣でした。わたしは彼らとは違い、プログラミングの世界に進んだのですが、これはある意味では「本の世界」との決別でもありました。「いつか商業誌になんらかの形で関わりたい」なんて思っていたことは、忘れたわけではないけれど、「そんな思いもあったなぁ。その思いに突き動かされてやってきたことは今直接に役に立ってはいないけど、なんだかんだいって自分の大事な一部分になっているよなあ」くらいの感じで、ありていにいえば「終わった夢」としてわたしの中に眠っていたものでした。

ところが、です。ひょんなことから技評の村下さんにお声がけいただき、「商業誌に自分の書いたものが活字になって載り、それが日本中の書店に並ぶ」という、終わったはずの夢が、当時思っていたのとは全く異なるルートから実現してしまいました。これは本当に青天の霹靂というか、人間万事塞翁が馬というか、瓢箪から駒というか、運と縁に恵まれたと思っています。

わたしはよく「人生9割は運と縁」と言ってるのですが、本当に自分の運と縁が最高すぎて、このままどっかで大暴落が待っているのではないかと不安な日々です。話がとっちらかっている。なんの話なんだこれは。とにかく、昔の夢が「終わった夢」になったあとも、別のことに一生懸命になってると、運と縁がからんで急に変なところからぽっとその夢がまた芽吹いたりするのだなあ。という感じです。

最後にもう一度内容について

もう一度言いますが、データ構造について、なんとなくしか知らなかった方や、知っているけど日々の業務となんだか結びつかないなあという感じになっている方、あるいはデータ構造についてほとんど知らないけど興味はあるというような方にとって、10年20年先までちゃんと活かせるような内容の記事になったと自負しております。ぜひ!読んでやってください。

あと、蛇足っぽいですが、記事書いてみて思ったんですけど、ものすごい量と質の知識、知恵を、常にわかりやすく読者に伝え続けている結城先生って化け物だと思いました。もともと結城先生のことをめっちゃ尊敬していましたが、自分で記事一本でも書いてみて尊敬が畏怖に変化しました。結城先生、そのうち学問の神様みたいな感じの祀られ方するんじゃないのか……。

www.amazon.co.jp

既存のクラスをScalazで定義されている型クラスのインスタンスにするの巻

この記事はScala Advent Calendar 2015(Adventar)の9日目の記事です。

Scalaには型クラスのための仕組みがあるぞ!

Scalaには、型クラスを実現するための仕組みとしてimplicit parameterという仕組みがあります。これとimplicit conversionを組み合わせることによって、オーバーロードやinterfaceでは実現できないようなオープンな演算の定義と安全性を両立させることができます。

このあたりの話は http://nekogata.hatenablog.com/entry/2014/06/30/062342 などを参照してください。

Scalazとかいう怖いライブラリもあるぞ!

Scalaの怖いライブラリの代表格として、Scalazというものがあり、ここでは様々な便利な型クラスが定義されています。たとえばそのなかのひとつに「Order型クラス」が存在します。

このOrder型クラスは、「順序があるよ」という性質を表した型クラスになっており、scala標準の型でも、Stringなど様々なクラスがこの型クラスのインスタンスにされています

また、Order型のインスタンスになることで、implicit conversion経由で "<" や ">" などの便利メソッドが使えるようになります

自分で手出しできないライブラリを型クラスのインスタンスにするぞ!

たとえば JodaTime を利用しているとき、AbstractInstantなインスタンス を > や < で比較できたら便利だなー、などと思ったとします。AbstractInstantな型をOrder型クラスのインスタンスにしてしまえば実現できそうですね。実際にやってみましょう。

まずはOrder型クラスの定義を見に行きます

見てのとおり、orderメソッドだけ実装されていないtraitがその実態です。ということは、orderメソッドを実装したAbstractInstantOrder[A <: AbstractPartial] extends Order[A]なオブジェクトへのimplicit conversionを定義してやれば、DateTimeなどのAbstractInstantのサブクラスのインスタンスを < や > で比較できるようになるはずです。(このへんの理屈がわからない場合は、しつこいようですが http://nekogata.hatenablog.com/entry/2014/06/30/062342 を参照してください)

自分でがんばってobject AbstractInstantOrder[A <: AbstractInstant] extends Order[A]を定義して、それへのimplicit conversionを定義してもいいのですが、Order.scalaを読んでいたらこんな便利なメソッドを見つけました。order[Nyan] {(a, b) => ???}としてやれば、new NyanOrder extends Order[Nyan]{ def order(a: Nyan, b: Nyan) = ??? }を返してくれる便利なやつです。こいつとimplicit conversionを組み合わせてAbstractInstantな型をOrder型クラスのインスタンスにしてやると、こんなかんじになります。

object JodaTimeOrder {
  implicit def JodaTimeInstantOrder[A <: AbstractInstant]: Order[A]  = order { (a, b) =>
    if (a.isBefore(b)) scalaz.Ordering.LT
    else if (a.isEqual(b)) scalaz.Ordering.EQ
    else scalaz.Ordering.GT
  }
}

これで、JodaTimeのAbstractInstantなクラスすべてを、Order型クラスのインスタンスにすることができました!使うときには、以下のようなかんじになります。

import JodaTimeOrder._
import scalaz.Scalaz._

if (dateTimeInstanceA < dateTimeInstanceB) {
  // Bのほうが後の日時
} else {
  // Bのほうが後の日時ではない
}

自分で書き換えることのできないようなクラスも、ちょっとしたグルーコードを書いてやることで型クラスのインスタンスのしてやることができましたね!

最後に

既存のクラスをScalazの型クラスのインスタンスにする例を見てみました。Scalazのコードを読みながら「なるほどこうやればいいんだな」みたいなかんじでやっていけばできることではあるのですが、「わざわざコード読まなくてもここに書いてあるよ」みたいな情報を知っているひとがあればぜひ教えてください。

YAPC::Asia 2015 で発表しました #yapcasia

Perlで学ぼう!文系プログラマのための、知識ゼロからのデータ構造と計算量」というタイトルでYAPC::Asia 2015 で発表してきました。

yapcasia.org

http://yapcasia.org/2015/talk/show/9f7059dc-003c-11e5-a00c-89c77d574c3a

上記のリンクからスライド、動画(そのうちアップロードされるでしょう)が見れます。

スライドはほとんど説明のための図にとどまっており、口頭でいろいろと説明したので、当日入場制限で入場できなかったとか、チケットが手に入らなくて来られなかった方はぜひ動画を見ていただけると幸いです。

わたしはプログラマとして活動し始めてから、Perlコミュニティのひとたちが対外的に発表してきたトークや資料、ブログ、あるいは直接のコミュニケーションなどで、直接、間接にかなり助けられてきていて、そのおかげで今の自分があると思っています(まだまだ学習すべきことは多く、これからもお世話になります!)。

そんななかで、「コミュニティへの恩返し」ってなんだろう、と思ったとき、ハッカーとしては1流ではないけれど、「わかりやすく説明する」とか、「参入障壁の低い感じのつながりをつくっていく」いう自分の得意分野でなにかやればいいんだ、と思い、ブログでなんか書いたり発表したりというのをやってきました。

懇親会でお話をさせていただいた方々やtwitterでの反応などを見ると、なかなか上々な反応をいただいていて、今回の発表では、初めて「それなりにコミュニティに恩返しができたかなぁ」という実感を得ることができました。YAPC::Asiaは今年でひと段落ですが、そういう節目の年にこういう機会を与えていただいて、スタッフの方やソーシャルボタンで応援していただいた方や当日発表を聞きに来ていただいた方への感謝の念でいっぱいです。

ありがとうございました!

プログラミングの「抽象化」ってどういう意味で、なぜ必要なのか

<追記>いろいろ反応あってたしかになーって思いましたが、ここで説明されてるのは「汎化」とか「パラメタライズ」としたほうが正しいですね。抽象化というと、一塊の手続きをブラックボックスにして、実装を隠蔽する面のほうが正解に近いです。でもまあそこを差し引いて読んでいただければ、それなりに有用ではある記事だと思うので、このまま残しておきます</追記>

プログラミングに限らない話かもしれませんが、ふだんの生活で触れないような概念というのは、一度わかってしまえば便利なんだけど、どうしてもとらえどころがない、というようなことが多いと思います。プログラミングにもそういう概念はたくさんあって、わたしのような凡人は新しい概念にぶち当たるたびに苦労しています。今日はそんな中で「抽象化」という言葉について、「昔の自分にこうやって説明してあげたかったな〜」という説明をします。

プログラミングを学んでいく中で、「とりあえず処理が書ける」というところから一歩進んで「良い設計ってなんだろう」ということを考え始めたとき、いきなり「抽象化」という言葉が出てきて面食らったことはありませんか?わたしはあります。「抽象化ってこういうことだよ」という説明のないまま、「抽象化」の事例をたくさん見ることで「うーん抽象化ってなんとなくこんな雰囲気……」みたいな感じでお茶を濁す感じになる事例というのはけっこう多い気がしています。

そんなふわっとした「抽象化」という言葉ですが、わからないときは逆の言葉の意味を考えて見るといいでしょう。「抽象的」の反対は「具体的」ですね。つまり、「抽象化」というのは「具体的じゃない状態にする」ということだと思えばいいでしょう。まだちんぷんかんぷんですね。例で考えてみましょう

たとえば、「user_id:1のユーザーの所持金額のうち50Gを、user_id:2のユーザーに移行する処理を作ってくれ」という指示が出ているとします。これを愚直に実装すると、以下のような感じになるでしょうか(トランザクションとかそういう話は今回の話に直接関係ないので無視します)。

def transfer_gold
  # user_1 から50G引いて
  user_1 = User.find(1)
  user_1.gold -= 50
  user_1.save!

  # user_2に50G足す
  user_2 = User.find(2)
  user_2.gold += 50
  user_2.save!
end

このコードを、「具体的じゃなくして」行ってみましょう。

今はuser_id:1のユーザーとuser_id:2のユーザーという「具体的な」ユーザーを直接コードで書いていますね。ここの「具体性」をなくしてみましょう。

def transfer_gold(from_user_id, to_user_id)
  user_a = User.find(from_user_id)
  user_a.gold -= 50
  user_a.save!
  
  user_b = User.find(to_user_id)
  user_b.gold += 50
  user_b.save!
end

はい、ユーザーidを引数で与えるようにしました。これで、コードからは「具体的なユーザーid」を排除して、ちょっと「具体的じゃないコード」になりましたね。

もうちょっと具体性を排除していきましょう。今は50Gという具体的な金額がまだコード上に残っています。これも引数で渡してあげましょう。

def transfer_gold(amount, from_user_id, to_user_id)
  user_a = User.find(from_user_id)
  user_a.gold -= amount
  user_a.save!
  
  user_b = User.find(to_user_id)
  user_b.gold += amount
  user_b.save!
end

はい。これでコードからはさらに「具体性」がなくなりました。こんな感じで、「具体的な値」とかをコードから排除していってコードの具体性を減らす行為全般を「抽象化」と呼ぶと考えて良いでしょう。

ところで、具体的な値をコードから追い出したことによって、なにが起こったでしょうか?具体的な値がベタ書きされていたときと違って、コードが「いろんな値に対応するようになった」ということが言えるでしょう。引数に10Gとuser_id:3とuser_id:4を渡せば、user_id:3からuser_id:4に10G移行することもできるし、20Gとuser_id:5とuser_id:6を渡せばuser_id:5からuser_id:6に20G移行することもできます。

さて、いいことづくめのように見える抽象化ですが、今度は「そのコードを使う側」の視点から見てみましょう。もしプログラムに具体的な値がベタ書きされていた場合、使う側はなにも考えずにそのコードを実行すれば良いだけです。一方、抽象化されたコードの場合、使う側が「どのユーザからどのユーザにいくら渡すのか」ということを判断しなければなりません。

そこに注目すると、抽象化というのは、具体的な値としてなにを使うのかという「判断の責任」を「そのコードを使う側」に押し付けることでもあることが見えて来ると思います。

言い換えます。抽象化されていない具体的なコードでは、メソッドの側に「具体的な値はこれとこれ!」ということが書いてあるので、呼ぶだけで具体的に意味のある処理が実現されます。一方、抽象化されたメソッドでは、メソッドを呼ぶ側がそこに「具体的な値」を与えることではじめて具体的で意味のある処理が実現されます。

まとめると、抽象化によって、使うときにいろんな値を突っ込んで使うことができ、柔軟になるというメリットを得る一方で、使うときにその都度使う側が「どんな値が適切なのか」ということを判断する責任を負うというデメリットも負うことになるわけです。

note:ところで、さきほど「具体的な値」「とか」 をコードから排除する、と書きましたが、とか、というからには、値以外のものも抽象化することが可能です。抽象化のレベルが上がってくると、値だけではなく、たとえば計算内容そのものを抽象化したり(高階関数やストラテジーパターンなどがそれを実現します)、型を抽象化したり、というパターンも出てきます。しかし、どんな抽象化も、「具体的な<なにか>」をコードから排除して、そこを「入れ替え可能なもの」にするという点では共通しています。「抽象化」という言葉がでてきたときには、「ここではどんな具体的なものをコードから引っぺがしているのだろう」と考えてみると、すっきりと理解できることが多いでしょう。

さて、以上の議論を踏まえた上で、「世界一抽象化されたコード」というのを今から書いてみましょう。一瞬でかけます。

# nop

上にあげたものがそうです。つまり、「なにもしない」というコードこそが、世界一抽象化されたコードです。冗談を言っているわけではありません。抽象化とは「具体的な値や処理などをなくして、使う側が必要なそれを選べるようにする」ものでした。では「はい、まったくなにも書かれてません。ここに必要な処理を書いていってください」というのが、究極に抽象化されたコードになるのはなにも変なことではありません。こんな落語みたいなことを言ってなにが主張したいのかというと、それは「抽象化すればいいってもんじゃない」ってことが言いたいのです。

抽象化はあくまで「具体的な判断を遅らせることで柔軟性を得る」ためのものです。コードが具体的な処理を行うためには、必ずどこかでその「具体的な判断」をしなければなりません。冒頭の例ならば、必ずどこかで引数に具体的なuser_idや金額を与えなければならないわけです。

そうである以上、プログラムの設計では「どこを抽象化するのか」「どこまで抽象化するのか」という判断が必要になってきます。しかし、「抽象化」のメリットデメリットを理解した今なら、その判断の一助になるものさしを持っています。それは、「具体的な判断は誰がするべきなの?」という視点です。

たとえば最初にあげた抽象化の例ですが、アプリケーションの仕様上、本来はお金の移行というのはありえない処理で、事故処理のためにめっちゃ特別に今回限りのスペシャル対応としてたった一回だけ行われる処理なのであれば、抽象化されてないメソッドのほうが、「使う側の負担」は少なくなりますね。なぜなら、使う側が「えーっと今回の事故処理ではだれからだれにいくら移行しなきゃいけないんだっけ」ってことを考えなくていいからです。一方で、どんなユーザーからどんなユーザーにいくらでもお金の移行が行われ得るような仕様のアプリケーションならば、移行が行われる都度「だれからだれにいくら」という判断をしなければいけないので、抽象化して「メソッドを使う側」にその判断をしてもらうべきでしょう。

かように、「正しい抽象化」というのはアプリケーションに求められている性質によって異なってきます。プログラムの設計とは、「このアプリケーションにはこういう性質があるから、だからここは抽象化して「使う側」に判断の責任を持ってもらおう、逆にここは具体的に書いておこう」ということを考えることでもあると言えるでしょう。

抽象化するための方法はいろいろあります(メソッドにして引数で渡すようにするとか、デザインパターンとか、型クラスとか……)が、それはあくまで「実装方法」であり、設計そのものではありません。実装方法をたくさん知っていることは武器にはなりますが、実装方法を知っているからといってむやみやたらに抽象化をしまくったとしても、それは単に責任の所在がいろんなところにとっちらかってて使いにくいプログラムにしかなりません。ギターの早弾きができることは武器になりうるけど、音楽的に意味のない早弾きは曲芸でしかないみたいなもんです。抽象化の方法をたくさん知った上で、アプリケーションが求める抽象化を正しく見出せるようになりたいものですね。

ブックマークコメントでいろいろ補足や指摘されていて、もっともな話が多いので、そちらも参考にしてください。とくにこのコメントは「まじでそのとおりですね!」という感じです。

プログラミングの「抽象化」ってどういう意味で、なぜ必要なのか - 猫型の蓄音機は 1 分間に 45 回にゃあと鳴く

これは抽象化の役割のうちパラメタライズに注目した説明。抽象化には他にも様々な問題に共通する構造を取り出すという役割があり、それは時に思考の足場や指針を与える。nopの例えが変なのは後者を考えてないから。

2015/08/05 09:00

なお過去に書いた抽象化の記事として適切に抽象化されたコードとはなにかって話というのがあり、こちらではこの記事で触れることができなかった抽象化の側面について触れています。よろしければそちらもお読みください。

宣伝

8/20,21,22に開催される、プログラマフジロック(あるいはプログラマの夏コミ)とも言えるYAPC::Asia 2015 にて、Perlで学ぼう!文系プログラマのための、知識ゼロからのデータ構造と計算量という発表をします。今回の記事の内容とはまたちょっと趣が変わって、もうちょっと実装よりの話になりますが、なるべくわかりやすい発表を心がけますので、気になった方はぜひ聴きに来てください。

なお、すでにチケットは完売しておりますが、なんとイベントレポーターになるとタダでYAPCに参加できるという裏技が存在しております!ぜひご検討ください。