レガシーをぶっつぶせ。現場でDDD! 参加レポート #genbadeDDD
申込み時点で +100 人くらいで補欠だったので諦めてたんですが、 当日の 0:30 に繰り上がり通知が来て、慌てて参加しました。
全体を通して、いくつか印象に残ったことを書いておきます。
- 始める前にメンバーとの共通認識をつくる
- DDD の方法そのものの学習
- 業務知識の理解
- エンジニア以外のメンバーとの共通認識も重要
- 良い設計のためにはビジネスの理解が必要
- まったく新しく取り組む場合はリスクを小さくする
- 小さく始める
- 重要だが緊急性が低いもの
- 緊急性が高いと品質を犠牲に完成を強いる圧力がかかりがち
- ビジネスサイドへの説明は簡単ではないが大事
- 小さく始めると少ないコストで実績を積んで成果を確認できる
- 刷新前と刷新後のコードベースに対して同じ改修をして効果測定をした
説得のために刷新前と刷新後全く同じ機能を作って効果測定したらしい!すごい #genbadeDDD pic.twitter.com/xVcRCk8kfn
— 松岡@DDDブログ書いてます (@little_hand_s) 2019年5月11日
- 変化に弱い = レガシーになりやすい
- とりあえずマイクロサービスにすればいいというわけではない
- サービス分割がイケてないとやっぱりポシャる
感想
- 新規開発ではつまづかないような、レガシーと戦う上での知見が聞けてよかった
- チームで DDD に取り組むための心構えができた
- まだ仕事で実践できていないけど、学んだ内容の再確認ができた
- DDD は銀の弾丸ではない。レガシーとの戦いは泥臭い作業の繰り返しだ。
zsh + zplug で最強でポータブルなターミナル環境を作りたい
タイトルで言いたいことは全部言いました。
なんとなくインストールしていた zplug, よく見ると何でもかんでもインストールできることに気づきました。
zplug "jhawthorn/fzy", \ as:command, \ rename-to:fzy, \ hook-build:"make && sudo make install"
これを使えば、言語環境から各種 CLI ツールまで全部 zpug で管理できるのでは? 最終的に、まっさらな環境で
sudo yum install -y git zsh git cllone git@github.com:ikasam/dotfiles.git chsh -s /bin/zsh exec zsh -l
と実行するだけで開発環境が出来上がるかもしれない。
導入するもの
次に新しい職場に行くまでに作っておきたい。
技術書典 6 の本の感想 / 技術を伝えるテクニック
- テクニックの具体例があって実践しやすい
- 文章だけでなく、登壇のテクニック、上手く教わるテクニックも紹介されていて良い
- 目次だけでもだいたい伝わってくるところがすごい
技術書典 6 の本の感想 / フリーランスを完全に理解できる本 / バーチャル幼女プログラマー きりみんちゃん 公式ファンブック
フリーランスを完全に理解できる本
- フリーランスという働き方にまつわる事柄を 1 冊で知れます
- 一つ一つのトピックは自力で調べられる内容だけど、コンパクトにまとまっていて良い
- 単価水準は参考にしてみようと思いました
- あくまで 2019 年現在、東京都内の Web 系エンジニアの相場です
- 税金周りはサラリーマンでも知っておいて損はない内容だと思います
- キャリアについては軽く触れられている程度ですが、すぐに実践しやすい内容です
- このあたりを掘り下げたかったら、より詳しい専門書をあたると良いでしょう
- 作者: ジョン・ソンメズ
- 出版社/メーカー: 日経BP社
- 発売日: 2016/06/02
- メディア: Kindle版
- この商品を含むブログ (8件) を見る
バーチャル幼女プログラマー きりみんちゃん 公式ファンブック
- 文字が少ないので脳のリソースを使わなくて良いです
- 1 ページ目に
Hallo kirimin-chan
って書いてあるけど幼女キャラの演出かなと好意的に捉えています - 君も公式ファンブックを買ってきりみんちゃんを応援しよう!
CakePHP 2.x の PaginatorHelper をハックする
TL;DR
この CookBook にあるようなパラメータを $this->request->params['paging']
に渡すことで任意のページネーション表示ができます。
https://book.cakephp.org/2.0/ja/core-libraries/helpers/paginator.html#PaginatorHelper::params
実際にパラメータを渡すサンプル。
$params = [ 'page' => 2, 'current' => 10, 'count' => 777, 'prevPage' => false, 'nextPage' => true, 'pageCount' => 4, 'order' => null, 'limit' => 10, 'options' => [], 'paramType' => 'querystring', ]; $this->request->params['paging']['YourModel'] = $params;
背景
いまどき CakePHP 2 かよ! とお思いかもしれませんが、なかなかレガシーから抜け出せない組織、ありますよね。 弊社ではようやく新しいフレームワークに移行することが決まったんですが、それがまさかの CakePHP 3 。 どうせならもっとほかのフレームワークにしてくれや……と内心思いながら移行の仕事をしています。
今回の移行は、利用者や役割の異なる複数のアプリケーションにそれぞれ書かれている、同じようなビジネスロジックを API に一本化してしまおうという目的があります。 単なるデータフェッチなら API にまるっと移してほぼ同じ構造のデータを返してもらい、 Controller とかがそれを受け取ればいいだけです。 しかし Paginator は View に がっつり Helper として入っていて、正直修正したくない。 *1 ということで Paginator によるデータフェッチをレガシーから切り離しつつ、 レガシーの Paginator には出来合いのパラメータを渡して PaginatorHelper を生きながらえさせる作戦を考えました。
実装
PaginatorHelper のパラメータサンプルの URL を再掲します。
https://book.cakephp.org/2.0/ja/core-libraries/helpers/paginator.html#PaginatorHelper::params
各パラメータの意味はこんな感じ。間違っていたら指摘ください。
$params = [ 'page' => 2, // 現在のページ番号 'current' => 17, // 現在のページに表示している件数 'count' => 3, // 全体の件数 'prevPage' => false, // 前のページがあるか? 'nextPage' => true, // 次のページがあるか? 'pageCount' => 4, // 全体のページ数 'order' => null, // ソート順 'limit' => 26, // 1 ページの件数( {:start}, {:end} の計算に使うのはこちら ) 'options' => [], // ページネーションのオプション。なんかいろいろあるっぽい。 'paramType' => 'querystring', // 生成するリンクのタイプ。この場合は ?page=2 のようなリンクを生成する。 ];
こういうデータを渡してあげることで、実際のデータフェッチ内容とは無関係のページング UI を生成できます。
しかし無意味なページング UI を構築しては使い物にならないので、フェッチしたデータとの整合性をとる必要があります。
今回、データフェッチは API 化して HTTP の JSON でレスポンスを返してくれる実装になりました。
なので、データと横並びでページングのパラメータをセットし、それをそのまま横流しする形をとりました。
気を付ける点として、 API 側は CakePHP 3 のため、若干パラメータのキーが変わっています。
以下、 CakePHP2 => CakePHP 3
の形式です。
order => sort
*2limit => perPage
この変換は CakePHP 3 側に実装しました。 こういった互換性対応は新旧どちらに実装するかは好みによるところですが、新 : 旧 = 2 : 4 という事情もあって新側に実装しました。 *3
余談
今回の CakePHP 2 => CakePHP 3 移行でこういうのも作りました。 レガシーと戦う全国 5000 億人の CakePHPer のためにも、また別の機会に紹介できたらなと思います。
まとめ
$this->request->params['paging']
にパラメータを渡すことで PaginatorHelper を操れます- CakePHP 2 <=> CakePHP 3 の Paginator のパラメータには一部互換性がないので気を付けよう
参考
可処分時間を上手に分配する
概要
- 一日のうち、自由時間をうまく使いたい
- 今の自分の環境だと平日 2 時間、休日 13 時間
- 自由時間を可視化したい
- 自由時間から自動計算してやりたいことを割り当てたい
- 日々取り組みたいこととそれぞれの割合あるいは固定時間を定義しておく
- そういう Web サービスとかスマートフォンアプリないかな?
- ないなら作るか・・・
- 自由時間を増やしたい
背景
やりたいことはいくつかあるんだけど、「知る」ことが大好きなぼくは自由な時間をほとんどそれにつぎ込んでしまっている。 特に、簡単に情報にアクセスできるネットサーフィンをやりがちだ。 Twitter の TL やリストを眺める、ブログや Qiita を読み漁る、 Wikipedia で知らない単語を延々とはしごする、はてブの人気エントリーをチェックする。 さらには読み切れないから「あとで読む」に入れて、次の日は他の新しい記事を読んでいたりする。 「あとで読む」があとで読まれない。無限に積みあがっていく。
今日、このブログを書いたのはある意味では奇跡で、ある意味では自分への警告だ。 今から時間の使い方を変えなければ、無限に「知」をむさぼるだけの妖怪になってしまう。 かつてそれでもいいと思っていた時期もあったが、今はそう思っていない。 自分を変えねば。
考察
自由時間 = 24 時間 - 生活維持時間
- 生活維持時間とは?
- 仕事と通勤
- 睡眠、食事、入浴といった生理的なもの
- ルーチンワーク
- 掃除や家電、住環境のメンテナンス
- 子供がいたら送迎とか
まずは自由時間を見えるようにする
- 生活維持時間から逆算する
- 生活維持時間を見えるようにする
- 仕事と通勤: 12h ( 定時勤務でこれはアレな気がする )
- 睡眠: 7h ( 最低これだけは欲しい )
- 食事: 1h ( これは朝+夜だけ、昼は仕事時間に含まれる )
- 入浴: 1h ( ぬるま湯で長風呂が好き )
- その他: 1h ( 掃除とか、アトピーのケアとか、雑に使うバッファ )
- 24h - 22h ( 生活維持時間 ) = 2h ( 自由時間 )
- 少なくね・・・?
- 2h 残業するだけで消える
- まず通勤時間が 3h でアレ。通勤は悪。
- 休日は 13h あった
- 仕事と通勤がなくなって自由時間 +12h
- 睡眠を +1h して 自由時間 -1h。休日はたくさん寝たいよね。
自由時間のスケジューリング
- やりたいことを決める
- インプット
- インターネット
- 書籍
- アウトプット
- ブログを書く
- コードを書く
- 語学 ( 特に英語 )
- ゲーム ( 最近はモチベーション低い )
- インプット
- やりたいことの時間配分を決める
- 割合: インプット 50%, アウトプット 30%, ゲーム 20% とか
- 固定時間: インプット.書籍 は 0.5h/1日 とか
- こういうのを日々自動計算して教えてくれると嬉しい
- イレギュラーなイベントで予定が狂っても現在時間から再計算してくれると助かる
- 何に何時間使ったとか、時間の記録もできると良い
自由時間を増やす
- = 生活維持時間を削る
- 安易に短時間睡眠に挑戦して睡眠時間を削りがち
- やってもいいけど向き不向きがあるのでその方法に固執しないこと
- 通勤時間は本当に無駄でしかないので削りたい
- 個人的には入浴、その他は頑張れば削れそう
- 体のケアや QoL 維持、日々の時間に余裕を持たせたいのでできれば削りたくない
- 仕事の時間を削るのもありかもしれない
結論
- まずは手動で、自由時間、生活維持時間の可視化とスケジューリングをやってみる
- そういうことを計算・記録してくれるアプリや Web サービスを探す
- なかったら自分で作る
docker-compose で複数環境を構築するときの設定をなるべく DRY に書く
概要
docker-compose
の-f, --file
オプションを複数使って、共通の Composeファイル と環境ごとの Compose ファイルを読み込むようにします- こうすることで、共通の設定を DRY に書けます
-p, --project-name
オプションとnetworks
で環境を分離します- 以下のリファレンスの内容が理解できていればこの記事を読まなくても大丈夫です
背景
docker-compose, 便利ですよね。 Docker 完全に理解した *1 くらいのレベルで複数コンテナの環境を作るなら手軽でよいです。
その docker-compose が開発環境だけならまだいいんですが、 テスト用の環境も同じ仕組みで作るようになると、 環境差分をどうするかが課題になります。 例えば、以下のような環境差分が考えられます。
まだまだありそうです。 実際に差分が発生するかはアプリケーションの設計や環境にもよるんですが、 いったんこういう差分があり得るという前提で話を進めます。
アンチパターン
1. Compose ファイルは 1 つで、環境ごとに branch を切る
- 修羅の道です
- Compose ファイルがブランチごとに成長して、目も当てられなくなります
- 唯一のメリットは、「環境ごとの起動コマンドが一緒」
- でも各環境にそれぞれ 1 step で起動できるジョブを用意しておけばいいですよね?
2. 環境ごとに Compose ファイルを作る
- 修羅の道パート 2 です
- やっぱり Compose ファイルがファイルごとに成長していきます
- プロジェクト名が同じだから同じサービス名が使えなくなり、かなりつらいです
解決策
$ docker-compose -f docker-compose.yml -f <your_env>.yml -p <your_env> up -d
実装例はこちら。
解説
-f, --file オプション
共通の Compose ファイル ( docker-compose.yml
) と環境依存の Compose ファイル ( <your_env>.yml
) を読み込みます
共通
$ cat docker-compose.yml version: "3.5" services: web: build: context: ./web volumes: - ./web/proxy-to-back.conf:/etc/nginx/conf.d/proxy-to-back.conf:ro environment: VIRTUAL_HOST: "*.web.local,*.back.local" networks: - default - front back: build: context: ./back depends_on: - web networks: front: external: true
環境依存
$ cat env1.yml version: "3.5" services: web: environment: VIRTUAL_HOST: "env1.web.local,env1.back.local" APP_ENV: env1 volumes: - ./web/env1.html:/usr/share/nginx/html/index.html:ro back: volumes: - ./back/env1.html:/usr/share/nginx/html/index.html:ro networks: default: name: env1 $ diff env1.yml env2.yml 5c5 < VIRTUAL_HOST: "env1.web.local,env1.back.local" --- > VIRTUAL_HOST: "env2.web.local,env2.back.local" 7c7 < - ./web/env1.html:/usr/share/nginx/html/index.html:ro --- > - ./web/env2.html:/usr/share/nginx/html/index.html:ro 10c10 < - ./back/env1.html:/usr/share/nginx/html/index.html:ro --- > - ./back/env2.html:/usr/share/nginx/html/index.html:ro 14c14 < name: env1 --- > name: env2
- 前のファイルで定義した同じフィールドの項目が後のファイルにあれば、それを上書きします。
- 新しい値があれば追加します。
例えば、
environment
の同じキー (VIRTUAL_HOST
) は上書きされますenvironment
の異なるキー (APP_ENV
) は追加されますvolumes
は追加されます
最終的にどんな設定になるのかは、 docker-compose config
コマンドを使うと見れます。
$ docker-compose -f docker-compose.yml -f env1.yml -p env1 config networks: default: name: env1 front: external: true name: front services: back: build: context: /home/ikasamak/work/dc-multi-env/back depends_on: - web volumes: - /home/ikasamak/work/dc-multi-env/back/env1.html:/usr/share/nginx/html/index.html:ro web: build: context: /home/ikasamak/work/dc-multi-env/web environment: APP_ENV: env1 VIRTUAL_HOST: env1.web.local,env1.back.local networks: default: null front: null volumes: - /home/ikasamak/work/dc-multi-env/web/proxy-to-back.conf:/etc/nginx/conf.d/proxy-to-backi.conf:ro - /home/ikasamak/work/dc-multi-env/web/env1.html:/usr/share/nginx/html/index.html:ro version: '3.5'
-p, --project-name オプション
プロジェクト名を指定します。 デフォルトは compose ファイルのあるディレクトリ名です。
~/work/dc-multi-env master* $ docker-compose up -d Creating network "dc-multi-env_default" with the default driver
プロジェクト名を指定せずに同じディレクトリで別環境を立ち上げると、 同プロジェクトの同サービスと見なされ、既存のコンテナがかき消されてしまいます。
$ docker-compose -f docker-compose.yml -f env1.yml up -d Creating network "env1" with the default driver Creating dc-multi-env_web_1 ... done Creating dc-multi-env_back_1 ... done $ docker-compose -f docker-compose.yml -f env2.yml up -d Creating network "env2" with the default driver Recreating dc-multi-env_web_1 ... done Recreating dc-multi-env_back_1 ... done $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ffd5b9f636be dc-multi-env_back "nginx -g 'daemon of…" 5 minutes ago Up 5 minutes 80/tcp dc-multi-env_back_1 6dcafba12120 dc-multi-env_web "nginx -g 'daemon of…" 5 minutes ago Up 43 seconds 80/tcp dc-multi-env_web_1
-p
でプロジェクト名を指定し、別環境として立ち上げます。
$ docker-compose -f docker-compose.yml -f env1.yml -p env1 up -d Creating network "env1" with the default driver Creating env1_back_1 ... done Creating env1_web_1 ... done $ docker-compose -f docker-compose.yml -f env2.yml -p env2 up -d Creating network "env2" with the default driver Creating env2_back_1 ... done Creating env2_web_1 ... done $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2496c6858e0c env2_web "nginx -g 'daemon of…" 4 seconds ago Up 3 seconds 80/tcp env2_web_1 fa5bcec301ad env2_back "nginx -g 'daemon of…" 5 seconds ago Up 4 seconds 80/tcp env2_back_1 0aca011671e7 env1_web "nginx -g 'daemon of…" 12 seconds ago Up 11 seconds 80/tcp env1_web_1 ec885d01fa73 env1_back "nginx -g 'daemon of…" 13 seconds ago Up 12 seconds 80/tcp env1_back_1
プロジェクト名を指定する方法
-p, --project-name
オプションを使うCOMPOSE_PROJECT_NAME
を使う- 環境変数を
.env
ファイルで指定する
- 環境変数を
Compose ファイルにプロジェクト名を指定できれば楽なんですけど、そういう仕様にはならなかったようです。
まあ普通は環境ごとにディレクトリ分けるから、 .env
で何とかしなさいということなんでしょう。
networks
適切にネットワークを設定しないと、コンテナ名で名前解決していると別環境にトラフィックが飛んでしまうことがあります。
例えば、面倒なんで全部 front のプロキシのいるネットワークにつないでしまえ! ということをすると
$ cat docker-compose.yml version: "3.5" services: web: build: context: ./web volumes: - ./web/proxy-to-back.conf:/etc/nginx/conf.d/proxy-to-back.conf:ro environment: VIRTUAL_HOST: "*.web.local,*.back.local" networks: - front depends_on: - back back: build: context: ./back networks: - front networks: front: external: true
env1
の web
が env1
, env2
両方の back
とつながるので、
back
へのアクセスがロードバランシングされてしまいます。
$ curl -H "Host: env1.back.local" localhost here is env2.back! $ curl -H "Host: env1.back.local" localhost here is env1.back! $ curl -H "Host: env1.back.local" localhost here is env2.back! $ curl -H "Host: env1.back.local" localhost here is env1.back!
なので、適切にネットワークを設定しましょう。
プロジェクト名を分けているのであれば、 default
で通信するようにしましょう。
*2
おまけ
extends
を使えば、設定をモジュール化して再利用できるようです。
2019/03/08 追記
extends
は compose file format v3 で使えなくなってました。
まとめ
- 共通部分、環境依存部分に分けることで Compose ファイルを DRY に書けます
-p
オプションでプロジェクト名を分け、同じサービス名を別環境で同時に動かせるようにしますnetworks
を適切に設定して別環境にトラフィックが迷い込まないようにします
参考
- Overview of docker-compose CLI | Docker Documentation
- Compose file version 3 reference | Docker Documentation
- Networking in Compose | Docker Documentation
*1:https://twitter.com/ito_yusaku/status/1042604780718157824
*2:サービス名だけの名前解決 ( http://back とか ) は、default ネットワークから行われるようです