The King's Museum

ソフトウェアエンジニアのブログ。

Dependencies - The Twelve-Factor App

12 Factor App シリーズ。2個目は依存関係の管理について。

Dependencies: The Twelve-Factor App

パッケージマネージャ

12 Factor app は決してライブラリに暗黙的に依存しません。

プログラミング言語にはライブラリを管理するためのパッケージマネージャが存在します。

システムワイド (site-package) にもインストールできますし、app を含む特定のディレクトリだけにインストールすることも可能です (vendoring or bundling) が、決して site-package にインストールするようなことがあってはいけません。

ツールへの依存

OS 側のツールにも暗黙的に依存してはいけません。

たとえば暗黙的な ImageMagick や curl の存在には依存してはいけません。 すべてのシステムに存在することや適切なバージョンが存在することを保証できないからです。

もし、ツールが必要であれば明示的に依存関係を書かなければなりません。

依存関係宣言と依存関係分離

すべての依存関係は依存関係宣言を使って明示的に宣言されます。 また、app の実行時には依存関係分離ツールを使って依存関係がシステムに漏れ出さないようにしなければなりません。

これは開発環境にもプロダクション環境にも適用されます。

具体例

Ruby では依存関係宣言のために Gemfile を利用し、依存関係分離のために bundle exec を利用します。

Python では依存関係宣言のために Pip を利用し、依存関係分離のために Virtualenv を利用します。

たとえ C 言語であっても依存関係宣言に Autoconf を利用し、依存関係分離のために静的リンクを利用できます。

たとえツールが何であろうと、依存関係宣言と依存関係分離はは常に一緒に行う必要があります。

macOS High Sierra で "macOS could not be installed on your computer" が出たときの対処法

macOS High Sierra の更新に失敗してしまい、次のようなメッセージがでて OS が起動できなくなった。

macOS could not be installed on your computer

再起動しても同じエラーで起動できない。 これはまずい。。。

起動する

まず「起動できない」という状況を打破したい。 次の記事を参考にして通常起動できるようにした。

http://sublimelife.hatenablog.com/entry/2017/12/15/103447

ただ、この方法は単に更新をスキップしているだけなので、このままだと最新の High Sierra にいつまでも更新できない。。。

きちんと更新する

最新の状態にならないのは困るなぁと思い少し調べると、

Apple のサイトから手動で dmg を落としてきて更新するとうまくいくよ

という報告を発見。

今回は High Sierra 10.13.4 への更新に失敗していたので、次のサイトから 10.13.4 の Combo Update dmg をダウンロードして更新したらうまくいきました。

https://support.apple.com/kb/DL1959?locale=ja_JP

きっと、この方法ではうまくいかないケースもあるのだろうけど、同じような事態に遭遇している人たちの一部にでも役に立てば…。

Codebase - The Twelve-Factor App

12 Factor App シリーズ。最初はコードの管理について。

Codebase: The Twelve-Factor App

バージョン管理システム

12 Factor App は常に Version Control System で変更をトラックしています。 このリビジョンのデータベースは Code Repository と呼ばれ、単に Repo と呼ばれることもあります。

Codebase は一つの Repo に相当し、Codebase と app は1対1の関係を持ちます。

もし、複数の Codebase を持つのであればそれはもはや一つの app ではありません。 それはなんらかの分散システムとなります。

ただし、分散システムを構成する一つ一つのコンポーネントは app として扱うことができ、それら一つ一つは 12 Factor App に適合することができます。

複数の app が同じソースコードを共有していることは 12 Factor App 違反です。 その場合、共通のコードをライブラリとして切り出し、依存関係を管理するようにするべきです。

複数の deploy

一つの Codebase が一つの app である一方、一つの Codebase に対して複数の deploy は可能です。 この場合、deploy は app が動作する一つのインスタンスだと考えます。

deploy には production や staging 環境などが考えられます。また、ローカル環境での開発も deploy の一つだと考えることができます。

Codebase は app と1対1てあるため、すべての deploy において Codebase は同一である必要があります。しかし、それらで違うリビジョンがデプロイされることはありえるでしょう。

Introduction and Background: The Twelve-Factor App

サーバーアプリケーションの開発において The Twelve-Factor App という考え方があるのをつい最近知った(いまさら感がすごい)。

勉強がてら記事にしておこうと思う。

まずは Twelve-Factor App の Introduction と Background から・・・

The Twelve-Factor App

12factor.net

INTRODUCTION

The Twelve-Factor app は「サービスとしてのソフトウェア(software-as-a-service)」を構築するための方法論です。

