micro tips

些細なこと

2020年の学習と2021年やりたいこと

年末年始あたりに投稿しようと思っていましたが、大分遅れてしまいました、供養。

2020年に取り組んだもの

  • React - The Complete Guide (incl Hooks, React Router, Redux) - Udemy
    主にサーバーサイド、インフラをメインにしていますが、フロントもある程度できるようになっておきたいというのと、近い将来業務でもフロントの開発をすることになりそうということでやってみました。
    Vueに関しても少々触ったことがあるのですが、Reactの方がTypeScriptとの相性がよい点、Vueと比べてプリミティブなためJSやライブラリの仕組みを理解する必要があり結果的に勉強になる点からReactを集中的に勉強することにしました。
    ただ、当初自分にとってReactの仕組みやReduxの考え方にはハードルが高くQiitaの記事などをいくつ読んでもわかったようなわからないような感じでした。
    そのため、Udemyの動画を見ながら写経することにしたのですが、日本語だと選択肢があまり多くないため英語のコースも含めて検討したところ、このMaximilianさんのコースは評価が高く、Reactを網羅的に学習できそうだったので選びました。
    モダンJSの記法からReactの仕組み、Reduxの考え方を解説しながら最終的にReact Hooks, React Sagaまでカバーしてアプリケーションを開発することで網羅的な学習をすることができました。
    ビデオ自体が全部で約40時間ほどあり、写経・デバック等含めて100時間くらいは使った気がしますが、かなりReactに慣れました。

  • Understanding TypeScript - Udemy
    上記と同様でUdemyのMaxilimianさんのコースです。 こちらもわかりやすかったですが、ボリュームはReactほどなく、TypeScriptを使いこなすにはやはり実践で型システムをガンガン使っていくしかないのかなという印象

  • りあクト! TypeScriptで始めるつらくないReact開発
    Udemyのコースでは、valina jsでのコースだったため、TSとReactの感触をつかむために読みました。 ただ、React, Redux, JS/TS自体の話はUdemyでほとんど網羅できていたと思う。

  • DNSをはじめよう ~基礎からトラブルシューティングまで
    DNSの基本的な仕組みから、代表的なレコードの役割を学ぶことが出来た。 雰囲気でRoute 53を触っていたが、これを読んだおかげで大分自信をもってRoute 53をいじれるようになった。

  • SSLをはじめよう ~「なんとなく」から「ちゃんとわかる!」へ~
    httpsの重要性やSSL証明書の仕組みを学ぶことができた。 重要な技術だがDNSほど普段細々とした作業もないので、実作業などではまだ活きる場面に出会ってない。

  • Goプログラミング実践入門 標準ライブラリでゼロからWebアプリを作る
    社内の一部でGoを採用するため、こちらで勉強させていただきました。 シンプルな文法と標準ライブラリの機能が充実していること、非同期処理が手軽にかけること、コンパイルが早くテスト、ベンチが外部依存なしにできることなどなどかなり魅力的な言語でした。 RubyRailsデファクトになっていることとは対照的にGoでは、あまり厚いフレームワークを使わない傾向があると思います。 こちらの書籍では基本的に標準ライブラリを利用してWeb アプリケーションの構築工程が解説されおり、標準ライブラリの仕組みやインターフェースになれることが出来ます。 外部のライブラリを使う場合も標準ライブラリでのインターフェースが踏襲されていることも多いので、標準ライブラリになれておくことは重要なようです。

  • Pragmatic Terraform on AWS
    実務でインフラを0から組むことがあり、IaSを一気に推し進めるためterraformの導入を決めました。 使い方やディレクトリ構成の指針として活用させていただきました。 AWSのサンプルコードが豊富でかなり助かりました。

  • 低レイヤを知りたい人のためのCコンパイラ作成入門
    これはまだ「電卓レベルの言語の作成」までしか終わってませんが、写経して実際に手元で動かしながら取り組んでいます。 この教材に出会うまでコンパイラがどうゆう仕組みで動いているか、ほとんど想像できない状態でしたが、構文解析アセンブリの出力がどうゆうものなのかある程度理解することが出来ました。 これまで、アセンブリを触ることは全くなかったのですが、低レイヤへのとっかかり、Cやmakeに慣れる機会としてかなり良かったです。 今後も時間があれば続きをやりたいと思います。

  • HTML5&CSS3デザイン 現場の新標準ガイド【第2版】
    上述のUdemyのReactの教材では、HTML/CSSに関しては突っ込んだ話はないので、現状を把握するために読みました。 どちらかというと辞書的な使い方が想定されるような書籍ですが、読み切れないボリュームではないのです。 これまでなんとなく使っていたHTMLタグの使用や把握していなかったCSSプロパティを頭にいれることで、フロントエンドの実務でキャッチアップがかなりスムーズになったと思います。

  • Web API: The Good Parts
    大量のAPIを開発する機会があり、体系的な教材が欲しかったので読みました。 Web APIを設計する上での、エンドポイントの考え方、レスポンスのスキーマの考え方などいくつかの指針を得ることが出来た。 また、HTTPにおいてのセキュリティについても記載があり、特にHTTPのセキュリティヘッダに関してはこれまで意識する機会がなかったので役に立ちました。

  • ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本
    これまでDDDについては、Evans本を読んだり(途中まで)、記事などで断片的に情報を仕入れていましたが、こちらの書籍は読みやすく具体的なサンプルコードが豊富で DDDのとっかかりとしてかなりよいと思いました。 ただ、DDDの本質的な部分は深く説明されているわけではないので、やはり概念的な部分を深く理解するにはEvans本やその他の本を参照しながら実際にトライアンドエラーを繰り返していかないといけないという印象

