saeki’s blog

The limits of my code mean the limits of my world.

2018年9月5日

仕事

業務委託でお世話になってる会社では主に昔から動いてるシステムの保守や追加開発をやっている。
どこかで「保守しかできないエンジニアはゆるやかに死んで行く」というような内容のエントリを読んだことを雑に思い出してこのままじゃゆるやかに死ぬなおれ、という気持ちになった。
やっぱ個人開発かー。個人開発だよな。進めるぞ。

本を読むスピードが遅い

のだ。かなり遅い方だと思う。例えば300ページくらいの小説なら読み終えるのに2, 3日かかる。1日30分で2, 3日、ということではない。だいたい1日3, 4時間くらい費やして2, 3日である。
活字を追うのは好きなので読書それ自体にストレスはないし、むしろ現実逃避の手段として、ストレスから逃げるために読書することも多い。
自分がノロノロと一冊の本を読んでいる間に、優秀な人がより多くの本に出会い、人生観を揺さぶられて、知識が増えて、仕事の幅が広がって、どんどん優秀になっていくことを想像すると、自分は世界に取り残された気分になる。こういうことを感じるようになったのも、新しい職場の周りの人が異常に優秀な方ばかりで、自分は本当に知らないことが多いしできないことも多いということを日々感じているからだと思う。

2018年9月4日

ランチ

最近昼飯はおにぎりとヨーグルトだけという日が多くて、それはまともに食事する暇も無いほど忙しいからというわけではなく、ふつうに昼休みを取っておにぎりとヨーグルトを食べている。人間はちゃんと食事をするとたぶん血糖値が上がるとかで眠くなる。ふつうに昼飯を食べていた頃は食後の眠気に耐えられず昼寝をしていた。これが良くない。まず自分は昼寝最適時間とされている10分とか20分とかに睡眠時間を調整できない。一度寝たら1時間近く寝てしまう。そうすると頭がすっきりするどころか今度は本格的な眠気がやってくるので、その後まともに集中して仕事ができない。したがって自分はちゃんと昼飯を取らない方が良いという結論になった。昼飯の量を減らして、かつ夜にしっかり寝ていれば仕事中に眠くなることは無い。おにぎりは腹持ちが良いので夕方になるまでそこまで空腹感を感じることも無い。それで最近は集中力を維持できている気がするのでこの生活をしばらく続けると思う。

最近はだいたいこの組み合わせ f:id:t_saeki:20180904232523p:plain

ドメイン駆動設計

最近はエリック・エヴァンスの「ドメイン駆動設計」を読んでいる。いわゆるDDD本。自分にはかなり難しく、進んでは戻っての繰り返しになっていてまだ1/3くらいしか読めてない。
自分はDDDについてはネットの記事やスライドを読んで表面的にしか理解しておらず、DDDの文脈で使われる用語も雰囲気だけで使っていた。いくつかのプロジェクトでもDDDっぽくやってみたがあまりしっくり来ることはなく、あまりその恩恵に与れていなかった。
これを読み終えたら実践ドメイン駆動設計も読みたい。

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

フリーランスになった

実は7月からフリーランスになった。今は別の会社で業務委託のエンジニアとして働いている。せっかくフリーランスになったのに週40時間働いてるから正社員の頃と生活があまり変わっていない。このあたりの話はまた改めて書きたい。とりあえずfreeeを使って開業費だったり日々の経費を入力したりしてるが、これで正しいのか良くわかってない。良さそうには思える。

vscodeでPlantUMLを使ってシーケンス図を書く

vscodeでPlantUMLを扱えるように設定したのでその覚え書き。

Java

何はともあれ今すぐJavaをダウンロード
https://java.com/ja/download/

graphviz

graphvizはテキストをグラフに変換するためのツール。
brewで入る。

$ brew install graphviz

vscode

vscodeにplantumlの拡張を入れる。
パッケージ名は PlantUML

これで設定は完了だと思う。かんたん。

シーケンス図を書いてみる

vscodeは.pu拡張子をPlantUMLのファイルと認識するっぽいので.puの拡張子がついたファイルを用意する。

// sample.pu
@startuml
skinparam monochrome true

actor User

User -> Node1 : なにかする
Node1 -> Node1 : なにかする
Node1 -> Node2 : なにかを要求
Node2 -> Node3 : なにかを要求
Node3 -> Node1 : なにかの検証依頼
Node1 -> Node3 : 検証OK
Node3 -> Node2 : なにかを返す
Node2 -> Node1 : なにかを返す
Node1 -> User : なにかが完了

@enduml

ふつうにplantumlの記法で書ける。

option + D でプレビュー表示。
skinparam monochrome trueを指定すると白黒のシーケンス図になる。
自分はこっちの方が好み。

f:id:t_saeki:20180727142915p:plain

こんな感じ。
テキストを変更して保存すれば時間差でプレビューに変更が反映される。
すぐにプレビューを再描画したい場合は option + Dで再描画できる。

S3 + CloudFrontで静的サイトホスティングしたので作業ログを残す

AWSで静的サイトをホスティングする際の王道パターンと呼ばれているS3 + CloudFrontの構成、 今更ながら初めて構築したので作業ログを残しておく。

構成

f:id:t_saeki:20180501212914j:plain

こんな構成。

S3

まずはバケットを作る。本番用とStage用。
後から上書きするが、まずはローカルでindex.htmlファイルを作ってアップロードしておく。

f:id:t_saeki:20180430165202j:plain

今回はS3のファイルはpublicにせずCloudFront経由のみアクセスを許可するようにしたので、 S3の設定で「ホスティングの有効」はしない。

f:id:t_saeki:20180430164715j:plain