サービスとしてのソフトウェアは次のような特徴を持ちます。

  • プロジェクトに新たに参加する開発者のコストを最小化するため、セットアップ自動化には宣言的なフォーマットを使う
  • OS への依存関係を明確化し、実行環境に関して最大限のポータビリティを提供する
  • サーバーやシステム管理の必要性を事前に省くために、モダンなクラウドプラットフォームへのデプロイを最適化する
  • 最大限の機敏性をもつ CI のために、開発環境とプロダクション環境の差違を最小化する
  • ツール、アーキテクチャ、開発プラクティスに大きな変更を加えることなしにスケールできる

どのような言語で書かれていても、どのようなバックエンドサービスとの組み合わせでも問題ありません。

BACKGROUND

このドキュメントの起草者は直接的、または間接的にさまざまなアプリケーションの開発やオペレーションを目にしてきました。

そこで目にした問題を提起し議論するために共通の語彙を与え、問題を解決するための概念的な解決策を提示するることがこのドキュメントの目的です。

感想

Introduction と Background はそんなに大したこと書いてないと思った。

じゃあ、どうやってこれらを実現していくか、っていうのが大事なわけで、それを説明したこのあとの12個の Practice がこのドキュメントの面白いところだと思う。

ここ数ヶ月 Docker 関連でサーバーサイドをいじっているが、自分なりに「こういう方法論で作るのがベストなんじゃないかな」と思っていることが、そのまま出てきたりしたので、もっと早くに出会っていれば、、、と思った。

Coursera: Improving Deep Neural Networks を修了したよ

Coursera: Deep Learning SpecializationCourse 2: Improving Deep Neural Networks を修了しました。

f:id:hjm333:20180323230238p:plain

学んだ内容は次の通り。

  • Train/Dev/Test set
  • Bias/Variance
  • L2 Regularization
  • Dropout
  • Normalizing
  • Mini-Batch Gradient Descendant
  • Momentum, RMSprop, Adam Optimization
  • Tuning hyper parameter
  • Batch Normalization
  • Soft-max
  • Tensorflow

Course1 は Deep Neural Network のイメージを掴むための基礎講義だったけど、Course 2 は学習時に使われている最適化アルゴリズムの紹介がメインだった。

DNN はパラメータ Wb で定義されるわけだけど、学習でそれらを決めるためには、

  • ネットワークの深さ
  • 各層のユニット数
  • 学習率
  • 減衰率
  • バッチサイズ
  • 学習回数
  • 最適化アルゴリズムとそのパラメータ

という、パラメータ Wb を決定するハイパーパラメータを決定する必要がある。

結局、これらのハイパーパラメータを「どうやって、どの値にするか」が勝敗を決める、という感じですね。

Course1 で DNN の全体像をきちんと掴んでいたおかげで、それぞれのアルゴリズムやテクニックがどこに効いてくるかがとても分かりやすかった。 やはり Andrew 先生の講義で間違いなかった…(比較対象はないけど)。

Coursera: Neural Networks and Deep Learning を修了したよ

Coursera: Deep Learning SpecializationCourse 1: Neural Networks and Deep Learning を修了しました。

f:id:hjm333:20180226214601p:plain

内容は次の通り。

  1. Logistic Regression as Neural Network
  2. Vectorization
  3. Shallow Neural Network
  4. Deep Neural Network

これらを学習する過程で、

  • Activation function
  • Forward propagation & Back propagation
  • Gradient descend
  • Compute Graph
  • numpy

という Deep Learning の基礎的な知識も得ることができる。

これらの知識を得られたことも価値だけど、時折 Andrew 先生が話してくれる

最近は、 XX という手法が流行っていて結果を出しているよ

とか

YY という手法もあるけどあまり使われてないよ

というアドバイスがすごく価値があるのではないかと思わせる講義だった。

Week 4 の課題のバグ

Week 4 の課題はバグがあって一度で 100% が取れず少し苦労した。

プログラミングの課題は Jupyter Notebook になっていて、

  1. テキストを読む
  2. コードの穴埋め
  3. その場でインタラクティブに実行して結果をチェック(この時点では採点されない)
  4. 最終的にコードを提出し採点

という流れになっている。

ただ、Week 4 の "Building your Deep Neural Network: Step by Step" の "6.3 - L-Model Backward" で提示されているコードは、穴埋め前の状態でバグがある。 加えて、そこに提示されている「期待される実行結果」自体が間違っている。

そのため、

  • 提示されているコードを元にして穴埋めをする
  • その場で実行すると、実行結果が「期待される実行結果」と一致するので、コードがあっているように見える
  • しかし、本当はコードが間違っているので最終的に提出するとスコアが 0 になる

という分かりづらい自体に陥る。

