あなたの職業は何? RPG風のエンジニアの分類を作ってみた

ひとくちにエンジニアと言っても、いろんなタイプの人が居て、性格に応じたロールがある。 たとえば「◯◯さんはやたら設計に拘って動きが遅いけどバグは出さない」とか「◯◯さんは手が早いけど、よくバグも作りこむ」とか「◯◯さんはいつもCIと叫んでる」とか。

こういったそれぞれの性格のメンバーが自分にあったロールをこなすことによって、良い開発プロセス/運用プロセスってのは出来ていくと思う。

そういったロールを自分なりに分類してDQ風の職業にマッピングしてみた。 というのも以前飲み会でDQ風にエンジニアのスキルマップを作ってる人がいて、なんか面白そうだったから真似してみただけなんだけどw

偉大なる先達の「プログラマの区分」よりも、抽象度を上げてるので、プログラマだけじゃなくて、インフラ屋さんとかもそれなりに当てはまるはず。

僧侶と魔法使いの区分が分かりづらいけど、 イメージとしては品質を上げるための活動と生産性を上げるための活動の違いかな。もっとも、それらは密接に相関があって切り分けしづらいのだけど。

あと、複数の職業を兼任してるとかは普通にあるとおもう。

職業

戦士
  • 戦闘(開発/運用)の要
  • 重厚な設計、検証された方法を好む
  • 守りは固いが、素早さは低め
武道家
  • 戦闘(開発/運用)の要
  • 軽量な設計、新しい方法を好む
  • 素早さは高いが、守りは低め
僧侶
  • 品質を維持するための魔法を使う
  • レビューやテスト、静的コード解析やCI/CDを好む
  • 盗賊と連携することでより強力な魔法を使うことができる
魔法使い
  • 強力な魔法を操り、戦士や武道家を支援する
  • フレームワークや共通ライブラリを弄ることが多い
  • 盗賊と連携することでより強力な魔法を使うことができる
盗賊
  • 他所のベスト・プラクティスを盗んでくる
  • 基本的に他の職業と兼任してることが多い
  • 外部のイベントによく参加している
商人
  • お金の計算が得意。外部からの調達も行う
  • ROIにもとづき自分たちが"しないこと"を計算できる
  • 限られたリソースを最適なところに投入するために重要な職業

 振り返り

さて、せっかく作ってみたので自己分析をしてみる。

武道家(lv 6), 盗賊(lv 5), 魔法使い(lv 4), 僧侶(lv 3)

Lv 10を一つの基準にするとだいたいこんな感じかな?  いろんな職業についてるので職業技能はそれなりに持ってるんだけど、それぞれのレベルは低いイメージ。

今後の成長プランとして、武闘家とかのレベルをもっと上げるべきか、いっそのこと商人を採って技能を増やすべきかは悩ましいところ。

ちなみにこの職業はバランスよくパーティが構築されている必要があると思う。 一つのパーティに攻撃職、魔法系職、商人が居て、盗賊は全員がLv1以上とってるとかがバランスいい気がする。 戦士や武道家だけでパーティー組むとか縛りプレイの粋だよね?

ただ、現実はクソゲーと言う言葉があり、縛りプレイ大好きな日本人は「戦士、武道家、武道家、武道家」というパーティもよくあるとか。 今いるチームもこの構造な感じで、ギルド所属? の商人、魔法使い、僧侶が複数のパーティーをまとめて面倒見てる感じ。そして、輪をかけて盗賊が少ない。。。

デザインパターンじゃ無いけど、こういったチームメンバの傾向やロールに名前を付けることで、「盗賊が足らない」とか「戦士のスキルを磨きたい」とかチーム戦略や自分の成長プランを考えなおすのに参考になるんじゃないかと思う。

人事系の部署とかはこんな思いつきで作ったようなのじゃなくてちゃんとしたの持ってるだろうけど、自己分析ならこのくらい馴染みのある奴のが自分は好きかな。

でも、この手のロールをファンタジー系職業で表すのは定番といえば定番なので、エンジニアのスキルセットを「ツンデレ」とか「幼なじみ」とかヒロイン属性風に表すとかのが頭がおかしくて良かったかもしれない。誰か作って!

それでは、Happy Hacking!

ドキュメントからコードへ

最近「ドキュメントからコードへ」というのをキーワードに考えています。 その辺に関してつらつらと書いてみました。例のごとく英語で書いた資料より日本語の方が詳しいよ><

「ドキュメントからコードへ」って?

例えばいくつかの種類のドキュメントは下記のようにコードに置き換えることが出来ます。

