パパエンジニアのポエム

奥さんと娘ちゃんへの愛が止まらない

建築士がプログラマーのごとく働かねばならぬとしたら

If architects had to work like programmers...

上記サイトの翻訳です。
ソフトウェア開発という行為が、いかに複雑で困難なことかを説明する時のために残しておく。
プログラマが泣ける内容になっております。

建築士様、

家を一つ設計施行してくださいな。まだ何が必要か具体的なことはわからないので、そこはよきに計らう方向で。

寝室の数は、2から45までの間。寝室の追加と削除は簡単に出来るようにしといて下さいね。青写真が出来次第あたしが何が気に入ったかを最終判断します。それぞれの青写真について明細書を付けるのをお忘れなく。後で気に入ったのをピックアップできるように。

完成後の家の費用は、今住んでいる家よりも安上がりでないと駄目なことを留意してくださいな。それでいて、今の家の欠陥(あたしが歩くたびにキッチンの床がきしむとか、壁の断熱がなってないとか)が全て修正されている必要があるのは言うまでありません。設計の際には、保守費用も最低になるよう工夫するのもお忘れなく。当然ですがそれにはアルミやビニールやサイディングのような高品質の部材が必要になるでしょう(アルミが使えない場合は、その理由を委細もらさず説明すること)。施行においては最新のデザインと素材を惜しまないように。モデルルームにひけをとらないように。ただし、キッチンには1952年ギブソン製の冷蔵庫を含め、今あるものが全て無理なく収まるようにすること。正しく家を設計するにあたって、当然ですが私の子供たち、義理の家族達に詳細にインタビューするように。そうそう、家に関しては一家言お持ちの姑をお忘れなく。一年に一度も来るんですからね。

選択肢は入念に吟味すること。ただし、最終決定権は当然あたしにあります。ささいなことであたしを患わせないこと。建築士様の仕事は、全体計画をたてて大枠を提示すること。例えばカーペットの色とかは委細。ところで私のダンナは青が好き。

資材調達に関しては心配ご無用。建築士様の第一優先は詳細設計と仕様固めですから。ただし、あたしが計画を承認ししだい、48時間以内に棟上げ完了すること。

あたしの家を設計する際には、いつかはあたしが家を別の誰かに売りに出すことを忘れないこと。将来の買主が誰になっても魅力的なものにすること。計画を仕上げる前に、近所の潜在顧客の了承もとりつけておくこと。

あたしのご近所の新築物件の視察は済ませておいた方がいいわ。あたしも多いに感銘を受けたし。あたしの家に必要なものもたくさんあったし。たとえば25mプールとか。建築士様なら、費用負担を一円も増やさずに出来るわよね。

必要な青写真はすべて取り揃えておくこと。本番デザインは必要ないわ。施工業者の入札に使うだけだから。ただし、設計変更による追加費用は、すべて建築士様の責任だということは念を押しておきます。

建築士様にとってこれほど魅力的なプロジェクトもそうはないでしょう!最新の技術と部材を使って、自由に設計できるんですから。滅多にない機会ですよ。アイディアと完成済みの設計をもって今すぐご連絡下さいませ。

追伸: ダンナはあたしの指示をあまり気に入ってないみたい。建築士様なら、丸く納められるわよね。あたしもいろいろ試してみたのだけどどうもうまく行かなくって。丸く納められないなら、他の建築士を探すことにするわ。

追々伸: もしかして、あたしが必要なのは家じゃなくてトレーラーハウスかも。そう思うならその旨すぐにご連絡を。

ドメイン駆動設計をざっくり把握したい②

前回の続き。
DDDの戦術的設計をざっくりまとめる。

戦術的設計

レイヤ化アーキテクチャ

アーキテクチャパターンの一つで、下位層から順番にインフラストラクチャ層、ドメイン層、アプリケーション層、UI層に分離される。
原則として下位層にしか依存してはいけない。

依存関係逆転の原則(DIP)

「上位のモジュールは下位のモジュールに依存してはならない。どちらのモジュールも抽象に依存すべきである。
抽象は、実装の詳細に依存すべきではない。実装の詳細が、抽象に依存すべきである。」

  • DDDにおけるDIP