ここで間違った部分のコードを貼って解説しようかと思ったけど、規約上微妙かな、と思ったので役に立ちそうな Discussion Forum のリンクだけ貼っておきます。

本当に困っていたら直接連絡をください。

【Effective Java 3rd】Item 1: Consider static factory methods instead of constructors

オブジェクトを生成するために public コンストラクタの他に static ファクトリーメソッドを用意するとよいでしょう。

static ファクトリーメソッドとは、インスタンスを返す単なる static メソッドのことです。 例えば、Java の Boolean では次のような static ファクトリーメソッドが提供されています。

public static Boolean valueOf (boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}

なお、GoF のデザインパターンで議論される「ファクトリーメソッド」とは異なるので注意が必要です。

Advantages

通常のコンストラクタと比較して static ファクトリーメソッドには次のようなメリットがあります。

名前がつけられる

コンストラクタの名前は必ずクラス名と一致しなければなりません。

一方、static ファクトリーメソッドではより適切な名前をつけることができます。

インスタンスの生成をコントロールできる

コンストラクタは必ずインスタンスを生成してしまいます。

一方、static ファクトリーメソッドでは必ずしもインスタンスを生成する必要はありません。 これは GoF のデザインパターンの Flyweight パターンに相当します。 さきほどの Boolean.valueOf はまさにこのパターンです。

インスタンスの生成をコントロールできることで、シングルトン(項目3)、インスタンス化不可能(項目4)、不変クラス(項目15)などのパターンに応用することもできます。

サブタイプのインスタンスを生成できる

コンストラクタは必ずそのクラスのインスタンスを生成します。

一方、static ファクトリーメソッドでは必ずしもそのクラスのインスタンスを返す必要がありません。 例えば、実装のためだけの非公開クラスを公開することなく、そのインスタンスを生成することができます。

Java8 以前ではインタフェースが static メソッドを持てませんでした。 そのため、Type というインタフェースを継承した実装クラスを生成するため、インスタンス化不可能な Types という Utility クラスを定義して static ファクトリーメソッドを用意していました。 しかし、Java8 からはインタフェースがインタフェースが static メソッドを持てるようになったのでこのテクニックの必要性はうすれています。

引数の値によって生成するインスタンスを変更できる

コンストラクタは生成する引数によってインスタンスを変更できません。

一方、static ファクトリーメソッドを使うと入力値によって生成するインスタンスを変更可能です。

EnumSet がよい例です。 EnumSet のファクトリーメソッドは enum 型の値の個数によって、生成するインスタンスを変更しています。 具体的には enum 要素が 64 以下なら RegularEnumSet のインスタンスを返しますが、それより大きければ JumboEnumSet のインスタンスを返します。

クラス作成時には存在しないインスタンスを生成できる

当たり前の話ですが、あるクラスのコンストラクタを作成するとき、生成するインスタンスのクラスは必ず定義されています。

一方、static ファクトリーメソッドでは作成時点では、返すクラスの定義は存在していなくてもかまいません。 この柔軟なファクトリーメソッドは Service Provider Framework の基本となります。

Disadvantages

static ファクトリーメソッドにはいくつかのデメリットもあります。

public または protected のコンストラクタを持たないクラスをサブクラスにできない

この制限は不便に感じるかもしれませんが、実際には問題ありません。 なぜなら、そのような場合は継承ではなく、コンポジョンの利用を促すからです。

他の static メソッドと区別がつきづらい

static ファクトリーメソッドのための API ドキュメントが存在しません。そのため、ドキュメント上で通常の static メソッドと static ファクトリーメソッドの区別がつきません。

これに対しては一般的な命名規則に従うことで弱点を克服しています。以下に命名規則の例を示します。

  • from()
    • 一つのパラメータをもらって対応するインスタンスを返します。
  • of()
    • 複数のパラメータをもらってそれらを取り扱うインスタンスを返します。
  • valueOf()
    • from() や of() の代替です。
  • instance() or getInstance()
    • パラメータで指定されたインスタンスを返します。
    • 入力したパラメータと同じ値を持つとは限りません。
  • create() or newInstance()
    • getInstance に似ていますが、必ず新しいインスタンスを生成します。
  • getType()
    • getInstance に似ていますが、ファクトリーメソッドが対象のクラスと異なるクラスにある場合に利用されます。
    • Type は返されるオブジェクトの型の名前です。
  • newType()
    • newInstance に似ていますが、ファクトリーメソッドが対象のクラスと異なるクラスにある場合に利用されます。
    • Type は返されるオブジェクトの型の名前です。
  • type()
    • getType や newType の代替です。

Effective Java

Effective Java

(c) The King's Museum