詳細設計書、テスト仕様書 => 自動テスト

サーバの構成定義書 => サーバテストツール

  • serverspec

インストールマニュアル => プロビジョニングツール系

  • chef/puppet

運用手順書 => デプロイツール, JOB管理ツール, CI ツール

  • Capystrano
  • Fabric
  • Jenkins

他にも要件定義や基本設計をAlloy等で作るのもこの範疇に入るかもしれないです。 ドキュメントを自動ツール系のスクリプト定義に置き換えることが「ドキュメントからコード」となります

そもそもなんで必要?

さて、そもそもなにがうれしいんでしょうか? まず思いつくのはコスト削減。 自動化をすることで手作業でやっていたことがボタンひとつでできるようになります。 これはとてもわかり易いですね。では、本当にそれだけが価値でしょうか?

「ドキュメントからコードへ」に移行することで真に得られるもの、それは作業コストの削減ではなく信頼性です。

ここで言う信頼性は大きく分けて下記の3つです。

  • プロダクトの信頼性
  • オペレーションの信頼性
  • ドキュメントの信頼性

プロダクトの信頼性とはシステムのコードの信頼性です。 自動テストツールを入れることで、今まで目視で確認していた様々な項目を簡単に再実行することが出来ます。 これはリグレッションテストをするにあたって強力な武器です。リグレッションテストはデグレや修正の影響を把握するための基本的な方法です。 これによって、コードの品質が保てるというのは分かりやすいかと思います。

プロダクトだけではなく、オペレーションの信頼性もコード化で担保出来ます。 日常の些細な業務から、本番へのデプロイを始め、システム運用にはオペレーションがかかせません。 しかし、それを実施するのが人間であるかぎりミスを犯します。それは確率的な話なので、頻繁にやる作業ほどミスをする可能性が高いといえるでしょう。 一方、プログラムは間違えません。プログラムは書いたとおりには動くので、間違ってなければ正しく動きますし、修正すれば同じ失敗もしません。 これはプロダクトの品質にかなり大きな影響を与えます。

個人的にはもう一点重要な要素としてドキュメントの信頼性向上があります。無論ここで言ってるドキュメントとはコードです。

ドキュメントは多くの場合間違っています。理由は様々です。ドキュメントを作った時点と変わった修正が反映していない。元のドキュメントにミスがある。そもそもドキュメントを見て作っていない。 ドキュメントは容易に壊れます。ドキュメント管理が脆弱な組織では、ドキュメントを見ても結局信用ができないのでコードも見るということはよく有ります。

最後に信用できるのはコードだけ、です。その信頼性の差が何でしょうか? それは実際に動いて使われていることです。 もし、間違えていれば動かない。あるいは要件レベルでバグっていたとしても今動いているものは書いてあるとおりだ、ということが論理的に保証されます。 これは運用をするにあたって大きな安心感を与えてくれます。この1点のためだけでも、仮にドキュメントより作成コストがかかってもコードに落とすべきだと考えています。

まとめ

TDDやBDD, DevOpsで言われるインフラのコード化, Jenkinsなどによるオペレーションの自動化、様々な手法がありますが、作業手順書を無くし自動化することは単なる作業のコスト削減ではありません。 プロダクトの信頼性、オペレーションの信頼性、そしてそれらを支援するドキュメントの信頼性。これらを現実的なコストで実現できるようになります。 つまり、ここで削減してるコストは既存の作業コストではなく、今まで高くて支払えていなかった98%の信頼性を99%にするためのコストです。

作業コストの削減だと割に合わないと思ってた人がもしいましたら、信頼性向上のためという考え方でぜひ実施してみましょう!

それでは、Happy Hacking!

テスタブルコードの書き方 - 基本戦略編

今のチームにテストコードの導入を本格的にしようと思ってるので、思考の整理がてらメモ。内容は初学者向け。

テストの必要性をとくのは比較的簡単である程度できた。既存のレガシーコードはとりあえず忘れることに(特定メンバーでプロジェクト的に実施)。

というわけで、新規コードはみんなテスト書いてね! 

と、これだけでテストを書いてくれるでしょうか? 答えは否でした。

原因として自分の書きたいコードをどうテストすれば良いかわからないというものです。

新規コードなのでテストをしやすいように設計をすれば良いだけです。TDDはそれを支援してくれる有効な手法です。 しかし、テストが無い環境に慣れた人間はそもそもテスタブルコードを見慣れてません。なので、自分の書きたい実装をどう書けばテストが書きやすくなるかが分からないのでテストコードが非常に複雑になったり、立ち止まったりしてしまいます。