自分が作ってるときこの設定を有効にしていて、 CloudFront経由でAccess deniedで弾かれてハマった。

CloudFront

Distributionを作る

「Create Distribution」からWebの「Get Started」と遷移していく。

設定入力画面ではこんな感じの設定になった。

f:id:t_saeki:20180430171117j:plain

Origin Domain Name: テキストフィールドにフォーカスするとバケットがサジェストされるので何も考えずにそれを選択。
Restrict Bucket Access: Yesを選ぶと「Origin Access Identity」に自動で値がセットされる。
Grant Read Permissions on Bucket: 「Yes, Update Bucket Policy」を選ぶことでバケットポリシーも更新してくれる。

f:id:t_saeki:20180430171152j:plain

TTL: 普通にS3の静的ファイルを配信するだけなのでCloudFrontにキャッシュさせる時間を入れる。自分の場合は一ヶ月にした。
Compress Objects Automatically: Yes, ファイルのgzip配信を有効にする。

f:id:t_saeki:20180430171218j:plain

SSL Certificate: 独自ドメインを取ってSSLで配信する場合は設定する必要があるが今回は省略。

「Create Distribution」ボタンを押すとDistributionの作成が始まる。
完了するまでだいたい20~30分ほどかかる。

GitHub

普通にリポジトリ作る。

CircleCI

CircleCIからS3にファイルをアップロードする用のiamユーザーを事前に作っておく。
自分はユーザー名を「circleci」にした。

CircieCIのページに行って Add Project -> 設定 -> AWS Permission と遷移して 上記iamユーザーのAccess Key ID と Secret Access Keyを入力して保存しておく。

最終的に .circleci/config.yml はこんな感じになった。

version: 2
jobs:
  deploy:
    working_directory: ~/circle-ci
    docker:
      - image: circleci/node:latest
    steps:
      - checkout
      - run:
          name: Setup AWS credentials
          command: |
            sudo apt-get update && sudo apt-get install -qq -y python-pip libpython-dev
            curl -O https://bootstrap.pypa.io/get-pip.py && sudo python get-pip.py
            sudo pip install -q awscli --upgrade
            mkdir -p ~/.aws
            printf "[default]\nregion = ap-northeast-1\nnoutput = json" > ~/.aws/config
            printf "[default]\naws_access_key_id = ${AWS_ACCESS_KEY_ID}\naws_secret_access_key = ${AWS_SECRET_ACCESS_KEY}" > ~/.aws/credentials
            chmod 600 ~/.aws/*
      - run:
          name: deploy static files to s3 stage
          command: |
            if [ "${CIRCLE_BRANCH}" == "stage" ]; then
              aws s3 sync ./public s3://<your stage bucket>/ --delete
            fi
            if [ "${CIRCLE_BRANCH}" == "master" ]; then
              aws s3 sync ./public s3://<your prod bucket>/ --delete
            fi
workflows:
  version: 2
  deploy:
    jobs:
      - deploy

解説としては
- 無駄なファイルをS3に上げないように公開用のディレクトリを用意してそれをS3と同期するようにした
- stage, masterで別々のjobを用意する方法はうまくいかなかったので、commandでブランチの分岐を書いた
- awscli用のimageを用意しておけばよかったっぽい

いずれにしても、これでGitHubでstage, masterにマージされたタイミングでS3にファイルがアップロードされるようになった。

Lambda

CircleCIからS3にアップロードするだけだと不十分で、最新のファイルを配信するためにはS3のファイル更新時にCloudFrontのキャッシュをinvalidationしたい。 ので、S3のファイル更新をLambdaで検知してLambdaからCloudFrontにinvalidationする。

以下、lambdaのコード。

import json
import urllib.parse
import boto3
import os
import time

s3 = boto3.client('s3')

def lambda_handler(event, context):
    print("Received event: " + json.dumps(event, indent=2))

    bucket = '<your bucket name>'
    key_orig = event['Records'][0]['s3']['object']['key']
    key_path = "/" + urllib.parse.unquote_plus(key_orig, encoding='utf-8')
    print("bucket: " + bucket)
    print("key path: " + key_path)
    
    client = boto3.client('cloudfront')
    invalidation = client.create_invalidation(DistributionId=os.environ['CLOUDFRONT_DISTRIBUTION_ID'],
        InvalidationBatch={
            'Paths': {
                'Quantity': 1,
                'Items': [key_path]
        },
        'CallerReference': str(time.time())
    })

stage, masterそれぞれのDistribution用にfunctionも作った。

おわり

書き疲れたのでこのへんで。
S3にファイルを上げるためにCIでコンテナ立ち上げるのはリソースの無駄使いな気がしてならないが、
まあ凝ったことしなければ無料で使えるから、自動化できる部分はできるだけ自動化しましょうということで。

「現場で役立つシステム設計の原則」読んだ

読んだ。内容としてはDDD本の実践編という感じで非常に勉強になった。

自分は仕事でも趣味でも MVC + Service でレイヤを組んでwebアプリを作ることが多いんだけど、雰囲気でServiceをやってるように感じていつもモヤモヤしてた。
特にRailsだとどうしてもActiveRecordを中心とした作りになるから、業務ロジックがテーブル設計に引っ張られて疎結合にならない。
それに画面の設計にも引っ張られるとデータの加工なんかもServiceでゴリゴリやっちゃってコードの見通しが悪くなる。
そもそも自分が理解してたモデルの上位層としてのService、という位置付けがよくないのかもしれない。

オブジェクト指向設計の他には、プロジェクトにおける上流工程、テーブル設計、Web Api、マイクロサービスなどweb開発において抑えておくべきトピックをオブジェクト指向の観点から網羅的に書かれていて勉強になった。