2021年やりたいこと

今年は、今のところ「オブジェクト指向のこころ」、「体系的に学ぶ 安全なWebアプリケーションの作り方」を読みました。 あと前々から興味のあったRustに入門するため「実践Rustプログラミング入門」を読み進めてます。 公式のドキュメントある程度読んだことがあるのですが、こうゆう書き方・ライブラリがよく使われますみたいなのが書かれていて結構よいです。 今後は「Linuxの仕組み」、「マスタリングTCP/IP」、「Real Wold HTTP」あたりを読みたい、普段使っている技術の中身を知るのが面白いというのと、ブラックボックスにしておきたくないというのがある。 競プロやってみないのでその勉強もしたいなーという感じです。

オブジェクト指向のこころを読んだ

TD;DR

雰囲気でオブジェクト指向言語を使っていた

今まで、オブジェクト指向言語を日常的に利用し、プログラミング言語の書籍に書いてある「オブジェクト指向」の使い方やインターネット上の断片的な情報を元に『オブジェクト指向』を使ってきました。

エンジニアにとってアプリケーションの設計は永遠のテーマであり、私もドメイン駆動設計関連の記事や書籍をいくつか読んでは完全に消化仕切れずにいました。 段々わかってきたのがドメイン駆動設計はオブジェクト指向の延長線上にあるっぽいということ。

そもそも自分は現状もっとも広く利用されているオブジェクト指向というパラダイムをを中途半端にしか理解できていないのだからドメイン駆動設計を学ぶ段階になかったのです。

ということで、オブジェクト指向の書籍を探したのですが、複数の知人がおすすめしていたためこちらの書籍を選びました。 電子版がなく大型本なので物理的に読みやすくはなかったのですが、内容は非常に良かったので満足しています。

本書のながれ

まず、とあるシステムを題材に継承を多用した従来のオブジェクト指向の手法で設計をし、要求の変更があった際の保守性や柔軟性といった継承の問題を示します。
その後、いくつかのデザインパターンを紹介し、先ほどのシステムをデザインパターンを利用した形で再度設計します。
これによって、特殊化と再利用目的とした継承ではなく、デザインパターンを利用することでより堅牢で柔軟な設計が可能であることが説明されています。
また、既存のデザインパターンはそれぞれ特定の状況で適用するものですが、インターフェースを用いて設計し、集約を用いて流動的要素をカプセル化するというデザインパターンの教訓はどのような設計でも適用可能であり、それに従うことで柔軟な設計が可能なことが語られ、オブジェクト指向の原則をより深く解説されています。