なので、テスタブルコードの基本戦略と事例集をまとめてみました。

基本戦略

  • 戻り値が無いコードを書かない
  • 同じ引数では同じ結果を返す
  • I/Oはそれに専念する
  • 依存性は注入できるようにする

戻り値が無いコードを書かない

Javaで言えばvoid型のメソッドです。なんというかテストを書くことを意識してないコードの典型例です。

戻り値が無いコードは後述するI/Oを含んだコードである可能性が高く、I/Oのテストはコストが高いものです。 なので原則的には単純に値を返すシンプルな関数を実装するのがコツです。

同じ引数では同じ結果を返す

例えば日付、例えば乱数。こういった実行される度に結果が変わる値って存在しますね?

こういった値をロジックの内部で使っていると同じ引数でも毎回違う結果になってしまいテストを記述出来ません。 なのでこの手の値は関数の引数にとったり、後述の依存性の注入を使うことでロジックから切り離してしまいましょう。 こうすることで、ロジック自体は簡潔にテストを書くことが可能になります。

I/Oはそれに専念する

ファイルの入出力、DBアクセス、ネットワークアクセス、標準入出力、ログ、画面、こういったI/Oはテストの敵です!

これらをテストすることは不可能ではありませんが、記述量的にも実行速度的にもコストが高いテストになりがちです。また、DBやネットワークの場合はテスト向けの環境を用意するのも頭を悩ませる問題です。 こういった部分はなるべく減らして、場合によってはテストコードではなく別の方法で実施しましょう。そのためにはI/Oとロジックを分離してロジックの部分だけをUTできるように分離するのが重要です。

依存性は注入できるようにしよう

依存性ってなに? とか言われそうですが、ようは前述してるI/Oや日付、乱数なんかを取り扱うオブジェクトをクラス内部でnew(初期化)せずにコンストラクタやsetterで外から設定できるようにしよう、という考え方です。

DIコンテナとか使うと、こういった設計でプロダクトコードを書きやすくなりますが、必須ではないです。 逆にDIコンテナ使ってても、外から設定できるようにすることを意識してないと、とても面倒なコードになりがちです。

フィールド値はすべてコンストラクタやsetterで設定できるようにするか、package属性(default)で記載するとテストコードを非常にシンプルに書けます。

まとめ

とりあえずこの辺が基本的に意識することになると思います。 とはいえ、これだけで具体的にどう書くか分かる人はすでに書き方が分かってる人だと思うので、明日は具体的な事例集を書きます。

それではHappy Hacking!

参考

JUnitで現在時刻が関わるテストを解いてみた

これであなたもテスト駆動開発マスター!?和田卓人さんがテスト駆動開発問題を解答コード使いながら解説します~現在時刻が関わるテストから、テスト容易性設計を学ぶ #tdd に書いてある問題がUnitTestを書いていく上での教材にとても良さそうだったので、自分のベンチマークがてら書いてみました。

【仕様1】 「現在時刻」に応じて、挨拶の内容を下記のようにそれぞれ返す機能を作成したい。

まずは問題1をシンプルに問いてみました。

記事でも言及されてますけど、時間を扱った問題は普通にテストを書くことが難しいです。 環境に依存したデータのでテスト毎に結果が変わってしまうからです。他にも外部のWebサイトとか、別のシステムとかそういったパラメータが入ると同じ理由で普通にテストできません。

なので、まず考えたことはDate型を引数に渡して、テストコード側で現在値を設定できるようにすることです。 こういうのは依存性を注入できるように実装するのが王道ですしね。

ただ、Javaで任意のDate型を初期化するのは面倒なので、いったんintでhourとminuteを受け取るテストとメソッドを定義。

    @Test
    public void greeterWithMorning() {
        Greeter greeter = new Greeter();
        assertThat(greeter.greet(5, 0), is("おはようございます"));
        assertThat(greeter.greet(11, 59), is("おはようございます"));
    }

後はベタにRed => Greenのサイクルを回して仕様を満たしていきました。 その後、下記のようにint型ではなく日付型を受け取るメソッドを定義し直します。

    @Test
    public void greeterWithDate() {
        Greeter greeter = new Greeter();
        assertThat(greeter.greet(time(6, 0)), is("おはようございます"));
        assertThat(greeter.greet(time(12, 0)), is("こんにちは"));
        assertThat(greeter.greet(time(23, 0)), is("こんばんは"));
    }

