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

理系学生日記

おまえはいつまで学生気分なのか

忍者TOOLS

Docker ComposeでPostgresバックエンドのgitbucket/redmineを構築する

Redmine をマジメに使ったことがなかったのですが、使う機会が多くなってきているので、ちょっと慣れとかないと厳しいなぁと思っておりました。 とりあえず本を買ったは良いのですが、手元で確認したいというのと、同じく良く使われるようになってきている Gitbucket も手元で使いたい、 それに、せっかくだったら全部 Postgresql をバックエンドにしておきたいという思いもありました。

というわけで、これらの環境を手元にサクっと構築できるように、Docker Compose で立ち上げられるようにしておくか、というのが本エントリの趣旨になります。

これにより、以下のコマンドで、redmine と gitbucket が動き出します。

$ docker-compose run -d

ベースとなるコンテナ

ベースとしたのは以下のコンテナです。

コンテナ URL
redmine:3.3.3 redmine
postgres:9.6.2 postgres
takezoe/gitbucket:4 gitbucket

Redmine

Redmine のコンテナについては、環境変数でバックエンドの DB を切り替えられるようになっています。このため、docker-compose.yml に何の工夫もなく記述するだけで良くて楽でした。

docker-compose.yml 上のサービス定義は以下のようになります。

  redmine:
    image: redmine:3.3.3
    ports:
      - 3000:3000
    environment:
      REDMINE_DB_POSTGRES: db
      REDMINE_DB_USERNAME: postgres
      REDMINE_DB_PASSWORD: password
    depends_on:
      - db
    restart: always

Gitbucket

Gitbucket については、以下の 2 つの課題がありました。

  1. Gitbucket はデータベース設定は設定ファイル database.conf で持つようになっているため、バックエンドを Postgres に設定した database.conf を使ってコンテナをビルドしておく必要があります。つまり、Dockerfile を作っておく必要がある。
  2. Gitbucket は起動時にデータベーススキーマを作るので、Postgres のコンテナ上で Postgres が立ち上がるまで Gitbucket の起動を待つ必要がある

前者は Dockerfile で ADD を使えば問題ないです。

後者については、コンテナの依存関係を示す depends_on だけではダメで、Postgresql の LISTEN ポートが有効になるまで待つ仕組みを入れる必要があります。 これを簡単に実現するのが wait-for-it.sh という Bash スクリプトです。 このスクリプトは、一定時間ほど指定された host:port の open を試み、その状態でブロックしてくれるというものです。

実装を見ると、/dev/tcp へのリダイレクトでこれを実現しておりまして、これで TCP open してくれるんや…知らんかった…。

というわけで、この wait-for-it.sh を組み込んだ Dockerfile はこちら。

# -*- mode: Dockerfile -*-
FROM takezoe/gitbucket

MAINTAINER kiririmode

ADD database.conf /gitbucket/database.conf
ADD wait-for-it/wait-for-it.sh /gitbucket/wait-for-it.sh

この Dockerfile をベースにして、docker-compose.yml のサービス定義は以下のようになります。

  gitbucket:
    build:
      context: .
      dockerfile: Dockerfile.gitbucket
    ports:
      - 8080:8080
    command: ["/gitbucket/wait-for-it.sh", "db:5432", "--", "java", "-jar", "/opt/gitbucket.war"]
    depends_on:
      - db
    restart: always

Postgresql

Postgres も特に特筆すべきことはしていないのですが、Gitbucket の前提が「起動時にデータベースがあること」なので、そのデータベースを作るように設定します。

Postgres のコンテナは、/docker-entrypoint-initdb.d というディレクトリに放り込んだスクリプトを起動時に実行してくれるので、以下のようなスクリプトを init-gitbucket-db.sh として保存しておいて、Dockerfile の ADD を使って送り込めば良い。

#!/bin/bash

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<EOF
    CREATE USER gitbucket PASSWORD 'password';
    CREATE DATABASE gitbucket;
    GRANT ALL PRIVILEGES ON DATABASE gitbucket TO gitbucket;
EOF

docker-compose.yml のサービス定義は以下のとおりです。

  db:
    build:
      context: .
      dockerfile: Dockerfile.postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    restart: always

つくったもの

特定ディレクトリ配下の拡張子の一覧を取得するワンライナー

特定ディレクトリ配下で特定の拡張子を持つファイルを探すのは find コマンドで一発ですが、一方で、特定ディレクトリ配下の拡張子をすべて抽出する、というユースケースがあります。 ぼくは、.gitattributes に書く拡張子って何にしよう、ってときに、その必要が生じました。

結論から言うと、以下で可能です。

$ find . -type d -name '.git' -prune -o -type f -exec basename {} \; | grep -o '\.[^.]*$' | sort | uniq
.MF
.aaa
.class
.classpath
.component
.config
.container
(略)

