Transfer to Hatena blog

Tumblrからはてなブログに移行してみました。 細々とTumblrに不満があったので、とりあえず1ヶ月お試しにはてなブログをという感じです。 もし、はてなブログにも我慢できなくなったらGitHub+S3構成にしようかなと思います。

で、今回はブログ移行の話です。 単純にエクスポート・インポートでいければ良かったのですが、人力と気合とお金で行うことになりました。

  1. Tumblrの記事をエクスポート
  2. はてなブログに記事を移行
  3. 移行元のURLから301 Redirectで移行先のURLにリダイレクト

1. Tumblrの記事をエクスポート

まずは、Tumblrから記事をエクスポートしなければいけないのですが、Tumblr自体にはエクスポートする機能はありません。 そこでTumblr APIを使って記事をエクスポートする仕組みが必要になってきます。

今回はエクスポートする仕組みを探して見つけたsky-tumblr-exportというツールを使っています。

npm install -g sky-tumblr-export

npm経由でインストール後に

sky-tumblr-export -u blog.kinzal.net -d /tmp/tumblr --titles

-uにURLを-dにディレクトリを指定して実行します。

├── posts
│   └── 2015
│       └── 03
│           ├── document-generator-with-angularjs-application.md
│           └── whether-frp-is-type-or-is-it-pipeline.md
└── sky
    └── config.json

そうすると上記のようにposts/年/月/タイトル.mdという形でエクスポートされるので、このmdファイルをベースにはてなブログに移行用のデータを作っていきます。

2. はてなブログに記事を移行

エクスポートしたデータをそのまま、はてなブログにインポート! といければ良かったのですが、はてなブログではMovable Type形式でしかインポートに対応していません。

また、BloggerからTumblrに移行したときの記事がhtmlでmdファイルにベタ書きされていたり、コードブロックがバッククォートではなくスペース4つでエクスポートされていたりで、はてなでサポートされているマークダウン形式と微妙に噛み合っていなかったりします。 そこで、人力で気合を入れて、記事一件毎に整形をして、記事を投稿していきます。

主な移行対象は下記になります。

  • 記事タイトル
  • 記事本文
  • 投稿日時
  • カスタムURL
  • タグ

今回の移行作業にかかった時間の大部分はここで、だいたい70ちょっとの記事数でアニメ2クール分ぐらいの時間がかかりました。 自動化しても良かったのですが、変換規則を抜き出して、はてなブログAtomPub API使って投稿することを考えると、時間的にとんとんになるだろうと見込んで人力でやりました。(どうせ1回しか使わないですし)

ツラかった。

3. 移行元のURLから301 Redirectで移行先のURLにリダイレクト

ここまで来たら後は公開するだけ。と言いたいところですが、実はTumblrとはてなブログではURLの形式が違います。

Tumblr

http://独自ドメイン/posts/カスタムURL

はてなブログ

http://独自ドメイン/entry/カスタムURL

このまま公開してしまうと、既存記事へのリンクが全て全滅してしまう上に、コピペした記事としてSEOがまずいことになってしまうため、postsにアクセスした場合に301 Redirectでentryにリダイレクトする必要があります。

Tumblrにもはてなブログにもそういった機能はないので、どうしたものやらと思っていたら

CloudFlareにその機能がありました。

ただし、はてなブログの独自ドメイン機能ではCNAMEのレコードチェックがあるため、はてなブログではCloudFlareを使用することができません。 そこで、少し面倒臭いですが、

  1. はてなブログ用に新規ドメインを取得
  2. はてなブログで新規ドメインを独自ドメインに設定
  3. Tumblrで使用していた旧ドメインにPageRuleを追加
    • http://blog.kinzal.net/posts/* -> http://www.rpms.me/entry/$1
    • http://blog.kinzal.net -> http://www.rpms.me
  4. はてなブログを非公開から公開に変更
  5. 旧ドメインでCloudFlareを有効化

という手順を踏んで、無停止で移行できるようにしました。 新規ドメインで良さそうなのが残っていたので助かりました。

おわりに

という訳で、無事移行完了しました。