境界値のテストとかはint型のケースで試してるので、書いてません。timeメソッドはさすがにCalendarの初期化を毎回書くのが面倒なので独自定義。 実際の開発ならDateUtils的な何かを入れてるはずなので、それを使うべきだと思います。

問題1はこんな感じ。intの実装は最終的には消してDateの実装だけにしたほうが、実装の詳細が残らないからいいかなぁ、とも思ったんですが、問題2でリファクタリング必要そうなのは分かってたので、いったんこのままで。全体のコードはこちらのgist.

【仕様2】 「現在時刻」と「ロケール」に応じて、挨拶の内容を下記のようにそれぞれ返す機能を作成したい。

同じ時間でもロケールが日本語なのか英語なのかで挨拶を変える課題です。単純にインタフェースを定義するとこんな感じでしょうか。

    assertThat(greeter.greet(time(6, 0), Locale.JAPAN), is("おはようございます"));
    assertThat(greeter.greet(time(6, 0), Locale.ENGLISH), is("Good Morning"));

パッと見の感想として、引数が2つになっています。となるとテストパターンがn * m というやんちゃそうな数になり、めんどそうです。 なので、要素を単純化するため問題1の機能を拡張せずに、まず以下のようなリファクタリングをしました。

  • 朝、昼、夜を表すenumのTime{Morning, Afternoon, Evening}を定義
  • greetから時間帯判定の条件分岐を抽出してgetTimeメソッドに。挨拶文を直接返すのではなく、Time enumを返す
  • Time enumを引数にとってメッセージを返すgetMessageを定義

上記のリファクタリングをした上でgetTime, getMessageにもテストを書きます。 これによって時間帯を判定するメソッドと、時間帯に応じたメッセージを返すメソッドを分離できました。 公開属性をpublicにしようかとも思ったのですが、テスト以外で使われることも無さそうなのでパッケージデフォルトにしてあります

では、次に新規のテストを追加します。getMessageを時間帯だけではなく、ロケールも受け取るように拡張しましょう。

    assertThat(greeter.getMessage(Time.MORNING, Locale.JAPAN), is("おはようございます"));
    assertThat(greeter.getMessage(Time.EVENING, Locale.ENGLISH), is("Good Evening"));

あとは例のごとくテストと実装のサイクルを回します。

    assertThat(greeter.greet(time(6, 0), Locale.JAPAN), is("おはようございます"));
    assertThat(greeter.greet(time(12, 0), Locale.JAPAN), is("こんにちは"));
    assertThat(greeter.greet(time(23, 0), Locale.JAPAN), is("こんばんは"));
    assertThat(greeter.greet(time(6, 0), Locale.ENGLISH), is("Good Morning"));
    assertThat(greeter.greet(time(12, 0), Locale.ENGLISH), is("Good Afternoon"));
    assertThat(greeter.greet(time(23, 0), Locale.ENGLISH), is("Good Evening"));

続いてGreeter#greetも同様の拡張をしてテスト。この時、時間帯判定ロジックは弄っていないので、テストを変える必要は無いです。 getMessageとgetTimeの2つのメソッドに分割することでそれぞれのメソッドの責務が分解されて、テストパターンも圧縮されたのでたぶんいい感じのはず。

個人的には、ひとつのメソッド毎に分岐がひとつの方がテストは書きやすいので、なるべくそうしたい。TDDするとめんどくさいから、そういった構造になりやすいのが良いです。テスト対象コードと、この時点のテストコードはこちら.

テストのリファクタリング

続いてテストのリファクタリング。記事を読んでたらParameterized Test という考え方があるらしいので、試してみることに。 私がよくやってしまう...Test01, ...Test02という残念な名前を付けなくても良いようにテストロジックとデータを分離させる記法です。

    @ToString
    @AllArgsConstructor
    public static class GetTimeParameter {

        int hour;
        int minute;
        Time expected;
    }

    @DataPoints
    public static GetTimeParameter[] moning() {
        GetTimeParameter[] dataset = {
            new GetTimeParameter(5, 0, Time.MORNING),
            new GetTimeParameter(11, 59, Time.MORNING)
        };
        return dataset;
    }

    @DataPoints
    public static GetTimeParameter[] afternoon() {
        GetTimeParameter[] dataset = {
            new GetTimeParameter(12, 0, Time.AFTERNOON),
            new GetTimeParameter(17, 59, Time.AFTERNOON)
        };
        return dataset;
    }

    @DataPoints
    public static GetTimeParameter[] evening() {
        GetTimeParameter[] dataset = {
            new GetTimeParameter(18, 0, Time.EVENING),
            new GetTimeParameter(23, 59, Time.EVENING),
            new GetTimeParameter(4, 59, Time.EVENING)
        };
        return dataset;
    }

    @Theory
    public void getTimeWith(GetTimeParameter parameter) {
        Greeter greeter = new Greeter();
        assertThat(parameter.toString(), greeter.getTime(parameter.hour, parameter.minute), is(parameter.expected));
    }