インフラストラクチャ層のコンポーネントは、ドメイン層が定義するインターフェースに依存するべきである。
具体的には、インターフェースIRepositoryドメイン層に実装し、具象暮らすRepositoryをインフラストラクチャ層に実装する。

エンティティ

一意なモノを表現する概念のことで、実装時は一意に特定するポイントとなる属性や振る舞いだけに注目することが重要。
ビジネスロジックを内包した一般的なクラス群の呼称、getterとsetterしかないドメインモデル貧血症というアンチパターンに注意する。

ドメインサービス

とあるドメインにおいてのサービスは、そのドメインに特化したタスクをこなす、ステートレスな操作のこと。

  • 注意
    • アプリケーションサービスと混同しないこと
    • エンティティの振る舞いをドメインサービス化してしまうとドメインモデル貧血症に陥る

集約

集約とは、エンティティのまとまりを表し、整合性を保ちながらデータを更新する単位のこと。
責務は、エンティティ群の生成/読み込み/変更/保存等のライフサイクル管理。

ファクトリ

ファクトリとは、集約を生成する責務をもつ概念のこと。
特定の集約にて、別のエンティティ(集約も含む)を生成することが多い。

リポジトリ

リポジトリとは、エンティティから構成される集約の保存と取得の責務をもつ概念のこと。
依存関係逆転の原則の説明にあるように、リポジトリのインターフェースは、集約と同じドメイン層のパッケージに配置。
リポジトリの具象クラスはインフラストラクチャ層に配置する。

アプリケーション

ここでいうアプリケーションとは、
ドメインモデル、ユーザーインターフェース、アプリケーションサービス、インフラストラクチャのコンポーネント全体を指す。

ユーザーインターフェース

JavaのSpringや.NETのASP.NETなどのWAFがこの層に属する。
ドメインモデルのユーザーインターフェースへのレンダリングは、DTOを用いることが多い(当然他の方法もある)。
アプリケーションサービスが集約インスタンスを取得し、それをDTOレンダリングする。
ドメインモデルに依存するかどうかはケースバイケース。

アプリケーションサービス

アプリケーションサービスとは、ドメインモデルの調整を行う責務をもつコンポーネント
ユーザーインターフェースドメインモデルの橋渡し役となるので、それぞれの層の依存関係を調整するのが大切。

インフラストラクチャ

インフラストラクチャは、アプリケーション全体の技術的機能を提供する責務をもつ。
DIPをい、アプリケーション内のあらゆるクライアントは抽象に依存するようにし疎結合化を図る。

ドメイン駆動設計をざっくり把握したい①

DDDをざっくりまとめておく必要があったので、メモがてらまとめる。

前提

「ソフトウェア開発とは、恐ろしく複雑である」という事実を真正面から向き合うための方法論。
プログラマが泣いた建築士がプログラマーのごとく働かねばならぬとしたらという秀逸な例え。

デジタルサービスを事業としている会社にとって「ソフトウェアは事業そのもの」といえる。
経営がソフトウェアを理解するのも大事だし、開発者が経営を理解するのも大事。
それがそのまま対象ドメインでの競争力になる。

DDDとは

DDD(ドメイン駆動設計)とは、Domain Driven Design の略でソフトウェア開発手法です。
GoFのようなデザインパターンではなく、ソフトウェア設計の概念です。

DDDの登場人物

  • 開発者
    • ソフトウェアを開発する人
  • ドメインエキスパート
    • ソフトウェアが対象とする業務領域(ドメイン)について業務知識を有する人

DDD導入メリット(事業)

開発費用がコストから事業投資へ置き換わる。

  • 開発者とドメインエキスパートが共通言語(ユビキタス言語)を用いて視点を揃えることにより、ワンチームであたかも顧客が開発するようにソフトウェアを開発できる
  • ドメインエキスパートですら理解が浅い業務ドメインの知識を、チームで共有し開発者視点も含め検討することにより、顧客の理想を超えるソフトウェアを開発できる
  • 対象ドメインの複雑さをドメインモデルというDDDの概念を用いて緩和する事ができる
  • DDDは、設計がコードであり、且つコードが設計であると表現されるように、開発時の翻訳コストが減り、実装時の課題を設計段階で気づくことが出来る
  • DDDは、アジャイル開発が前提なので、イテレーティブでインクリメンタルな開発を行うことが出来る