find コマンドについては、.git ディレクトリ配下のファイルは無視するという前提でファイルパスを抽出し、basename コマンドにかけてファイル名を抽出しています。

-prune のオプションについては、こちらが分かりやすいかと。

ファイル名を取得できた後、grep-o オプションを使います。

grep は、別に合致した行を抽出できるだけでなくて、「合致した箇所」を -o オプションで抽出することができます。ここでは、 「最後の . の後に続く、. を含まない文字列」を拡張子として定義しました。

あとは、おなじみの sort | uniq で、重複した拡張子を削除するってかんじです。

Excelの結合セルの高さを調整する伝家の宝刀

Excel 方眼紙を使いこなすぼくたちにとって、セルの結合というのはエクスカリバーに近しい最終兵器です。 そんなエクスカリバーたる結合セルに入れる文章というのもまた、明治の文豪がその人生を賭して綴り捻り出す人生そのものであって、セル内改行に伴って文字が切れてしまうようなことは絶対にあってはなりません。

しかしですね、Excel というソフトウェアは、結合セル内の文章に合わせてセルの高さを調整する機能を有しておりません。このため、Excel 方眼紙を作り出すユーザは、逐一セルの高さを手動で揃えなければならない。これは由々しき問題です。

いやね、セルを結合していなければ、自動で高さ調整をしてくれるんです。

ところが、結合セルに対しては調整をしてくれない。Microsoft には、石に刺さったエクスカリバーを引き抜くことができなかったとばかりです。

しかしぼくは、ついにエクスカリバーを引き抜くことができるアーサー王を発見した。それが、AutoFitRowEx という Excel アドインです。

これをインストールすることでコンテキストメニューに「行の高さを自動調整」というメニューが追加されます。 高さ調整したいセルを選択した状態でこのメニューを使用することで、Excel マクロが起動され、行の高さが良い感じに自動調整されます。

「印刷したら文字切れしてるぞ」みたいな指摘をしたりされたりして修正に時間を要するのは時間をドブに捨てているようなものですから、積極的に使っていきたいと思いました。 Microsoft に何とかしてほしいものですが、Excel は表計算ソフトですから、みたいな言葉の暴力で撲殺される恐れがあるので、そういうことは言わない。

.gitattributesによる改行コードの変換設定

Git での改行コードの取り扱いについてきちんと調べたことがなくて、プロジェクトにおいては「みんなー! ただしく .gitconfig 設定してねー」という立場を取っておりました。 しかししかし、改行コード設定については、もはや個人の設定に正しさを求めるのではなく、リポジトリ単位に行う方がベストプラクティスのようです。

基礎知識

改行コードの取り扱いを面倒にしているのは、プラットフォーム毎に改行を意味するコードが異なることです。

プラットフォーム 改行コード
Windows CR LF
Linux/OS X LF

Linux で作成され改行が LF で表現されたファイルがあるとします。これを、Windows で Checkout し、Windows 側で勝手に改行を CRLF で表現するようにしてしまうと、全行に差分が出てきてしまって、レビュー等が著しく大変になります。 このような状況を防ぐため、Git では、リポジトリ上のファイルは (基本的に) LF で表現するという考え方を採っています。

関連する設定

関連する設定については、以下の 2 つがあります。

設定 概要
core.eol 作業ディレクトリ上のファイルに使用する改行コード。デフォルトは native
core.autocrlf Git で改行コードを自動変換するかどうかを設定するフラグ。デフォルトは false

core.eol のデフォルトである native は、Windows 上の改行コードを CRLF に、Unix/Linux/OS X では LF と解釈します。この変数を個別プロジェクトで設定するということはまずないと思います。 一方で、core.autocrlf については、デフォルトの false だと git は改行コードを as-is で扱いますので、リポジトリ上は、LF のファイルと CRLF のファイルが混在する状況が生まれがちです。 このため、プロジェクトの開発者に対して、Git がテキストファイルと判断した ファイルに対し、自動的に LF に変換する true を設定させることが多いのではないでしょうか。

リポジトリ単位での設定

こういう設定を個人の .gitconfig の正しさに求めると、誰か設定漏れをしていてリポジトリを破壊(!) することになります。 このため、個人任せではなく、リポジトリを clone した時点で開発者に強制できることが望ましい。それを行えるのが、.gitattributes です。

.gitattributes は、.gitignore と同様に指定したファイル名のパターンに合致するファイルに対し、特定の属性を与えるファイルです。 このうち、改行コードに影響を与えるのは以下のような属性。

属性 概要
text 対象ファイルを「テキストファイル」として扱うものと指定し、改行コードの正規化を行うようにする
eol text と一緒に指定することで、改行コードの正規化を行うようにする