JUnit4 ではParameterized Test を支援する機能として Parameterized アノテーションやTheories アノテーションがあります。

エラー検出時の可読性はParameterizedが良いですが、それ以外のすべての面でTheoriesが使いやすかったので、こっちを使用。リファクタリング後のテストはこちら.

本気で可読性とエラー表示の見やすさを狙うなら大人しくSpock使えという感じのようなので、今度そっちも検証してみます。

まとめ

今回、直接カレンダー型呼びましたけど、プロダクトで使うなら結合テストのしやすさも考えて、SystemDateとか言う名前の現在時刻を返すクラスを作って、必要に応じて設定ファイルとかで値を制御できるようにします。

で、それを今の実装の引数なしメソッドの実装にする感じです。そうしておくことで、ブラウザ等からのテストでも時間固定ができるので。

UTもその機能で賄うことも不可能ではありませんが、テストコードがめんどくさくなるので、今回のように設計で解決したほうが基本無難な認識です。

それにしても、元記事はいろんな観点で解説があって非常に参考になりました。問題も良かったし。 まだまだTDD(というかここまで来ると詳細設計)に関して未熟なので自分も精進しないと、年の締めくくりに思った次第。

それでは、Happy Hacking!

レガシーコードも年末に向けて大掃除! - jMockitを使おう

さて、今年もあと僅かになりましたが、この1年間で溜まりに溜まったコードの負債を大掃除してみませんか?

レガシーコードだから書くのが大変? プロダクト側を改修したいけどそもそもテストが無いから改修が怖い? ですよねー。 なのでjMockitを使って既存のコードにテストを書く方法を紹介します。

まず、想定するレガシーコードですが検証したいメソッドの内部で現在時刻を取得してるケースを考えます。 普通にクラスやメソッドから日付をインジェクションできるように作るのが正しいコードですが、結構ありがちなのがこんなコード。

    public class MyCalendar {
        public Date nextDay() {
            Calendar calendar = SystemDate.getDate();
            calendar.add(Calendar.DATE, 1);
            return calendar.getTime();
        }
    }

SystemDateは検証環境なんかで結合テストしやすいように、設定ファイルやDBの値を読み込むことが多いでしょうけど、今回はシンプルに現在時刻だけ。

    public class SystemDate {
        public static Calendar getDate() {
            return Calendar.getInstance();
        }
    }

このようなケースでMyCalendar#nextDayにテストを書こうとしても日付が変更出来ないので、月またぎや年またぎ、うるう年のテストが出来ません。検証環境にデプロイして何らかの方法でシステム日付を変更し、手でポチポチと検証しながら画面のスクリーンショットを取る簡単なお仕事が待っていそうですね。

ユニットテストをする気がちっとも無い素敵な感じですが、残念なことにしばしば見かけるタイプのコードです。

jMockitを使うことで、こんな残念な設計に対しても、比較的低コストでUTを書くことが可能です。

    public class MyCalendarTest {

        String $(Date date) {
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            return df.format(date);
        }

        Calendar getCalendar(int y, int m, int d) {
            Calendar cal = Calendar.getInstance();
            cal.set(y, m - 1, d);
            return cal;
        }

        @Test
        public void test01() {
            new Expectations() {
                @Mocked
                SystemDate systemDate;

                {
                    SystemDate.getDate();
                    result = getCalendar(2013, 12, 13);
                    result = getCalendar(2013, 12, 31);
                    result = getCalendar(2013, 12, 13);
                }
            };

            MyCalendar myCalendar = new MyCalendar();
            assertThat($(myCalendar.nextDay()), is("2013-12-14"));
            assertThat($(myCalendar.nextDay()), is("2014-01-01"));
            assertThat($(myCalendar.nextDay()), is("2013-12-14"));
        }
    }

Expectationsブロックの中にMockとして戻り値を差し替えたい内容を記述します。 MyCalendar#nextDay()の中で利用される"SystemDate.getDate()"の戻り値は直下に記載したresultのものに差し替えられます。 今回はstaticメソッドを置き換えましたが、もちろん同様にインスタンスメソッドも置き換え可能です。

