Docker道場オンライン #1 に行ってきた #dockerdojo

Docker道場オンライン #1 に参加しました。今回はオンライン開催。簡単に所感をまとめます。

dockerdojo.connpass.com

所感

Docker は、社内でちょっとした開発ツールを試すときに触ってみた程度です。きちんと基本から理解しておきたいところ。今回は Docker のコンセプトや基本的な概念の話でした。特にイメージレイヤの話は参考になりました。

Play with Docker は初めて知りました。便利そう。Docker Desktop でプロキシに悩まされたあの頃はなんだったのか...。

第2回があったら参加したいなー。

YouTube はこちら。

youtu.be

以下、メモから抜粋。

www.slideshare.net

  • 仮想サーバーをコンテナで代替するものではない
  • Build, Share (Ship), Run
  • Play with Docker
  • Linux のコンテナ技術を簡単にアプリを移動したり共有したりしたい ⇒ Docker
  • すべての依存関係をパッケージ化してコンテナ化して動かす
  • 一般的なプロセス実行
    • OS がユーザー空間にプロセスを起動する
  • コンテナでは特別な状態でプロセスを起動する
  • cgroup でリソースを制限する
    • CPU, メモリ, I/O, ...
  • Docker エンジン (dockerd デーモン)
    • Docker クライアントのコマンドを受け付ける
    • Docker イメージを使ってコンテナのプロセスを起動する
  • Docker イメージ
  • イメージレイヤ☆
    • ファイルシステム/アプリケーションとメタ情報が含まれる
      • 設定ファイル, コマンド, プログラム, ...
    • 親子関係を持つ
    • 親子関係のイメージレイヤをまとめてタグを付けられる
    • 他のイメージレイヤと共有できる (GitHub の fork みたいなもの)
  • イメージレイヤは削除できない
    • 部分的に差し替える場合は派生イメージとして別に作られる
  • ベースイメージ = OSレイヤ?
  • Dockerfile
    • Docker イメージを作成するための設計図
    • FROM, ADD, ENTRYPOINT, CMD, ...
    • Docker は docker commit でイメージレイヤ群を自動構築する
  • カーネルに依存するプログラムでは Docker は向かない
  • Docker コンテナ
    • イメージレイヤは読み込み専用
    • コンテナ実行時に読み書き可能なイメージレイヤを追加する☆
    • Copy on Write
  • docker inspect
    • Docker コンテナの情報を表示する
  • docker history
    • イメージレイヤの情報を表示する?
  • Docker Compose
    • 複数のコンテナをまとめて管理する
    • コンテナ, ネットワーク, ボリューム, ...
  • Docker ボリューム
    • 永続領域の管理
    • ホスト上の領域を参照可
  • ドキュメント

Records の Compact Constructors の中ではフィールドを初期化する処理は書けない

Java の Records に Compact Constructors と呼ばれる機能があります。

record Foo(int x) {
    Foo {
        x = 100;
    }
}

Compact Constructors の中ではフィールドを初期化する処理は書けません。コンパイルエラーになります。

record Foo(int x) {
    Foo {
        this.x = 100; // エラー: final変数xに値を代入することはできません
    }
}

ふつうのコンストラクタの場合は問題なし。

record Foo(int x) {
    Foo(int x) {
        this.x = 100; // OK
    }
}

なんであえてコンパイルエラーになるようにしたんだろうか...?

そのあたりの理由というか経緯は見つけられませんでしたが、とりあえず最初の Compact Constructors 版を javap してみました。

> java --version
openjdk 15 2020-09-15
OpenJDK Runtime Environment (build 15+36-1562)
OpenJDK 64-Bit Server VM (build 15+36-1562, mixed mode, sharing)

> javac --enable-preview --release 15 Foo.java

> javap -c Foo.class
Compiled from "Foo.java"
final class Foo extends java.lang.Record {
  Foo(int);
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Record."<init>":()V
       4: bipush        100
       6: istore_1
       7: aload_0
       8: iload_1
       9: putfield      #7                  // Field x:I
      12: return

  public final java.lang.String toString();
    Code:
       0: aload_0
       1: invokedynamic #13,  0             // InvokeDynamic #0:toString:(LFoo;)Ljava/lang/String;
       6: areturn

  public final int hashCode();
    Code:
       0: aload_0
       1: invokedynamic #17,  0             // InvokeDynamic #0:hashCode:(LFoo;)I
       6: ireturn