プログラミング言語入門本では、継承などの機能的な側面は説明されてもなかなかクラス・オブジェクトの責務や実装、設計のカプセル化といったトピックは深く説明されないことが多いと思います、本書では実際にパターンを利用して設計するプロセスを見せることでオブジェクト指向の本質を実感できるつくりになっています。
本書を読んだことで、オブジェクト指向の階段を確実に進んだ実感がありますし、本書で紹介されていないデザインパターンについてもひと通り理解しておきたいというモチベーションも生まれました。

関数型言語への興味

オブジェクト指向をある程度「うまくやる」方法は理解したものの、そもそもオブジェクト指向で語られる適切な抽象化というものが非常に難しいことは日々実感しているところである。

そんな中ふと、オブジェクト指向関数型プログラミングを検討した記事を読んだことでオブジェクト指向以外のパラダイムも勉強してみたいなーと思ってしまった。
Elixir から Elm の流れで、いよいよオブジェクト指向に対する懐疑心が無視できないレベルに達した2017年冬。

近年おおくのOOP言語は関数型言語から機能を輸入はしているものの、やはり純粋関数型言語をやらないと関数型プログラミングのなんたるかはわからないだろうなーと思い とりあえずすごいHな本を買ってしまったので、地道に読んでいきます。。

オブジェクト指向のこころ

Laravel-Swooleでunix domain socketを使う方法

最近PHPで新しくサーバーを立てる機会があったのですが、出来るだけパフォーマンスのオーバーヘッドを意識したくない && シンプルな処理しかしない小規模なサーバーということもありポピュラーなnginx + fpmの構成ではなく、Laravel-Swooleを採用しました。

Laravel-Swooleは、swooleというPHPでイベント駆動な非同期サーバーを実現するextensionをLaravel/Lumenで簡単に利用可能にするライブラリです。

ドキュメントをひと通りチェックしたところ、The support of swoole_http_server for Http is not complete. So, you should configure your swoole server with nginx proxy in your production environment.と記載があり、単体での利用は推奨されていないようでした。

9. Nginx Configuration · swooletw/laravel-swoole Wiki · GitHub

ただ、サンプルで用意されているnginxの設定はリバースプロキシをTCP/IPで行っており、Laravel-Swooleのドキュメントにはunix domain socketに関する具体的な設定例は見当たりませんでした。 一応、swoole自体もunix socketに対応していますし、Laravel-Swooleの設定項目にもunix socketが存在します。


swoole_http.php

<?php

return [
    'server' => [
        'host' => env('SWOOLE_HTTP_HOST', '/var/run/swoole.sock'),  // socketを置くパスを指定する
        'port' => env('SWOOLE_HTTP_PORT', '0'), // unix socketを使う場合0にする
        'socket_type' => SWOOLE_UNIX_STREAM, // unix socktを使う場合 SWOOLE_UNIX_STREAM / SWOOLE_UNIX_DGRAM を指定する
        // ....
    ],
    // ...
];

以上でswoole自体の設定は出来たのです、Laravel-Swooleとnginxを別ユーザーで実行する場合socketのパーミッションをいじってやる必要があります。

取り急ぎpermissionを変更したいのですが、php-fpmでいうところのlisten.modeに相当する設定項目がLaravel-Swooleにはないようです。

dockerで利用するので、swoole起動時にフックしたいのですが、どうしようかと思ったところswooleのexampleに参考になりそうな記述がありました。
どうやら、swooleサーバーの起動時に発行されるイベントにフックしてchmodを叩いてやれば良いようです。

swoole-src/stream_server.php at 15404958c76edfe745e18a9219439f4bd9993b71 · swoole/swoole-src · GitHub

Laravel-Swooleでは、swoole.startというイベントが発行されるので、それにフックしてsocketのパーミッションを変更します。

laravel-swoole/Manager.php at master · swooletw/laravel-swoole · GitHub


EventServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use SwooleTW\Http\Server\Facades\Server;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
    ];

    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        parent::boot();

        // swoole 起動時にsocketのpermissionを変更する
        Event::listen('swoole.start', function () {
            $server = $this->app->make(Server::class);
            chmod($server->host, 0666);
        });
    }
}

ただ、unix domain socketを使う場合のpermissionは666でベストなのか、dockerで複数コンテナ使う場合のユーザーの取り回しなどは未解決、、