デザイン的にも前と同じシングルカラムレイアウトで、ほぼ似たようなデザインになっています。 あとはもう少し運用してみてBounce RateとTime on Pageがどう変わるかみて、いろいろと変えて行こうかなと思います。

個人的にはてなブログに書き換えて良かったなと思うのは、コードブロックで言語指定できるところが良いですね。 PHPのコードブロックが<?phpを入れないと有効にならないのはあれですが、Tumblrでは一切指定できなかったのでエンジニア的には結構嬉しいです。

Whether FRP is Type? or is it Pipeline?

FRPとは何なのか?時間軸に対する値の変化をする型なのか、パイプライン処理を表現しやすくする処理なのか。 自分が何がわかっていないのかわからないので、とりあえずポエムで吐き出します。

FRPに関して調べてるといろいろな解説がされています。

  • Q. (関数型)リアクティブプログラミングとは何ですか? http://postd.cc/what-is-functional-reactive-programming/

    FRPを「“時間とともに変化する”値を表すデータ型」とシンプルに表現しています。

  • なぜリアクティブプログラミングは重要か。 http://d.hatena.ne.jp/pokarim/20101226

    リアクティブプログラミングは、「時間とともに変化する値」=「振る舞い」同士の関係性を記述することでプログラミングを行うパラダイムです。

  • 2015年に備えて知っておきたいリアクティブアーキテクチャの潮流http://qiita.com/hirokidaichi/items/9c1d862099c2e12f5b0f

    リアクティブプログラミングを言い換えるのであれば、Observerパターンを意識させず関係性のみを記述することともいえるでしょう。

どの解説でも言われているFRPの特徴が

  1. 時間とともに変化する値を表す型
  2. 関係性の記述

の2つになります。

時間とともに変化する値を表す型

  • データ型 http://ja.wikipedia.org/wiki/%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B

    データ型(データがた、data type)とは、コンピュータにおけるデータの扱いに関する形式のことである。データタイプとも。データ型は、プログラミングなどにおいて変数そのものや、その中に代入されるオブジェクトや値が対象となる。

wikipediaを見ると型は上記のように説明されています。

では、それを踏まえて実際にFRPのダイアグラムとコードを見てみます。

requestStream:  --a-----b--c------------|->
responseStream: -----A--------B-----C---|->

(lowercase is a request, uppercase is its response)

var requestStream = Rx.Observable.returnValue('https://api.github.com/users');