DDD導入メリット(人物)

各人の望むことが手に入る可能性が高まる。

  • 開発者
    • 適切で正しいソフトウェア開発手法を用いて、スキルアップしながら楽しく開発したい
  • シニア開発者
    • 開発者とドメインエキスパートの距離を縮め、事業価値を向上させたい
  • ドメインエキスパート
    • 開発者とコミュニケーションをスムーズに行い、顧客に喜ばれるソフトウェアを開発したい
  • マネージャー
    • 開発者が業務知識を得て、ドメインエキスパートが開発力を理解し、協力して結果を出してほしい

DDD導入メリット(具体例)

  • 従来
  • ドメインエキスパートが話す言葉と開発者の言葉が違い、実装内容にズレが生じる
  • 1つの大きなシステムのため、実装(プログラム)が肥大化する
  • 処理主体のトランザクションスクリプトでは、変更を入れる際のリスクと工数が肥大化する
  • 1つの大きなシステムのため、DB(永続化層)が肥大化する

  • DDD

  • ドメインエキスパートと開発者で共通言語(ユビキタス言語)で会話したとおりに実装できる
  • ドメインとコンテキストを適切に分割することで、業務知識ごとに機能を分離することが出来る
  • 業務知識を抽象化したドメインモデルを用い開発を行うため、見通しがよく変化に強くなる
  • ドメインとコンテキストを適切に分割することで、永続化ストレージ(RDB/NoSQL等)を適切に分離することが出来る

DDD用語集

  • ドメイン
    • ソフトウェアが対象とする業務領域のこと
  • ドメインモデル
    • 業務知識に則り、ドメインの名前や振る舞いが、適切に反映されている概念的なモデル
    • ドメインモデルをコードに落とし込むとソフトウェアモデル(OOPの場合エンティティモデル)となる
  • 境界づけられたコンテキスト
  • ユビキタス言語
    • ドメインエキスパートや開発者を含めたチームで共有する言語のこと
    • 名詞だけでなく形容詞や動詞も含まれる
    • 境界づけられたコンテキスト内で一意であれば良い
  • 戦略的設計
    • ユビキタス言語、境界づけられたコンテキスト、コンテキストマップを用いた抽象的なソフトウェア設計の総称
  • 戦術的設計
    • レイヤ化アーキテクチャ、エンティティ、サービス等の具体的なソフトウェア設計の総称

PHPとnginxとMySQLをdocker-composeでミニマム構築

ちょっとPHP触ってみたくなったのでnginxMySQLなWebアプリケーションをdocker-composeで構築してみる。

PHPの環境構築

PHPの実行環境をnginxで構築する場合、PHP-FPMを使いやり取りを行うらしい。
nginx と PHP-FPM の仕組みをちゃんと理解しながら PHP の実行環境を構築する - Qiita

php.iniファイルが↓

[Date]
date.timezone = "Asia/Tokyo"

[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

Dockerfileが↓

FROM php:fpm-alpine

COPY php.ini /usr/local/etc/php/

RUN docker-php-ext-install mysqli pdo pdo_mysql mbstring

nginxの環境構築

nginxのパラメータは正直ググりながら適当にやったら動いたという代物笑。
本格的に使うときにちゃんと調べる。

server {
    listen 80;
    server_name _;
 
    root  /var/www/html;
    index index.php index.html;
 
    access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;
 
    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }
 
    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_index index.php;    
        fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include       fastcgi_params;
    }
}

index.php

何を表示しようかと思ったけど、とりまDBに接続できてればよいかという発想で書いた。

<?php

printf("%s\n", date("Y/m/d H:i:s"));

$db = new mysqli("php-db", "root", "zaqroot", "test");

if ($db->connect_errno) {
  echo $db->connect_errno . " : " . $db->connect_error;
  exit();
}