FPM opcache + preload / swoole / PHPP-PMあたりの比較してみたい。

選ばれたのはAmplifi HDでした。

新しいルーター

そういえば、4月に新しいWiFiルーターを購入しました。

f:id:highgreat:20200820222828j:plain
Amplifi HD

キューブ型のシンプルなデザインにタッチスクリーンが搭載されており、WiFiとしてだけでなく時計にもなるのがとてもエレガントです。

このルーターですがUbiquitiという近年米国でシェアを伸ばしているネットワーク機器メーカーの製品です。

タッチスクリーンで、ネットワークの接続情報を確認できたり、アプリから設定・モニタリング、さらにVPN、メッシュにも対応しているところが気に入っています。

NECWiFiルーターが調子悪くなる

実はNEC Atermを10年近く使っており、これも安定していたので気に入っていたのですが、流石に寿命が来たのか接続が不安定になってしまいました。 感染症の影響で、自宅での作業がほとんどになったこともあり、ネットワークの安定は死活問題。

早急に、かつ信頼できるWiFiルーターはないか、、と検討したところ、最終的にこのAmplifiくんが選ばれました。

ひとたびamazonWiFiルーターと検索すれば、大量の有象無象が出現し頭が痛くなります。 Baffaloは宗教上の理由で使えないし、またNECを買うのも芸がない。 かといって、それ以外のルーターは下品にもツノを生やせばはやすだけ良いというようなデザイン

信頼できて、デザインも優れたルーターはないかと思ったところ、rebuildで聞いたことのないルーターの名前が出てきました。

rebuild.fm

調べたところ、最近一部で注目を集めているWiFiルーターで、信頼性、機能性、デザイン性どれも良さそう。

Wi-Fiを Amplifi HD に移行した - tech.guitarrapc.cóm

yabe.jp

これは間違いないと、購入を決定しました。

IPv6が繋がらない

さて、意気揚々と古いWiFiを撤去してAmplifiをセッティングしたわけですが、全然スピードが出ない。 おいおい、どうなってんだ、こっちは大枚叩いてるのに10年前のWiFiよりスピードが出ないなんでおかしいぞ、、、、 と思って調べたところ、どうやらAmplifiはIPoEに対応しておらず、PPPoE IPv4でのみの通信になっていることが原因のようだった。

しばらくはIPv6パススルー機能を使うために前段に古いAtermを噛ませって使っていました。せっかく新しいルーターを買ったのに古いルーターに頼る羽目になるとは、、 (いまだにこのIPv6パススルーって機能がわかってない、なんでPPP接続するとIPv6降ってくるんだ、、?)

その後、中古のNEC IX2105を購入して、IPv4 over IPv6(MAP-E)を利用しています。 今まで、時間帯や接続先によってスピードが出ないことがあったのですが、IPv4 over IPv6の導入でかなり快適になりました。

UNIVERGE IX2105 : UNIVERGE IXシリーズ | NEC

IX2105を選んだ経緯ですが、(自分はネットワークエンジニアではないのですが)お仕事でYAMAHA RTX830を触る機会があり、設定だったりネットワーク周りの情報を集めていたところ、価格ドットコムの口コミに親切かつ強そうルーター玄人が生息していることを発見。

その玄人様の書き込みによると、YAMAHAよりNECの方が性能が期待でき、CUICISCOに近いということで?メルカリで中古をゲットしました。 (MAP-Eが使えれば良いので、適当な日本向けWiFiルーターを買えばよかったが、Amplifiを導入した手前WiFiがついてるルーターを買うと負けな気がした)

見た目と浪漫でWiFiを選定したため、余計な予算と時間を使ってしまいましたが、WiFiとしてのAmplifiは非常に安定していて満足していますし、IPv4 over IPv6あたりの知識を勉強できたのは結果的によかったし、ネットワークも安定したのでよかったなと。 (実家は、ひかり電話だったため、HWでMAP-E対応していたので、安定していたんだなぁ)

RubyでJSONをPOSTする方法

Net::HTTP.postを使う

なぜか、日本語のリファレンスの方には記載がないので、Net::HTTP#postを使う方法がよく紹介されている。 しかし、Net::HTTPインスタンス作ったり、SSL有効にしたりURIインスタンスを作って、host, port, pathをそれぞれパラメータに設定するのは面倒だ。