var responseStream = requestStream
  .flatMap(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

responseStream.subscribe(function(response) {
  // render `response` to the DOM however you wish
});

変数、もしくはその中に代入されるものと考えるとrequestStreamresponseStreamがその対象に思えます。 つまりはStreamのことを指して「時間とともに変化する値を表す型」と言っている訳ですね。(そうだと思いたい)

ダイアグラムを見れば「時間とともに変化する値を表す型」という表現に納得です。

Promise

しかし、このコードを見ているとPromiseを思い出します。

var requestPromise = Promise.resolve(‘https://api.github.com/users');

var responsePromise = requestPromise
  .map(function(requestUrl) {
    return fetch(requestUrl).then(function(response) { return response.json(); });
  });

responsePromise.map(function(response) {
  // render `response` to the DOM however you wish
});

単一のデータに対して記述しているので、似ているだけなのかもしれません。 requestに複数の値を設定してみます。

var requestStream = Rx.Observable.from([‘https://api.github.com/users', ‘https://api.github.com/users/k-kinzal/repos’]);

var requestPromise= Promise.then([‘https://api.github.com/users', 'https://api.github.com/users/k-kinzal/repos']);

どちらも同じように最初のrequestを作る箇所で複数の値を設定することができます。(Promiseにはbluebirdを使っています) しかし、実際にコードを何度か動かすと挙動が違うことがわかります。

responseStream.subscribe(function(response) {
  console.log(response); // -> repos, users
});

responsePromise.map(function(response) {
  console.log(response); // -> users, repos
});

Streamはレスポンスが戻ったものからsubscribeを実行し、Promiseは両方のレスポンスが戻ってから順序を維持してmapを実行します。(たぶんあってるはず) つまり、Streamは単一の値に対して後続の処理が流れ、Promiseは集合に対して後続の処理が流れます。

FRPもPromiseも似たような表現になりますが、この違いが使い分ける場合の指針の一つになると思います。

副作用

FRPの特徴の一つとして作成したStreamに値を流すことができます。

public func notificationsStreamAtInterval(interval: NSTimeInterval, since: NSDate) -> RACSubject {
    let subject = RACSubject()

    Timer(interval: interval).start {
        self.client.getNotifications(since) { (notifications, error) -> Void in
            for notification in notifications as Notifications! {
                subject.sendNext(notification)
            }
        }
    }

    return subject
}

事前にStreamを作成し、そこに値をpushすることでStreamに値を流し続けることができます。 しかし、ここでFRPは「時間とともに変化する値を表す型」であるということを考えると、Streamの状態が変化します。

Stream:  --a-----b--c------------->

このStreamに対してdをpushすると

Stream:  --a-----b--c-----------d-->

と、Streamの状態が変化する訳です。 これは関数型という意味では正直どうなんだろうと思ってしまいます。(関数型に関して勘違いしている可能性がある) とはいえ、この変化を許容しないと正直なところ魅力が激減します。 例えば良く例に出てくるユーザーアクションに対してバインドして(クリックとかマウスムーブとか)、それに対して関係性を記述するなんてことが出来なくなります。 そう考えると、ここは許容せざるを得ないのですが、気持ち悪さが残ります。

なんだろ。Streamに副作用を押し込めるから良いという話なんでしょうか。

型?処理?

もやっとしたので、pushしたときの実装を除いてみることにします。

Dispatcher.prototype.push = function(event) {
  if (event.isEnd()) {
    this.ended = true;
  }
  return UpdateBarrier.inTransaction(event, this, this.pushIt, [event]);
};
inTransaction = function(event, context, f, args) {
  var after, result;
  if (rootEvent) {
    return f.apply(context, args);
  } else {
    rootEvent = event;
    try {
      result = f.apply(context, args);
      flush();
    } finally {
      rootEvent = void 0;
      while (aftersIndex < afters.length) {
        after = afters[aftersIndex];
        aftersIndex++;
        after();
      }
      aftersIndex = 0;
      afters = [];
    }
    return result;
  }
};

pushしたタイミングでイベントを発火しているだけですね。(たぶん) ということは、別にダイアグラムのように内部に値を保持して状態が変化している訳ではなさそうです。 これでちょっとすっきりしました。

と、思ったところでFRPは「時間とともに変化する値を表す型」ということを思い出すと、これは型なのか・・・?という疑問がわいてきます。 よくよく考えてみると特に型制約がある訳でもなく、pushしたら後続の処理が発火されるだけの処理で、これをプログラムの型のIntとかと同列に考えるのは何か違う気がしてきます。(実装都合の問題で思想的なところはまた別?)

つまるところ、これってパイプライン処理ですよね。

FRPってなんなんだろう・・・。

その他

  • Eventでしか見てないから理解できない? Behaviorなら変わる?
  • それPromiseで良いじゃんな例
    • HTTP Requestとか
    • パイプライン的処理は全般的にそう思う
  • 循環させると複雑さが跳ね上がる
    • Observerの悲劇再演
  • 複雑に分岐するStreamは死ぬ
  • 全てをStreamにできる
    • 正気の沙汰と思えない
      • 狂気の沙汰ほどおもしろい
        • つまりStreamはおもしろい
  • 関係性という言葉に疑問
    • 反応的に処理を書けるだけで別に関係性は記述してない(既存言語の限界?)

Document generator with AngularJS Application

みなさんはAngularJSアプリケーションを作るさいに、ドキュメントの生成をしていますか?

AngularJSではngdocという形式のドックコメントでドキュメントを生成できるDgeniを使っています。では、AngularJSで作ったアプリケーションはどうするかと言うといくつかの選択肢があります。

JavaScript document generator

まず、選択肢の一つとしてJavaScript用のドキュメント生成器を使うことができます。 この場合のメリットは従来通りのドックコメントを書けば良いため学習コストを低く保つことができます。 しかし、AngularJS独自の区分(provider、directive…)でクラスを区分けしようとすると、空のネームスペースを作ったり、コードに沿わないドックコメントを書く必要が出てきたりします。 そこに対して解決策があるならAngularJSアプリケーションで使うという選択肢を取ることができます。

/**
 * @namespace module
 */

/**
 * @namespace module.services
 */

/**
 * require service factory 
 *
 * @name Require
 * @function
 * @memberOf module.services
 * @param {ng.$http} $http {@link https://docs.angularjs.org/api/ng/service/$http}
 * @param {Content} content Content loader
 * @param {String} [PROXY_API_URL] Proxy URL
 * @return {Function} require function
 */
function Require($http, content, PROXY_API_URL) {
  /**
   * load script
   *
   * @function
   * @memberOf module.services
   * @param {String} source script file URL
   * @param {Function} callback callback that is called when load the script
   */
  return function require(source, callback) {
    // …
  };
}

module.service('require', ['$http', 'content', 'PROXY_API_URL', Require]);

Instant document generator

変わり種として左右にドックコメントとコードを表示する簡易的なドキュメント生成器を扱う選択肢もあります。 ドックコメントをそのまま表示するだけなので、どのような方式のドックコメントにも対応できることがメリットです。

AngularJS API Doc clone generator

※注 名前は似てますが全て別物です

ngdoc形式でドックコメントを書きたい場合はAngularJS API Docクローンのドキュメント生成器が選択肢に入ります。 すぐにngdoc形式のドックコメントからドキュメントを生成することができるのがメリットですが、あくまでもクローンなのでツールによってngdocのサポート範囲が異なるところに注意が必要です。 (providerが指定できないなどAngularJSで使われているドックコメントがそのまま使えないことがある)

/**
 * @ngdoc directive
 * @name ev.directive:evWheel
 *
 * @description
 * The `evWheel` directive allows you to specify custom behavior on mousewheel event.
 *
 * @element ANY
 * @param {expression} evWheel {@link http://docs.angularjs.org/guide/expression Expression} to evaluate upon
 * mousewheel. (Event object is available as `$event`)
 *
 * @example
 * &lt;div ev-wheel="sameCallback()"&gt;...&lt;/div&gt;
 */
function evWheel($parse) {
  return function(scope, element, attr) {}

余談ですが、ngdocではcontrollerという区分はサポートされていません。 そのため、AngularJSアプリケーションで使う場合はcontrollerをサポートしている拡張されたジェネレーターを使う必要があります。(廃止予定のcontrollerは使わないのが正しいですが)

ngdoc supported generator

完全にngdoc形式をサポートしているのはDgeniのみになります。 そのためAngularJSと同様のドックコメントを書けるというのがメリットですが、HTMLなどを生成するために必要なテンプレートを自分で作成する手間がかかります。 また、カスタマイズできる領域が他のドキュメント生成器よりも広く、ドックコメントの構文から生成するドキュメントまで自由に変更できますが、その分覚えることが多く、導入までの敷居が高くなっています。

/**
 * @ngdoc service
 * @name require
 * @module module
 * @kind function
 * @requires $http
 * @requires $content
 * @requires PROXY_API_URL
 * @description
 * 外部ファイルのコードを読み込む。
 */
function Require($http, content, PROXY_API_URL) {
  return function require(source, callback) {
    // …
  };
}

※テンプレートにdgeni-markdownを使用しています

What to choose

どれを使うべきかは、ユースケースによって変わってきます。 例えば開発者がコードを読むときの助けにするためにドキュメントを生成する、公開用のAPI Docを作成するために生成する、とりあえずドックコメントの検証をする・・・などで求めるドキュメント生成器が変わります。

これは個人的な見解になりますが、ある程度どのユースケースでも対応できるものをあげると、ngdocを使わないならJSDocを。ngdocを使うならDgeniを採用するのをお勧めします。 JSDocは定番だけあって情報量が多く、テンプレートのカスタマイズまで可能なため、開発者向けのドキュメントから、公開用のAPI Docまで幅広く扱うことができます。 Dgeniは導入するまでが大変ですが、一度導入さえしてしまえば完全なngdoc形式が扱えるため、AngularJSと同じようにドックコメントを書けない・・・という事故をなくせるため安心してコメントを書くことができます。

また、JS界隈の流れは速いので他にもAngularJSアプリケーションで使えるドキュメント生成器はあると思います。 こんなものを使っているよ!というのがあればぜひ教えてください。

蛇足。

Angular2だとどうなるんでしょうね。 DgeniにTypeScript packageが追加される気はしてますが、バッサリ捨てにかかりそうな気もしてます。 AngularJSアプリケーションを作る選択肢としてbabelという方向性も捨て難いので、ES6やTypeScriptに対応したドキュメント生成器なんかも漁ってみないとダメですね。

Startup!! Yeoman and AngularJS : Qiita Advend Calendar 2014 12/04

この投稿はAngularJS Advent Calendar 2014の4日目の記事です。 今年も昨年に引き続き、yeomanを使用したAngularJSの始め方です。

気がつけばAngularJS用のyeomanのジェネレーターがとんでもない数になってきました。 (なんとBackbone.jsの4倍!) 昨年までは定番的なジェネレーターを使っておけば良かったですが、今では自分の望む構成のジェネレーターを探した方が早かったりします。 そこで今年は趣向を変えて、いくつかの構成のジェネレーターとその始め方を紹介していきます。

準備

yeomanを始めるための事前準備として、node.jsnpm、各種ツールをインストールします。

node.jsをインストールする

まずはyeomanを動かすためにnode.jsをインストールします。 既にnode.jsがインストールされている場合は飛ばしてもらって構いません。

node.jsは公式サイトにて各OS用のバイナリが配布されています。

こちらからOSに合わせてバイナリをダウンロードしてインストールします。 バージョンは後述のnで指定するので、ダウンロードページのものをそのままインストールしてもらって大丈夫です。

npmをインストールする

node.jsをインストールしたら、次にパッケージ管理のnpmをインストールします。 既にnpmがインストールされている場合は飛ばしてもらって構いません。

curl -L https://npmjs.org/install.sh | sh

nをインストールする

次にnode.js、npmの複数バージョンを切り替えることの出来るnをインストールします。 他にも同じことのできるツールがありますが、個人的には一番事故の少ないnが気にっています。

npm install -g n

npmを使ってグローバルにnをインストールします。 インストールが完了したらnでインストール可能なバージョンを調べます。

n ls

と実行するとインストール可能なバージョンを表示することができます。 ここでは2014/12現在の最新安定板の0.10.33をインストールします。

n 0.10.33

もし、違うバージョンに変えたくなったらn [version番号]とすれば何時でも切り替えることができます。

各種ツールをインストールする

yeomanと各種定番ツールをインストールします。

この3つのツールをインストールしておけば大抵のジェネレーターに対応できます。

npm install -g yo grunt-cli gulp bower

他にもジェネレーターに必要なツールがあれば、随時インストールしてください。

プロジェクトを生成する

今回は定番的な構成の汎用性の高い3つのジェネレーターでプロジェクトを生成します。 何か特定のツールや、フレームワークを使いたいとき以外は、ここで紹介するジェネレーターを使うがオススメです。

yeoman/generator-angular

昨年も紹介させてもらったジェネレーターです。 取り敢えずAngularJSを初めてみたい・・・という方は、このジェネレーターで始めて、自分好みのカスタマイズしていくことをオススメします。

インストール

npm install -g generator-angular
yo angular

いくつか質問されますが、ここで回答した内容はあとで変更することができます。

タスク

  • grunt
    • テストとビルドを実行します
  • grunt build
    • ビルドを実行します
  • grunt test
    • テストを実行します
    • e2eテストはタスク定義されていないため必要なら設定する必要があります
  • grunt serve
    • 開発用のWebサーバーを起動します
  • grunt serve:dist
    • ビルド結果を表示するWebサーバーを起動します

プロジェクト構成

.
├── gruntfile.js         - grunt設定ファイル
├── app                  - アプリケーションディレクトリ
│   ├── 404.html
│   ├── bower_components - bowerコンポーネントのインストールディレクトリ
│   ├── favicon.ico
│   ├── images           - 画像ディレクトリ
│   ├── index.html
│   ├── robots.txt
│   ├── scripts          - Javascriptディレクトリ
│   ├── styles           - CSSディレクトリ
│   └── views            - ルーティングで指定する分割したHTMLのディレクトリ
├── bower.json           - Bower設定ファイル
├── karma-e2e.conf.js    - E2E用のkarma設定ファイル
├── karma.conf.js        - karama設定ファイル
├── node_modules
├── package.json         - npm設定ファイル
└── test                 - テストディレクトリ
    ├── runner.html
    └── spec             - karamaで実行するspectディレクトリ

cgross/generator-cg-angular

Angular Best Practice Guidelines for Project Structureに則ったプロジェクトを生成するジェネレーターです。 generator-angularではシンプルなSPA向きのジェネレーターでしたが、generator-cg-angularはよりチームで開発する規模の開発に向いたジェネレーターになっています。

インストール

npm install -g generator-cg-angular
yo cg-angular

いくつか質問されますが、ここで回答した内容はあとで変更することができます。

タスク

  • grunt build
    • ビルドを実行します
  • grunt test
    • テストを実行します
  • grunt serve
    • 開発用のWebサーバーを起動します

また、generator-cg-angularではgulpによるビルドもサポートされています。

npm install gulp gulp-concat gulp-uglify gulp-imagemin gulp-less gulp-cheerio gulp-ng-html2js gulp-ngmin gulp-htmlmin gulp-cssmin streamqueue rimraf gulp-rename gulp-jshint gulp-jasmine jshint-stylish gulp-dom-src

gulpで使用する依存モジュールはデフォルトではインストールされません。 そのため、上記のコマンドでインストールするか、package.jsonに依存モジュールを追加してください。

  • gulp build
    • ビルドを実行します

プロジェクト構成

.
├── gruntfile.js     - grunt設定ファイル
├── app.js           - 共通のJavascriptファイル
├── app.less         - 共通のLessファイル
├── bower.json       - Bower設定ファイル
├── bower_components - Bowerコンポーネントのインストールディレクトリ
├── gulpfile.js      - Gulp設定ファイル
├── index.html
├── node_modules
└── package.json     - npm設定ファイル

機能を追加する場合はAngular Best Practice Guidelines for Project Structureに沿ってディレクトリを作成します。

admin                           - Admin機能のディレクトリ
├── admin-directive             - Admin機能で使うdirectiveディレクティブのディレクトリ
│   ├── admin-directive-spec.js - 
│   └── admin-directive.js
├── admin-partial               - Admin機能で使うルーティングで指定する分割したHTMLとそこで使用するJavascript、Lessのディレクトリ
│   ├── admin-partial-spec.js
│   ├── admin-partial.html
│   ├── admin-partial.js
│   └── admin-partial.less
├── admin-spec.js
├── admin.js                    - Admin機能共通のJavascriptファイル
└── admin.less                  - Admin機能共通のLessファイル

Swiip/generator-gulp-angular

gulpをメインのタスクランナーにしているジェネレーターです。 他のジェネレーターのほとんどがgruntをタスクランナーにしているため、gulpでAngularJSアプリケーションを開発したい場合はこのジェネレーターを使用してください。

また、今回紹介するジェネレーターの中でもっとも機能が充実しているジェネレーターでもあります。 生成時に変更できる内容の多さや、protractorを使用したe2eテストのタスクなど最近のAngularJSアプリケーションの開発に必要なものが一揃いしています。 他のジェネレーターに慣れている方も、最近の流行を知るために一度は使ってみてください。

インストール

npm install -g generator-gulp-angular
yo gulp-angular

いくつか質問されますが、ここで回答した内容はあとで変更することができます。

タスク

  • gulp
    • ビルドを実行します
  • gulp build
    • ビルドを実行します
  • gulp serve
    • 開発用のWebサーバーを起動します
  • gulp serve:dist
    • ビルド結果を表示するWebサーバーを起動します
  • gulp wiredep
    • bowerでインストールしたコンポーネントをHTMLにscriptタグを埋め込みます
  • gulp test
    • テストを実行します
  • gulp protractor
    • e2eテストを実行します
  • gulp protractor:dist
    • ビルド結果に対してe2eテストを実行します

プロジェクト構成

.
├── bower.json             - Bower設定ファイル
├── bower_components       - Bowerコンポーネントのインストールディレクトリ
├── gulp                   - Gulpのタスクディレクトリ
├── gulpfile.js            - Gulp設定ファイル
├── node_modules
├── package.json           - npm設定ファイル
├── src                    - アプリケーションディレクトリ
│   ├── 404.html
│   ├── app                - アプリケーションで使用するHTML、Javascript、Sassのディレクトリ 
│   │   ├── index.js       - 共通のJavascriptファイル
│   │   ├── index.scss     - 共通のSassファイル
│   │   ├── main 
│   │   │   ├── main.controller.js
│   │   │   └── main.html
│   │   └── vendor.scss     - bowerでインストールしたCSS、Sassを取り込むSassファイル
│   ├── assets              - 画像やフォントなどのリソースのディレクトリ 
│   │   └── images          - 画像ディレクトリ
│   ├── components          - 共通的なコンポーネントのディレクトリ
│   │   └── navbar
│   │       ├── navbar.controller.js
│   │       └── navbar.html
│   ├── favicon.ico
│   └── index.html
└── test                   - テストディレクトリ
    ├── e2e                - protractorで実行するe2eテストディレクトリ
    ├── karma.conf.js      - karama設定ファイル
    ├── protractor.conf.js - protractor設定ファイル
    └── unit               - karamaで実行するspecディレクトリ

機能を追加する場合はappの下にディレクトリを作成していきます。

admin
├── admin.controller.js
└── admin.html

おまけ

ちなみにですが、最近の自分はyeomanでプロジェクトを生成することが減ってきました。 元々はyeoam/generator-angularで作ったプロジェクトをカスタマイズしてコピーして使い回しています。 新規に作るプロジェクトの仕様に合わせて、構成やタスクを最適化するので使い慣れたプロジェクトをカスタマイズした方が早いためです。

こんな風にカスタマイズしているのか、参考までに簡単に最近の自分の構成を紹介します。

タスク

  • grunt
    • ビルドを実行します
  • grunt publish
    • ビルド結果をデプロイします
  • grunt build
    • ビルドを実行します
  • grunt test
    • テストを実行します
  • grunt coverage
    • テストを実行してカバレッジを出力します
  • grunt doc
    • ドキュメントを生成します
  • grunt server
    • 開発用のWebサーバーを起動します
    • node http、http-proxyを使って本番環境と同等のバックエンドを立ち上げています
  • grunt debug
    • watchを実行しながらテストを行います

プロジェクト構成

.
├── gruntfile.js        - grunt設定ファイル
├── app                 - アプリケーションディレクトリ
│   ├── components      - Bowerコンポーネントのインストールディレクトリ
│   ├── favicon.ico
│   ├── images          - 画像ディレクトリ
│   ├── index.html
│   ├── scripts         - Javascriptディレクトリ
│   │   ├── controllers - Controllerディレクトリ
│   │   ├── directives  - Directiveディレクトリ
│   │   ├── filters     - Filterディレクトリ
│   │   ├── app.js      - 共通のJavascriptファイル
│   │   ├── modules     - 自作のモジュールディレクトリ
│   │   ├── prefix      - JSファイルを結合したさいに先頭に結合するファイル
│   │   ├── services    - Serviceディレクトリ
│   │   └── suffix      - JSファイルを結合したさいに末尾に結合するファイル
│   └── styles          - Sassディレクトリ
├── bower.json          - Bower設定ファイル
├── node_modules
├── package.json        - npm設定ファイル
├── tasks               - gruntの各タスクの設定ファイル
└── test                - テストディレクトリ
    └── spec            - karamaで実行するspecディレクトリ

このプロジェクト構成は小規模用の構成です。

いま一番気に入っているAngularJSのプロジェクト構成

ある程度規模があるときは、こちらの記事で紹介されているFolders-by-Featureを採用するのがベターです。

また、サービスの配置はレイヤーによって切り分けた方が良さそうと最近感じています。 同じサービスでもビジネスロジックが中心になっているサービスと、APIやライブラリをラップしているサービスが出てきます。 これを混在して配置するのは良くないため、切り分けを行いつつプロジェクトの規模を大きくしていこうと思っています。


今回は汎用的に使えるジェネレーターだけを紹介しましたが、他にもいろいろなジェネレーターがあります。 大抵のフレームワークやaltJSに対応したジェネレーターがありますので、自分好みの構成を検索してみてください。

Monitoring nginx By New Relic Agent SDK: Qiita Advend Calendar 2014 12/02

この投稿はnginx Advent Calendar 2014の2日目の記事です。


皆さんnginxの監視にNewRelicを使用していますか? NewRelicではnginx.incが提供しているnginx web server Pluginが提供されています。 nginx Plus限定ですがupstreamやcacheの監視も行えるため、取り敢えずこのプラグインを入れておけば十分な監視を行えます。

しかし、せっかくNewRelicを使っているのでAPMとして監視をしたい! ということでNewRelic Agent SDKを使用してnginxをAPMに追加をしたいと思います。

What is NewRelic Agent SDK

NewRelic Agent SDKはNewRelic.incが提供しているAPMに登録するためのC言語で書かれたSDKです。 APM用に標準で提供されているAgentではJava、Ruby、.Net、PHP、Node.js、Pythonの言語でしか使うことができませんが、NewRelic Agent SDKを使うと他の言語や、アプリケーションを登録することができます。

Include NewRelic Agent SDK to nginx

すでにnginxのモジュールとして作成されている方がいらっしゃるので、そちらを使ってnginxに組み込みます。

1. Install NewRelic Agent SDK

まずはNewRelic Agent SDKをインストールして、パスの通ったディレクトリに配置します。

curl -L http://download.newrelic.com/agent_sdk/nr_agent_sdk-v0.16.0.0-beta.x86_64.tar.gz
tar xvz nr_agent_sdk-v0.16.0.0-beta.x86_64.tar.gz
sudo cp nr_agent_sdk-v0.16.0.0-beta.x86_64/include/*h /usr/local/include/
sudo cp nr_agent_sdk-v0.16.0.0-beta.x86_64/lib/*so /usr/local/lib/

2. Make nginx

準備が出来たらnginxとnginx NewRelic ModuleをダウンロードしてMakeします。

git clone https://github.com/yars/nginx_newrelic_module.git
curl -L http://nginx.org/download/nginx-1.6.2.tar.gz
tar xzv nginx-1.6.2.tar.gz
cd nginx-1.6.2
./configure \
  --add-module=../nginx_newrelic_module
make && make install

上記コードはnginx_newrelic_moduleの部分だけを抜粋しています。 他にもPCREなど必要なモジュールをconfigureに設定してください。

3. Configure nginx

nginxのmakeに成功したら、nginx.confに設定を追加します。

http {
    ...
    newrelic on;
    newrelic_license_key my-newrelic-key;
    newrelic_app_name my-app-name;

上記のようにnewrelicディレクティブでon/offを切り替え、newrelic_license_keyディレクティブにAPIトークンを、newrelic_app_nameディレクティブでAPMに表示するアプリケーション名を設定します。 また、APMで表示されるトランザクション名は基本的にURLになりますが、これを設定で変更することもできます。

location /some_location {
    newrelic_transaction_name some_other_name;
    ...
}

ここまで出来たらnginxを起動して、ページを表示すればNewRelicのAPMに新しいアプリケーションが登録することができます。


皆さん上手く動きましたでしょうか。 APMに登録できて何が嬉しいって、APMで使えるAvailability monitoringやAlertを使えるようになることです。

特にHerokuで静的サイトやリバースプロキシーを運用するときに、Availability monitoringが使えないとインスタンスの停止が発生してしまうため、APMは必須の機能になります。

あとはupstreamをNewRelicのexternal serviceとして登録できれば完璧なのですが、上手いフックタイミングが見当たらなくて改造するのは諦めました。 このあたり、nginxモジュールについて詳しい方がいたら教えてください。