また、重要なのはこれがクラス全てではなく部分差し替えとなっていることです。 これにより、対象クラス全体の振る舞いを書き直す手間やリスク無く、モックを作成することが可能です。

ちなみにこのコードで

    MyCalendar myCalendar = new MyCalendar();
    assertThat($(myCalendar.nextDay()), is("2013-12-14"));
    assertThat($(myCalendar.nextDay()), is("2014-01-01"));
    assertThat($(myCalendar.nextDay()), is("2013-12-14"));
    assertThat($(myCalendar.nextDay()), is("2013-12-14"));

とすると

    mockit.internal.UnexpectedInvocation: Unexpected invocation of:
    SystemDate#getDate()

という例外が発生してテストが失敗します。これは、resultの数以上呼び出されるのは期待値と異なるためです。 差し替える値自体は固定で良いが複数回呼びたいケースというのもありますよね? その場合にはExpectaionsの代わりにNonStrictExpectationsを使うことで解決します。

       @Test
        public void test01() {
            new NonStrictExpectations() {
                @Mocked
                SystemDate systemDate;

                {
                    SystemDate.getDate();
                    result = getCalendar(2013, 12, 13);
                    result = getCalendar(2013, 12, 31);
                    result = getCalendar(2013, 12, 13);
                }
            };

            MyCalendar myCalendar = new MyCalendar();
            assertThat($(myCalendar.nextDay()), is("2013-12-14"));
            assertThat($(myCalendar.nextDay()), is("2014-01-01"));
            assertThat($(myCalendar.nextDay()), is("2013-12-14"));

            // 最後のresultとinstanceが同じなので12/14の更に翌日になる
            assertThat($(myCalendar.nextDay()), is("2013-12-15"));
        }

ね、簡単でしょ? これで、今まで初期化が大変過ぎて二の足を踏んでいたコード群にもガンガンテストを書いていくことが出来ます。 それではみなさんも良い年末を! Happy Hacking!

参考:

Keynote風のプレゼンテーションをMarkdownで作ってみた

最近ちょっと英語の練習がてら上のような英語プレゼンを作ろうと思い立ちました。 目的なく写経的なの苦手なので、目的作る方式。

ただ、OpenOfficeなりKeynoteなりPowerPointなりで毎回作るのも面倒だし、JS系のプレゼンツールだとslideshareに上げれないし、良い方法無いかな、と調べてみることに。 Markdown + pandocでの変換が一番自分の好みにマッチしたので、そのやり方を記載します。 以下、内容的には上のプレゼン資料の和訳 + α。そこ、αが多いとか言っちゃダメですよ?

PowerPointKeynoteじゃダメなの?

どちらもめちゃくちゃいいツールですが、ちょっと問題があります。

  1. 同じレイアウトにするのがめんどい
  2. オフィスアプリケーションが必要.
  3. バイナリフォーマット。gitやSVNとの相性が残念

まず1ですがテンプレートを使っても少し面倒です。ブラウザや別なエディタからコピペしようものならそこだけフォントが変わるとかザラですね。 あと、GUI系のエディタだと自分の場合どうしても見た目指向になりがちで、論理構造が変になったりしてる時があるので、あとからスタイル切り替えで苦しみます><

続いて2なんですが、当たり前ですが編集にオフィス系アプリが必要です。立ち上げるのがめんどいのです。エディタが好きなのです。

最後に3。実はコレが一番大きくてまっとうな理由。バージョン管理しづらいんですよね。バイナリフォーマットなので。 修正の差分がわからないです。プラグインとか入れまくればなんとかなるかもですが、ちょっとねえ?

そこでMarkdown + Pandoc

Markdown と Pandocの簡単な説明はこんな感じ。

Markdown

  • シンプルテキストフォーマット。だからgitとの相性もバッチリ!
  • 人間が簡単に読める、そして書ける!
  • HTML風のシンプルな論理文章構造を提供

Pandoc

  • マルチドキュメントトランスレータ(HTML, PDF, docx, markdown, LaTex, reStructuredText...)
  • Markdownからスライドを作成可能
  • しかもs5とかHTML形式のものだけではなく、PDFにできる

大変自分のニーズにあっております。特にMarkdownはgithubとかでも人気ですし、資料が多いのが良い所。 wiki記法みたいなもんですが、謎の方言よりある程度標準化されてるのが良いですね。pandocは他にもwordとかにも変換できるので、マニュアル作りとか社内資料に便利そうです。

なにはともあれ使い方

インストール Pandoc.

こちらの公式から落とせます。linux系の場合は各種パッケージマネージャですかね。 haskellのパッケージ管理ツール入れてやるのも良いかもです。 http://code.google.com/p/pandoc/downloads/