text には、単に宣言するだけでなくて、text=auto のような指定も可能ですし、eol には eol=crlf というような設定も可能です。 また、text に対して binary という指定もでき、この属性が指定されたファイルに対しては改行コードの指定は行われません。binary-text -diff という指定のマクロとなっていて、改行コード変換と、diff が無効になります。

.gitattributes に合致するパターンが複数あった場合、後勝ちという仕様になっています。 このため、一般的な指定を先頭に、ファイル固有の指定を後にすることになります。

以下は、man gitattributes に出てくるサンプルですが、最初に全ファイルに対しての text=auto を指定することで、「テキストと判断したファイルについては、改行コード変換(LFへの変換) する」という設定にしています。 その後、以下のように、拡張子毎に詳細な設定を行っています。

  1. .txt ファイルは改行コード変換を行う (LF に変換)
  2. .vcproj ファイルは、改行コード変換を行う。ただし、CRLF に変換する
  3. .sh ファイルは、改行コード変換を行う。ただし、LF に変換する
  4. .jpg ファイルには、改行コード変換を行わない
# 
*               text=auto

*.txt           text
*.vcproj        text eol=crlf
*.sh            text eol=lf
*.jpg           -text

こういった指定を .gitattributes に指定してリポジトリにコミットすることで、今後当該のリポジトリを clone する開発者に対しては改行変換の設定が強制されることになり、より安全な開発が行えます。

オブジェクト指向の世界においては、小さなオブジェクトが、いわゆるメッセージングパッシングを通して一つの処理を行う世界が構築されます。しかし、このメッセージングパッシングがネットワークを介して多数行われるとなると、その蓄積はいつしかパフォーマンスに影響を与える規模のものになります。 だからといって巨大オブジェクトを構築すると拡張性が落ちる。このジレンマを軽減するパターンが、Remote Facade です。

Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))

Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))

Remote facade は何のドメインロジックも持たず、単に「粗い」粒度のメソッドコールを受けて、それを個々のオブジェクトへの細かなメソッドコールに変換する wikipedia:Facade パターン です。

上記の例では、Remote Facade である AddressFacade はクライアントに対して getAddressData を提供し、このメソッドコールを getStreet()getCity()getZip() という一連の細かなメソッドコールに変換します。クライアントは、ネットワーク越しに細かなメソッドコールを行うことなしに、一連の住所データを取得できるということになります。

RemoteFacade は、クライアントとの接点になることから、様々な他の機能を持つこともあります。

  • アクセスコントロール
  • トランザクション制御

などなど。

ただ、RemoteFacade は、単にネットワーク間やプロセス間通信の負荷を低減させるのが目的であることがミソで、そのために RemoteFacade の実装は非常に薄いものになります。実際の処理はドメイン層に移譲されます。

iOS 10.3.1から非MFI認証のイヤホンジャックアダプタが使えなくなった

iPhone7 に付属していたイヤホンジャックの変換アダプタをずっと使用してきていたんですが、この間紛失してしまいました。 それでも 3rd パーティのアダプタを使い続けてきたんですが、iOS 10.3.1 にアップデートしたら、「このアクセサリは使用できません」みたいなメッセージが出てくるようになって、事実上、アダプタを使えなくなりました。

その後も、Amazon で MFI 認証を取っていないアダプタをいろいろ買ってみたんだけど、やっぱり使えない。 ムカつくのが、1 分くらいは使えて「ヤッター使えたー!!!!」みたいに糠喜びした後で、上記のようなメッセージが出てきて認識すらしなくなるところ。

関連事象は以下のとおりです。

かなしすぎる。やはり MFI 認証を取ったアクセサリじゃないとダメなのか。MFI 認証を取った変換アダプタは、だいたい 4,000 円以上するイメージあってつらい。 ちょっと調べてみると、Apple の公式のアダプタが 1,000 円以下だったので、それ買った。買うしかなかった。Apple なしに生きていけないプラットフォームになってる。

モジュール間の依存関係図をGraphvizで図示する

ちょっとライブラリ間の依存関係を可視化することになりました。

おなじみ Excel 方眼紙に書くというのも考えたんですが、Microsoft Office のオブジェクトで描画するのって、依存関係が複雑になるほど大変になってきます。

ほらー、きっとモジュール 1 つを矩形とかで表現することになるじゃないですかー。その矩形間を矢印のオブジェクトで繋げていくことになってー、その矢印が多くなってくるとマウスクリックすら難しくなるしー、矩形上で矢印をくっつけるポイントも多くないので矢印が混雑してくるしー、なにより Excel って差分が残らないから何が変わったのか分からないしーーーー。

依存関係というのは基本的には有向グラフになるわけですが、有向グラフを書くんだったらそれ用のソフトウェアがあるわけなので、それを使えば良いのではと思っております。