  public final boolean equals(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: invokedynamic #21,  0             // InvokeDynamic #0:equals:(LFoo;Ljava/lang/Object;)Z
       7: ireturn

  public int x();
    Code:
       0: aload_0
       1: getfield      #7                  // Field x:I
       4: ireturn
}

どうやらコンストラクタのローカル変数に代入して、そのあとにインスタンスフィールドを初期化してるっぽいです。おそらく、Compact Constructors に書いた処理はインスタンスフィールドの初期化の前に差し込まれるのではないかと思います。(想像で書いてるので正確ではないと思います)

最初の Compact Constructors 版の record は次のようなクラスになっていると思われます。

class Foo extends Record {
    private final int x;
    public Foo(int x) {
        x = 100;
        this.x = x;
    }
    // ... (略)
}

ちなみにふつうのコンストラクタ版を javap するとこういう感じ。

> javap -c Foo.class
Compiled from "Foo.java"
final class Foo extends java.lang.Record {
  Foo(int);
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Record."<init>":()V
       4: aload_0
       5: bipush        100
       7: putfield      #7                  // Field x:I
      10: return

  ... ()

参考

追記

ここにいろいろ書いてありました。(原文)

blogs.oracle.com

コンパクト・コンストラクタを宣言する目的は、カノニカル・コンストラクタの本体で必要となる、検証や正規化のみを行うコードを提供することにあります。その他の初期化コードはコンパイラが提供します。

あと、このあたりにもいろいろ書いてあるっぽい。ちゃんと読んでないですが...。

8.10.4 Record Constructor Declarations - Records - Oracle Help Center

JJUGナイトセミナー「Java 15 リリース記念イベント」に行ってきた #jjug

JJUGナイトセミナー「Java 15 リリース記念イベント」に参加しました。今回はオンライン開催。簡単に所感をまとめます。

jjug.doorkeeper.jp

所感

チャットにも書かれてましたが、リリースサイクルが変わってから少しずつ機能が追加されていくのでキャッチアップしやすくていいですね。

Sealed Classes の最終目標は「使えるパターンマッチング」とのことで、機能をうまく分割して導入しているようです。なるほど。将来、どういう機能を実現したいのかを意識しておくのは大事かも。

あと、Biased Locking とか Hidden Classes は初めて聞きました。Hidden Classes は新しい機能なのでちょっと調べてみるか。

YouTube はこちら。

youtu.be

以下、メモから抜粋。

Welcome, Java 15!

  • Azul では 13/15 が MTS
  • Java 15 の JEP は 14個
  • Nashorn ⇒ GraalJS への移行を推奨
  • Biased Locking
    • デフォルト無効化
    • デフォルトのロック実装
    • アトミックな CAS 命令が高コストではなくなった
  • Hidden Classes
  • UDP socket API を Fiber 対応
  • ZGC
  • Text Blocks
  • Shenandoah
  • (Preview) Pattern Matching for instanceof
    • 型テストパターン (type-test pattern)
    • 型が一致するときは変数にバインドされる
  • (Preview) Records
    • フィールドの名前がそのまま getter になる (フィールド変数の命名に注意)
    • immutable
    • インタフェース実装可
    • extends 不可
    • フィールドは final (リフレクション利用不可)
  • (Preview) Sealed Classes
    • 実装/継承先を同一コンパイル単位内のクラスのみに制限する?
    • パターンマッチングと組み合わせて使う
    • sealed で宣言
    • permits で拡張を許可するサブクラスを列挙する
    • 拡張許可されたサブクラスの制約☆
  • Foreign-Memory Access API
    • よくわからず...
  • Parallel/G1 GC
    • -XX:MaxRAM=16g のみ, ヒープサイズ指定なしの場合?
    • Parallel GCスループット重視
    • G1 はスループット&レイテンシ重視
    • Java 15 ではヒープのリージョンサイズ指定を変更

Recordsを中心にした新機能の紹介と今後の展望