PDF用にTexのインストール

PDFの作成はTex経由で行っているのでインストールが必要です。なんか色々モジュールが居るみたいですが、MacならMacTex入れれば全部揃うようです。http://tug.org/mactex/

Run コマンド

$ pandoc -t beamer test.md -o test.pdf

ね、簡単でしょ? 実行するとこんな感じのスライドが出来ます。

f:id:pascal256:20131028190551p:plain

カスタマイズ

 

テンプレートの適用

ちゃんと、スライドが出来たのは良いですが、ちょっとシンプル過ぎですね。というか気に入らないです(ぉ というわけでKeynoteのグラデーション風の奴に変更しようと思います。 まずは、Texのカスタムスタイルをダウンロード。幸い、同じようなことをしてる人がすでにいらっしゃったので、こちらを使わせてもらいます。 beamerthemeKeynoteLikeGradient.sty.

で、ダウンロードできたら、そのファイルを下記ディレクトリにコピーします。MacTex以外を入れてる方は適宜読み替えで。

$ sudo cp ./beamerthemeKeynoteLikeGradient.sty /usr/local/texlive/2013/texmf-dist/tex/latex/beamer/themes/theme/

次に、インデックス情報の更新です。残念ながらこれだけだと、テンプレートを指定しても見つからないと怒られれます。 おそらく適切な更新方法があるのですが、良くわからなかったので、直接「Tex Live Utility」を起動して、適当なパッケージを再インストールしてインデックスを更新するという荒業にw 誰か、やり方ご存知でしたら教えて下さい。

テンプレートの指定は下記のように "-V theme:"で指定します。これで、晴れてkeynote風のデザインに。

$ pandoc -V theme:KeynoteLikeGradient -t beamer test.md -o test.pdf

コードブロックのカスタマイズ

この状態だとコードブロックが背景色が透明なため少し見づらいです。そのため、ちょっとカスタマイズしたいと思います。この変換の仕組みは裏側はTexなんですが、Texでコードを綺麗に出すためにはlistingというモジュールを使うようです。

$ pandoc --listings -t beamer test.md -o test.pdf

これで、コードブロックがlistingになります。なるんですが、このままだとカスタマイズされて無くて特に見た目変わらないんで、下記のようにヘッダーにフォーマットをしています。 ここにフォント種類やサイズ、背景色やラインもろもろを記載することが出来ます。ヘッダーの書き方はこんな感じ。

\usepackage{listings}
\lstset{%
 %language={sh},
 backgroundcolor={\color[rgb]{0.1, 0.1, 0.1}},%
 basicstyle=\footnotesize,%
 commentstyle=\textit,%
 classoffset=1,%
 keywordstyle=\bfseries,%
 frame=tRBl,framesep=5pt,%
 breaklines=true,
 showstringspaces=false,%
 %numbers=left,stepnumber=1,numberstyle=\footnotesize%
}

利用するには "-H"オプションを使います。

$ pandoc -H header.tex --listings -t beamer test.md -o test.pdf

これでいい感じに出力されました。

まとめ

MarkdownとPandocはシンプルな典型的なプレゼン資料を作るのに向いています。 派手な見た目や画像の多様をした資料を作りたい時はPowerPoitとかKeynoteが確実に良いです。 ただ、おんなじような紋切型で文字多めドキュメントの時は軽量なMarkdown + Pandocはかなり有りです。

今回作成したサンプルはこちら。下記コマンドで冒頭のプレゼン資料が出来上がります。

$ pandoc --listings -H header.tex -V theme:KeynoteLikeGradient -t beamer test.md -o test.pdf

今後の課題としては画面いっぱいのデカ文字とか結構多用するので、その辺の作り方ですね。あと、コマンド毎回打つのも面倒なので、rakeベースのFWというかテンプレートを作ってみました。 それはこちらにおいてあります。良ければ試してみてください。

それでは、Happy Hacking!

参考:

電子書籍ストアのランキングを比較したよ[Book☆Walker, Kindle, Kobo]

ふと思い立って、電子書籍ストアのランキングを比較してみたら、それなりにカラーが違って面白かったのでブログにまとめてみる。

 

まずは、Book☆Walker。最近大合併したKADOKAWAの直轄ストアだけあって、やはり萌系が多い。

新刊や、アニメ化した作品がランキング反映されてる感じなので、わかりやすいですね。

一般書籍も売れてるとのことでしたが、ランキング見る限りはやはり消費者としてはアニメイト的な専門店の位置づけっぽいです。

Book☆Walker

1 ハイスクールD×D16 課外授業のデイウォーカー ¥600
2 週刊アスキー 2013年 10/29号 ¥350
3 新約 とある魔術の禁書目録(8) ¥683
4 週刊ファミ通 2013年10月31日号 ¥350
5 艦これ白書 -艦隊これくしょん オフィシャルブック- ¥1,995
6 東京レイヴンズ10 BEGINS/TEMPLE ¥600
7 艦隊これくしょん -艦これ- 鎮守府生活のすゝめ Vol.1 ¥600
8 おまえをオタクにしてやるから、俺をリア充にしてくれ!8 ¥600
9 落第騎士の英雄譚<キャバルリィ> 【電子特装版】 ¥473
10 ストライク・ザ・ブラッド1 聖者の右腕 ¥599
平均単価   ¥685

 

続いてKobo。文芸作品というか一般作品が多いですね。漫画ランキングとかも見てみたんですが、進撃の巨人が多かったです。同じ漫画というジャンルに絞っても、Book☆Walkerとは明らかに違う傾向ですね。

楽天Kobo

1 ロスジェネの逆襲 ¥1,200
2 キングダム 31 ¥368
3 マリアビートル ¥740
4 成功者に学ぶ時間術 ¥99
5 東京喰種トーキョーグール[JACK] ¥100
6 人生がときめく片づけの魔法 ¥762
7 あなたの仕事に革命を起こす!「つたえることリスト」 ¥100
8 オレたちバブル入行組 ¥690
9 宮本武蔵 完全版 ¥100
10 人類資金IV ¥525
平均単価   ¥468

 

KindleKoboと同じような傾向に見えますが、小説よりもビジネス書が多いですね。

なんとなく意識高い系?の社会人が使ってそうなラインナップですね。

Amazon Kindle

1 下半身で覚えるビジネス英会話-下ネタは世界の共通語!- (ビジネスファミ通) ¥95
2 ソニーをダメにした「普通」という病 ¥200
3 種まきガールズコレクション ¥300
4 宮本武蔵 完全版 ¥350
5 あなたの仕事に革命を起こす!「つたえることリスト」 ¥200
6 人類資金IV (講談社文庫) ¥525
7 仕事ができる人できない人 ―「あの人はできる!」と納得させる20のルール ¥200
8 しゃべれないあなたは悪くない! 英語力が伸びるホントの方法 ¥200
9 20代は勉強に狂いなさい! ¥300
10 30分で一流の仕事をマスターする方法 ¥200
平均単価   ¥257

 

参考までに紙の本を売ってる楽天ブックス楽天市場の利用者とかぶるせいか、主婦向けのラインナップが上位に来てます。

あとは、ジャンル無差別に入ってるので、傾向というほどはなく売れてるものが売れてるって感じですかね。

 

楽天ブックス(参考)

1 【バーゲン本】新干し野菜レシピ ¥480
2 ロスジェネの逆襲 ¥1,575
3 【予約】レシピブログmagazine Vol.1 ¥515
4 【予約】ポケットモンスター X・Y公式ガイドブック 完全ストーリー攻略ガイド ¥1,260
5 【予約】フェフェ2013-2014Winter fafa‘s Universe ¥1,680
6 オレたち花のバブル組 ¥690
7 【入荷予約】乃木坂派 ¥1,995
8 オレたちバブル入行組 ¥690
9 極北ラプソディ ¥735
10 艦これ白書 ¥1,995
平均単価   ¥1,162

 

比較したのはあくまでランキング内容で、売れてる絶対数は不明なので一概には言えませんが

Book☆Walker => 萌系の専門店としてオタク層が利用

Kindle => ビジネス書籍を購入するような層が利用

Kobo => 比較的広い範囲の層が利用

 

という傾向が言えるんじゃないでしょうか。たぶん。

あと、単価が圧倒的に違うのが特色だと思います。

紙を売ってる楽天ブックスは1,162円、ラノベ・コミックが中心のBook☆Walkerが685円、Koboが468円、Kindleにいたっては257円です。

KoboKindleは200円台も目立つのでそのせいでしょう。逆に言えば、萌え系は価格をそれなりに高くしても維持できるコンテンツと消費者の関係が気づけてるという話かもしれないです。

もともと、デジタルデータには慣れてる層でしょうし。Kindleが1強なイメージでしたが、売れてる価格比率を考えると、一人勝ちというほどでもなく、他社にも十分チャンスがある状態なのかなー、とおもいました。

 

それでは、Happy e-Book Life!