例えば、すごくシンプルな例ですが、以下のような有向グラフが出力できます。

nf:id:kiririmode:20170415193103p:plain

これを作り出すのは以下のような設定ファイル。これを dot -Tpng projects.dot -o projects.png でコマンド実行して、png ファイルを出力しています。

// プロジェクトの依存関係
digraph projects {

  // グラフ全体の定義
  graph [
    charset = "UTF-8";
  ]
  // 矢印の定義
  node [
    style="solid,filled"
  ]

  // プロジェクトの定義
  common, batch, daemon, web, api1, api2;
  testsupport [label = "test-support"];

  // 依存関係の定義
  batch  -> common;
  daemon -> common;
  web    -> common;
  api1   -> common;
  api2   -> common;
  common -> testsupport;
}

上の有向グラフは、dot というコマンドで生成していました。このコマンドは、主に階層構造やフローを表現するような有向グラフを作成します。 一方で、このような「形」が気に入らなかった場合は、他の形でグラフを生成することもできます。

例えば、dot の代わりに、"ばね" モデルを用いたエネルギーが最小化される形式でのグラフを neato コマンドで作ることができます。 同じ依存関係であっても、ずいぶんと形が変わるものですね。

f:id:kiririmode:20170415193147p:plain

他にもモジュールの依存関係だったら、以下にギャラリーの作品があったりしますので、ご参考になれば。

PoEAA: Application Controller

Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))

Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))

Application Controller には 2 つの役割があります。

  1. どのドメインロジックを実行するのかを決める
  2. どの View を使ってレスポンスを作成するのかを決める

この目的を果たすため、Application Controller は、ドメインロジックの集合と View の集合を持つ必要があります。

プレゼンテーション層との分離は Application Controller の設計上の要点ですが、著者はこの点について、

my preference is for the Application Controller to have no links to the UI machinery.

と述べていて、その理由は testability と拡張性です。 Testability については、プレゼンテーション層との分離に従い単体でテストが実施できるということを意味していますし、拡張性についても、プレゼンテーションと分離するが故にプレゼンテーションが差し変わったとしても対応できるということになります。

楽天Edyのオートチャージ額変更にはオンライン/オフラインの両方で設定変更が必要になる

今年から楽天 Edy を使うようになりました。 ぼくにとっては初の電子マネーだったわけですが、財布から小銭を取り出すことなしに買い物ができ、かつ、お釣りとして小銭が返ってこないというのは大変良いですね。毎日、会社最寄りの FamilyMart で Edy で買い物をするようになりました。

で、この Edy にはオートチャージの機能がありまして、残金が設定した金額以下になると、一定額を自動チャージしてくれるというものになります。

使い始めるときに設定したもので、チキンなぼくは 1,000 円を切ると 1,000 円をオートチャージするようにしていました。 しかしですね、このような設定ですと、1,000 円を切った状態で 1,000 円以上の買い物ができないわけですね。これは不便だ。 というわけですので、オートチャージの額の設定を変更しようと思ったら、マジで違和感ある方法になっていました。

オートチャージの設定変更は、

  1. Web でオートチャージ設定を変更する。これにより、カードに設定反映待ちの状態になる
  2. FamiryMart の Fami ポート、あるいは、楽天 Edy リーダー等でカードに対する変更をおこなう

という 2 ステップが必要になります。

Web 側、というか、Edy のシステム側だけで、オートチャージ設定情報を保持しているのだと思っていたんですが、カード側にも何らかの情報が記憶されているんですかね。

PoEAA: Two Step View

最終的に HTML を出力する場合であっても、一度論理的な View に変換した後で、それを実際の View に変換するという 2 ステップを踏むパターンを、文字通り Two Step View と呼びます。 JVM の中間コードだったり、LLVM の IR みたいなもの。主なメリットは、個々のページで共通的な箇所を論理的な View で抽象化でき、全体のページのレイアウト等を変える等しやすい点。

Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))

Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))

最初に読んだときはあまりイメージが分かりませんでしたが、なるほど、

  1. Action でドメイン情報を含んだ XML を出力し
  2. その XML を XSLT で論理 Screen (論理的な View) の XML に変換し、
  3. その XML をさらに XSLT で HTML に変換する

という例や、

  1. 論理 Screen を Template View を使って ` として構成して、
  2. それをさらに HTML に変換する

という例が提示されていて、なるほど〜〜〜と思いました。抽象化というのはそういうものですが、現実を抽象化できない抽象化はもはや抽象化ではないのであって、うまく抽象化できないと死ぬパターンですねこれ。 また、2 ステップによる View の構築は、エンジニアがデザインに巻き込まれることを意味しており、このあたりがデメリットであるというのも本文の中で語られています。