  • Records (2nd Preview)
  • 名前付きタプル
  • record はキーワードではない
    • 型には使えないけど変数名には使える
  • Record の要素はコンポーネントと呼ぶ
  • 中括弧は省略不可
  • Canonical Constructor
  • Compact Constructor
  • コンパクトコンストラク
    • コンストラクタのパラメータは省略可
    • フィールドは初期化してはいけない
  • Pattern Matching for instanceof (2nd Preview)
    • Kotlin のスマートキャストみたいな機能
  • Sealed Classes (Preview)
  • 継承できるクラスを限定する
  • 現状では使い道なし?
    • 後発の機能と組み合わせて使う?
    • Pattern Matching for switch とか
  • sealed, final, non-sealed
    • non-sealed を付けるとそれ以下の階層は継承可
  • Sealed Classes の今後の計画☆
  • Pattern Matching for switch
    • Sealed Classes と組み合わせると default なしで書けるようになる
  • Deconstruction
    • パターンマッチングで構造を分解する
    • Optional をパターンマッチングしたい☆
    • Optional を interface にする必要がある
      • ※リフレクションで非互換性が出る
    • Some, None が Optional を実装する
      • Sealed Classes がないため final class になっている
  • 最終目標は使えるパターンマッチング☆

Vue.js でウィジェットっぽいもの (TypeScript)

以前、Vue.js の学習を兼ねてウィジェットっぽいもの作りました。

Vue.js でウィジェットっぽいものを作ってみる (仮) - kntmr-blog

Vue.js でウィジェットっぽいもの (仮) その2 - kntmr-blog

続編として今回はこれを TypeScript に移植しました。とは言ってもそんなに大したことはやってなくて TypeScript のお作法的にも怪しいかも...。

github.com


以下、備忘録。

前回は学習を兼ねてたので Vuex とか Vue Router を使ってましたが、今回はもっとシンプルに。あと、Vue.js はとりあえず 2.x 系にしています。後々、3.x に移行したい。

> vue create vue-widget-sample-ts

Vue CLI v4.5.6
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS
? Choose a version of Vue.js that you want to start the project with 2.x
? Use class-style component syntax? No
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No

axios だけインストール。

> yarn add axios

vue.config.js

Configuration Reference - Vue CLI

Webpack の設定などはここに書く。

コンポーネント

基本的に Vue.js + JS 版を Vue.extend でラップしてるだけであまり変わってないです。

これからやりたいこと

もう少し TypeScript や Vue 3.x の学習を兼ねるようなサンプルにしたい。

Engineers in VOYAGE #voyagebook

先月、Engineers in VOYAGE を読みました。VOYAGE GROUP のエンジニアのインタビューをまとめた本です。

Engineers in VOYAGE ― 事業をエンジニアリングする技術者たちwww.lambdanote.com

内容が生々しいという噂が気になって読んでみました。確かに生々しかったです。

大小さまざまな問題があって、個人としてチームとして組織としてそれらにどう向き合うか、ビジネスやプロダクトの方向性をどうするのか、いろいろな迷いや葛藤の中で日々戦っているエンジニアの話です。

なんだか読んでて勇気が出ました。みんなすごい頑張ってるんだなぁって。

「はじめに」に書いてある通り、読むひとがそれぞれの立場で共感できる本です。どこかに刺さるキーワードや一文があると思います。個人的には5章の旧システムの話があるあるでグッと来ました。その他、興味深った一文を抜粋します。