$arr = $db->query("SELECT * FROM hoge");
while ($val = $arr->fetch_assoc()) {
  var_dump($val);
}

$db->close()

?>

docker-compose

肝心のdocker-composeファイルがこちら。
MySQLlatestを使ってます。

version: '3'
services:
  nginx:
    image: nginx:alpine
    container_name: php-nginx
    ports:
      - 8000:80
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
      - ./www/html:/var/www/html
    depends_on:
      - php
  php:
    build: ./php
    container_name: php-app
    ports:
      - 9000:9000
    volumes:
      - ./www/html:/var/www/html
    depends_on:
      - db
  db:
    image: mysql:latest
    container_name: php-db
    ports:
      - 13306:3306
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      - "MYSQL_USER=root"
      - "MYSQL_ROOT_PASSWORD=zaqroot"
      - "TZ=Asia/Tokyo"
    volumes:
      - ./mysql/data:/var/lib/mysql

出来たものがこちら

GitHub - yuki-toida/php-tutorial

感想

全然わからないが、なんとなくPHPを生のまま書くのは死ねる気がする。
一旦Laravel使ってみてからじゃないと評価できなそう。
というわけで次回はLaravel使う。

Cloud Storage FUSEを使ってGCSをGCEにマウントする

Cloud Storage FUSE とは

GCSを、Linux または OS X システム上でファイル システムとしてマウントするためのGoogle謹製OSS

Cloud Storage FUSE  |  Cloud Storage  |  Google Cloud

インストール

gcsfuse/installing.md at master · GoogleCloudPlatform/gcsfuse · GitHub

export GCSFUSE_REPO=gcsfuse-`lsb_release -c -s`
echo "deb http://packages.cloud.google.com/apt $GCSFUSE_REPO main" | sudo tee /etc/apt/sources.list.d/gcsfuse.list
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
sudo apt-get update
sudo apt-get install gcsfuse

マウントする

GCSのバケット名を bucket-vod とするとし、マウント元を/home/bucket-vodとすると、

sudo mkdir /home/bucket-vod
sudo gcsfuse -o nonempty bucket-vod /home/bucket-vod

これで、/home/bucket-vodbucket-vod にマウントされる。

GCE起動時にgcsfuseを実行する

GCEのカスタムメタデータstartup-script に同じコマンドをを仕込む。
これで、サーバー再起動等行っても正常にマウントされる。

sudo gcsfuse -o nonempty bucket-vod /home/bucket-vod

GCE で Wowza Streaming Server をつくる② GPUアクセラレーション編

前回の続き。
この記事ではGPUをGCEで使えるようにする設定を行う。

NVIDIA Driver をダウンロードする

Nvidiaの公式サイトから下記画像の沿ってドロップダウンを選択しダウンロードする。

  • Tesla
  • K-Series
  • Tesla K80
  • Linux 64-bit

f:id:yuki-toida:20181114162448p:plain

GCEでNVIDIA Driver を使うためのセットアップ

Set up NVIDIA NVENC accelerated encoding on Debian

この辺を参考にしつつ、ウルトラググりながら依存ライブラリをインストールする。

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install build-essential
sudo apt-get install linux-headers-$(uname -r)
sudo apt-get install dkms

blacklist.confblacklist nouveauを追加する。 vimで編集します。

sudo vim /etc/modprobe.d/blacklist.conf

ここで忘れずにGCE再起動。

NVIDIA Driver をGCEにアップロードしインストールする

GCEインスタンス名をwowzaとし、ドライバをNVIDIA-Linux-x86_64-396.26.runとすると、
下記SCPコマンドでアップロード可能。

gcloud compute scp ./NVIDIA-Linux-x86_64-396.26.run wowza:~/

GCEターミナル内でドライバを実行権限をつけてインストールする。

chmod +x NVIDIA-Linux-x86_64-396.26.run
sudo ./NVIDIA-Linux-x86_64-396.26.run

動作確認

nvidia-smi コマンドでGPUの使用状況が取得できれば正常にインストール完了。
一筋縄ではいかなかったので、ググラビリティが試されるかも。

f:id:yuki-toida:20181114164703p:plain