Net::HTTP.postならURIスキーマhttpsだったらSSLを有効にしてくれるし、URIインスタンスをそのまま渡してあげれば良いのでとてもシンプルだ。

require 'net/http'
require 'uri'

    response = Net::HTTP.post(
      URI('https://example.jp/path/to/endpoint'),
      { key: 'value' }.to_json,
      'Content-Type' => 'application/json'
    )

class Net::HTTP - Documentation for Ruby 2.7.0

terraformでElastiCache Redis Cluster modeをたてる

terrafromでredisを立てる場合、aws_elasticache_clusterを使う方法とaws_elasticache_replication_groupを使う方法がある。

aws_elasticache_clusterの場合ひとつのノード(cluster mode disabled)しか立てられない 。

レプリカを使う場合やCluster modeを使う場合は、aws_elasticache_replication_groupを使うことになる。

cluster_modeブロックの定義とパラメータグループのcluster-mode-enabledを設定することで、Cluster modeのRedisが立ち上がる。

最初パラメータグループの設定に気づかなかったので、かなり時間を溶かしてしまったよね、、

resource "aws_elasticache_replication_group" "main" {
  replication_group_id          = "${var.sysname}-${var.env}"
  replication_group_description = "redis cluster for ${var.sysname} ${var.env}"
  engine_version                = "5.0.6"
  node_type                     = var.node_type
  port                          = 6379
  parameter_group_name          = aws_elasticache_parameter_group.main.id
  subnet_group_name             = aws_elasticache_subnet_group.main.id
  security_group_ids            = [aws_security_group.elasticache.id]
  maintenance_window            = "mon:21:00-mon:22:00"
  snapshot_window               = "20:00-21:00"         
  snapshot_retention_limit      = var.snapshot_retention_limit

  automatic_failover_enabled = true
  auto_minor_version_upgrade = true

  at_rest_encryption_enabled = true
  kms_key_id                 = aws_kms_key.main.arn

  transit_encryption_enabled = false

  apply_immediately = true

  // ここ
  cluster_mode {
    replicas_per_node_group = var.num_cache_replicas
    num_node_groups         = var.num_cache_nodes
  }

  tags = {
    Name    = "${var.sysname}-${var.env}-redis-cluster"
    SysName = var.sysname
    Env     = var.env
  }
}

resource "aws_elasticache_parameter_group" "main" {
  name   = "${var.sysname}-${var.env}-redis-cluster-on"
  family = "redis5.0"

  // ここ
  parameter {
    name  = "cluster-enabled"
    value = "yes"
  }
}

参考

Resource: aws_elasticache_replication_group - terraform Resource: aws_elasticache_cluster - terraform

dockerでscratchイメージを使う

scratch imageとは

dockerが用意した最小イメージです。 shやlsすら入っていないので、goやrustのようなシングルバイナリを生成できる言語で超軽量なコンテナを作りたい際にうってつけです。 しかし、普段各言語公式のイメージなどに慣れていると、意識せずに使っていたファイルが存在せずにうまく動かないこともあります。

証明書を入れる

httpsを使うならTSLのためにCA証明書を入れておく必要があります。 自前で用意せずに、メンテされてそうなイメージから引っ張ってくるのがおすすめです。 Goの場合、公式alpineベースのイメージに含まれているので、これから引っ張ってきました。

FROM scratch as api

COPY --from=builder /go/bin/api /go/bin/api
COPY --from=golang:1.14-alpine3.11 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

ENTRYPOINT ["/go/bin/api"]

ローカルでawsと連携させたい場合

普段alpineを使っている際は、ローカルのcredentialをdocker内にマウントしている。

version: "3.7"
services:
  api:
    build:
      context: .
      target: api
    ports:
      - 80:80
    volumes:
      - $HOME/.aws/credentials:/.aws/credentials

イメージ内に、root以外のユーザーが存在せず/rootディレクトリがない場合は、ルートディレクト/へマウントすることになるので注意 

参考

Dockerのscratchイメージを探検する

ScratchイメージでGolangアプリの超軽量イメージをビルド

The Linux Information Project - The /root Directory