  • 同じ目的を共有するチーム間で「依頼」が発生するのは本意ではない
  • 最初はよかれと思って導入したものがアンチパターンになる
  • 重要なのは切り戻しできるかどうか
  • 葬りで問題の分母を減らす
  • 「事業葬り」「機能葬り」「コード葬り」
  • 部屋のドアノブを回すと風呂の底が抜ける
  • データベース設計の意図を辿れるようにする
  • 実装から距離をとってテストを書くことで独立性を保つ
  • 自分たちの予測モデルの存在が将来の予測を陳腐化させる

閉方テーブル (Closure Table)

閉方テーブル (Closure Table) は RDB で階層構造を表現する際に使われるデータモデルです。数年前にとある案件で使ったのですが、内容を忘れかけてるので復習します。備忘録。

閉方テーブルでは直接の親子関係だけでなく、階層全体の関係を持つ。閉方テーブルを利用すると階層構造をシンプルに表現できる。特にクエリがシンプルになるのが利点。ただし、階層全体の関係を持つため、階層が深くなるほどデータサイズは大きくなる。

f:id:knt_mr:20200810160928p:plain

ルートアクセス

ルート直下 (最上位階層) のフォルダを取得する場合、祖先フォルダIDにルートのIDを指定して、深さ 1 で検索する。ルートは特別な扱いになるため、IDには何かしらの固定値を用いる。

SELECT * FROM FolderPath as fp
JOIN Folder as f ON fp.祖先フォルダID = f.id
WHERE fp.祖先フォルダID = {ルート} AND fp.深さ = 1

f:id:knt_mr:20200814014507p:plain

サブフォルダアクセス

ルートアクセスと同様。祖先フォルダIDにカレントのフォルダIDを指定して、深さ 1 で検索する。

-- フォルダAを基点にする場合
SELECT * FROM FolderPath as fp
JOIN Folder as f ON fp.祖先フォルダID = f.id
WHERE fp.祖先フォルダID = {フォルダA} AND fp.深さ = 1

f:id:knt_mr:20200814014946p:plain

パンくずリスト

カレントフォルダまでのパス。子孫フォルダIDにカレントのフォルダIDを指定して検索する。深さを降順で並べ替えるとパンくずリストになる。

-- フォルダCを基点にする場合
SELECT f.* FROM FolderPath as fp
JOIN Folder as f ON fp.祖先フォルダID = f.id
WHERE fp.子孫フォルダID = {フォルダC}
ORDER BY fp.深さ DESC

f:id:knt_mr:20200814015643p:plain

フォルダ削除

閉方テーブルでは階層全体の関係を持つ。フォルダ削除では、子孫フォルダIDに対象のフォルダIDを持つすべての階層データを削除する。

-- フォルダDを削除する場合
DELETE FROM FolderPath as fp
WHERE fp.子孫フォルダID = {フォルダD}

f:id:knt_mr:20200814020724p:plain

フォルダ追加

閉方テーブルでは階層全体の関係を持つ。フォルダ追加では、子孫フォルダIDに対象のフォルダIDを持つすべての階層データを作成する。対象のフォルダ自身を深さ 0 として、親フォルダのパンくずリストでルートまで辿りながら深さを +1 する。以下はフォルダE配下にフォルダXを追加する場合。

f:id:knt_mr:20200814021102p:plain

Remote.vue #2 に行ってきた #remote_vue

先日、Remote.vue #2 に参加しました。オンライン開催。簡単に所感をまとめます。

lapras.connpass.com

所感

ユーザーに提供する知識、情報、振る舞いは、いわゆる情報設計?というものかと思いますが、これをコンポーネント分割の観点にするというのは目から鱗でした。なるほど。

Composition API はあまり理解できてないのですが、Ref と Reactive の違いや reactive のハマりどころが知れてよかったです。その他のリアクティブ関係の関数がスライドの最後の方に記載されていましたが、なかなかおもしろそう。特に readonly とか customRef とか markRaw とか。

YouTube の URL はこちら。

https://youtu.be/hUcQXgUxQVcyoutu.be

以下、メモから抜粋。

SFCで挑戦するFunctional Component

  • Functional Component
  • Functional Component であることを明示してパフォーマンス向上☆
    • ライフサイクルメソッドがないから☆
    • <template functional> or functional: true
      • Vue 3 からはこの書き方はサポートされない?
      • ⇒ h関数 or JSX
  • props がない
    • this (コンテキスト) がない (props キーワードでアクセス)
  • methods は $options にある
  • その他、通常コンポーネントと振る舞いが違うところがある☆
  • 状態を持つコンポーネントをたくさんレンダリングすることはあるか?
    • リストなど, ...

Fat Component にならないためのフロントエンド + オブジェクト指向 on Vue.js

Ref vs Reactive 〜Vue Composition API リアクティブ関数の探究〜

  • Composition API
  • 責務ごとにデータとロジックをまとめて書ける
  • ref
    • プリミティブな値を ref オブジェクトでラップしてリアクティブに
  • reactive
    • プリミティブでない値を Proxy オブジェクトでラップしてリアクティブに
    • プリミティブな値を渡すとエラー
    • Proxy は IE11 ではサポート外
  • ref と reactive を使い分ける☆
    • プリミティブ値は ref, オブジェクトは reactive
  • 可能な限り reactive を使う☆
    • Vue 2 系の data のような扱い
    • コンポーネントごとに単一の state として持たせたり
  • ref は内部で reactive を呼ぶ
    • プリミティブでない値は reactive が呼ばれる
  • template Ref
  • computed の戻り値は readonly な ref
  • reactive の消失☆
    • 外部ファイルで reactive なオブジェクトを返す
    • 使う側で返り値を分割代入するとただのプリミティブな値になる
      • ⇒ toRefs 関数で第一階層だけ ref にラップしてくれる
    • props を分割代入するときも注意
    • reactive な値を渡すときも注意 ⇒ toRef を使う
  • その他、リアクティブ関係の関数☆
  • オブジェクトにして reactive に寄せる
    • ⇒ あとでプロパティが増えたときに吸収しやすそう☆