kakakakakku blog

Weekly Tech Blog: Keep on Learning!

git checkout の代替としてリリースされた git switch と git restore

2019年8月にリリースされた Git 2.23 から,Experimental(実験的機能)として新コマンド git switchgit restore が使える.今までずっと使ってきた git checkout は機能が多すぎたため,機能を分割し git checkout の代替としてリリースされた.個人的にリリースされてから,できる限り git switchgit restore を使うようにしてるけど,まだ無意識に git checkout を使ってしまうこともある.最近 git switch を教える機会があったため,ブログにまとめておく.

github.blog

なお,以下の検証は Git 2.26.0 を使った.

$ git --version
git version 2.26.0

1. git switch を使う

git switch を使って「ブランチ操作」を行なう.ドキュメントを網羅的に紹介するのではなく,よく使う操作を中心に git checkout などと比較しながら紹介する.詳細はドキュメントを参照してもらればと.

git-scm.com

ブランチを作る

git switch -c でブランチを作れる.今までは git checkout -b を使っていた.

$ git checkout -b my-git-checkout

$ git switch -c my-git-switch

ブランチを切り替える

git switch という名前の通り,ブランチ名を指定すると切り替えられる.

$ git checkout master

$ git switch master

1個前のブランチに切り替える

Linux の cd - と同じく,- を使って git switch - とすると,1個前のブランチに切り替えられる.

$ git checkout -

$ git switch -

リモートブランチを取得する

「ブランチを作る」と同じく git switch -c を使って,origin/xxx など,リモートブランチを指定する.

$ git fetch
$ git checkout -b my-github-branch origin/my-github-branch

$ git fetch
$ git switch -c my-github-branch origin/my-github-branch

"強制的に" ブランチを作る

個人的にあまり使う機会はなさそうだし,誤って使うと危険な気もするけど,git switch-C オプション(大文字)もしくは --force-create オプションを使うと,もし同じ名前のブランチが存在していても強制的に作り直す.-c-C は区別しにくそう...!

$ git switch -C my-git-switch

2. git restore を使う

git restore を使って「変更を戻す操作」を行なう.ドキュメントを網羅的に紹介するのではなく,よく使う操作を中心に git checkout などと比較しながら紹介する.詳細はドキュメントを参照してもらればと.

git-scm.com

Unstaging な変更を戻す(git add をする前)

今まで git checkout を使って変更を戻していたけど,git restore で戻せる.とは言え,個人的に1番無意識に使ってしまうのが git checkout . で,今もまだ git restore . には慣れていない.

$ git checkout README.md
$ git checkout .

$ git restore README.md
$ git restore .

実際に git status を使うと,git restore を使うリファレンスも出る.

$ git status

(中略)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   README.md

Staging な変更を戻す(git add をした後)

git add で Staging にした変更を戻す場合,今までは git reset を使っていたけど,git restore --staged を使う.

$ git reset README.md

$ git restore --staged README.md

実際に git add をした後に git status を使うと,git restore --staged を使うリファレンスも出る.

$ git status

(中略)

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   README.md

指定した Commit に戻す

指定した Commit に戻す場合は git restore -s を使う.ただし,git checkoutStaging な状態に戻り,git restore -sUnstaging な状態に戻るため,単純比較ではなく,注意すること.

$ git checkout ${HASH} .
$ git checkout master~2 .

$ git restore -s ${HASH} .
$ git restore -s master~2 .

まとめ

Git 2.23 から,Experimental(実験的機能)として使えるようになった新コマンド git switchgit restore の中でよく使う操作を中心に紹介した.プログラミング講師の仕事をしていたときに git checkout の説明に苦労した経験もあり,今後は Git 初学者は git switchgit restore から学べば良さそう.

Kubernetes の CronJob に設定できる concurrencyPolicy と suspend を試した

Kubernetes の CronJob を使って Job を定期的に実行するときに,マニフェストに設定できるフィールド concurrencyPolicysuspend を試す機会があった.振り返りながら整理しておく.

kubernetes.io

Concurrency Policy とは?

CronJob では,例えば「ジョブの実行時間が長時間化した(突き抜けた)場合」のために「同時実行ポリシー (Concurrency Policy)」を設定できる.具体的なフィールドは concurrencyPolicy となり,以下の3種類から選べる.デフォルトは Allow となり,同時実行を許容する.

  • Allow : 同時実行を許容する
  • Forbid : 同時実行を許容せず,実行中のジョブがあれば,新規ジョブをスキップする
  • Replace : 同時実行を許容せず,実行中のジョブがあれば,新規ジョブに置き換える

concurrencyPolicy のイメージを図解してみた.青は Running で,赤は Terminating などを意味する.

f:id:kakku22:20200406113227p:plain

concurrencyPolicy 検証 : Allow

Kubernetes のドキュメントを参考に簡単なマニフェストを作成した.Cron 表記は「1分間隔」とし,単純に「300秒スリープする」 Job にした.そして,今回検証する concurrencyPolicyAllow にした(デフォルト設定).

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: kakakakakku
spec:
  schedule: "*/1 * * * *"
  concurrencyPolicy: Allow
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: sleep
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; sleep "300"; date
          restartPolicy: OnFailure

マニフェストを適用し,少し待ってから Pod を確認すると,同時実行になっていた.

$ kubectl apply -f cronjob.yaml
cronjob.batch/kakakakakku created

$ kubectl get pods
NAME                           READY   STATUS              RESTARTS   AGE
kakakakakku-1585740960-kvq28   0/1     Completed           0          6m6s
kakakakakku-1585741020-fmjl7   0/1     Completed           0          5m6s
kakakakakku-1585741080-x88r2   1/1     Running             0          4m6s
kakakakakku-1585741140-f7sbh   1/1     Running             0          3m6s
kakakakakku-1585741200-jpxnj   1/1     Running             0          2m5s
kakakakakku-1585741260-6lbc7   1/1     Running             0          65s
kakakakakku-1585741320-s54b2   0/1     ContainerCreating   0          5s

concurrencyPolicy 検証 : Forbid

次は concurrencyPolicyForbid にしてマニフェストを適用する.

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: kakakakakku
spec:
  schedule: "*/1 * * * *"
  concurrencyPolicy: Forbid

(中略)

Forbid は同時実行を許容せず,実行中のジョブがあれば,新規ジョブをスキップする.Running になっている kakakakakku-1585741620-spbnkCompleted になってから,新しく kakakakakku-1585741920-phjzsRunning になっている.

$ kubectl get pods
NAME                           READY   STATUS    RESTARTS   AGE
kakakakakku-1585741620-spbnk   1/1     Running   0          4m50s

$ kubectl get pods
NAME                           READY   STATUS      RESTARTS   AGE
kakakakakku-1585741620-spbnk   0/1     Completed   0          5m20s
kakakakakku-1585741920-phjzs   1/1     Running     0          10s

concurrencyPolicy 検証 : Replace

最後は concurrencyPolicyReplace にしてマニフェストを適用する.

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: kakakakakku
spec:
  schedule: "*/1 * * * *"
  concurrencyPolicy: Replace

(中略)

Replace は同時実行を許容せず,実行中のジョブがあれば,新規ジョブに置き換える.実行中だった kakakakakku-1585743600-ftmb8Terminating になり,新しく kakakakakku-1585743660-4gb5vRunning になっている.

$ kubectl get pods
NAME                           READY   STATUS        RESTARTS   AGE
kakakakakku-1585743600-ftmb8   1/1     Terminating   0          70s
kakakakakku-1585743660-4gb5v   1/1     Running       0          10s

Suspend とは?

CronJob では,例えば「メンテナンス時に実行を止める」など,「一時停止 (Suspend)」を設定できる.具体的なフィールドは suspend となり,truefalse を設定できる(デフォルトは false).

suspend 検証

同じマニフェスト(concurrencyPolicyForbid にしておく)に suspend: false を設定し,マニフェストを適用する.

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: kakakakakku
spec:
  schedule: "*/1 * * * *"
  concurrencyPolicy: Forbid
  suspend: false

(中略)

一時停止を有効化する場合,マニフェストを suspend: true に更新することもできるけど,今回は kubectl patch コマンドを使って一時的に suspend: true に変更する.その後に CronJobPod を確認すると,SUSPEND: True になり,新しく Pod はスケジューリングされなくなった.

$ kubectl patch cronjob kakakakakku -p '{ "spec": { "suspend": true } }'
cronjob.batch/kakakakakku patched

$ kubectl get cronjob,pods
NAME                        SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cronjob.batch/kakakakakku   */1 * * * *   True      0        7m14s           13m

NAME                               READY   STATUS      RESTARTS   AGE
pod/kakakakakku-1585746240-296mt   0/1     Completed   0          12m
pod/kakakakakku-1585746540-8spgm   0/1     Completed   0          7m

一時停止を無効化する(戻す)ために,同じく kubectl patch コマンドを使う.

$ kubectl patch cronjob kakakakakku -p '{ "spec": { "suspend": false } }'
cronjob.batch/kakakakakku patched

なお,kubectl patch コマンドを使った方法は「Kubernetes 完全ガイド」の第5章にも載っている.

Kubernetes完全ガイド (impress top gear)

Kubernetes完全ガイド (impress top gear)

  • 作者:青山 真也
  • 発売日: 2018/09/21
  • メディア: 単行本(ソフトカバー)

まとめ

Kubernetes の CronJob に設定できるフィールド concurrencyPolicysuspend を試す機会があり,検証結果を整理した.Kubernetes 関連の記事は今まであまり書いてなく,今後はどんどん書いていく.

役割を超えて顧客から始めよう /「みんなでアジャイル」を読んだ

2020年3月に出版された「みんなでアジャイル」を読んだ.本書はアジャイルを「ムーブメント」と位置付けて,アジャイルの魅力を紐解く内容になっている.具体的なアジャイルフレームワークに特化せず,顧客中心主義やコラボレーションなど,アジャイルなスタイルに興味があれば読者層に入るため,エンジニアに限らず,営業やマーケティングや人事など,あらゆる立場でも読める.なお,1章に書いてある通り,アジャイルな「マインドセット」は重要だけど,思考だけではなく,あえて「ムーブメント」という言葉を選ばれているのも特徴的に感じた.

なお,本書は著者の吉羽さん (@ryuzee) から献本をしていただいた.ありがとうございます!!!

みんなでアジャイル ―変化に対応できる顧客中心組織のつくりかた

みんなでアジャイル ―変化に対応できる顧客中心組織のつくりかた

  • 作者:Matt LeMay
  • 発売日: 2020/03/19
  • メディア: 単行本(ソフトカバー)

まえがき と 謝辞

まず,本書は及川さん (@takoratta) の「まえがき」からはじまる.「実はアジャイル推進論者ではない」という立場から語られる本書の魅力は,否定的な論調からのコントラストがあり,読んでいて惹き込まれた.さらに原著者の「謝辞」も1章の前にある.原著者自身が今までチームに指摘してきたことを自分自身もやってしまっていることに気付いたという驚きが書かれている.だからこそ,原著者にとっても執筆プロセス自体が「アジャイルの旅」だったという文章も重く感じられた.読み飛ばしがちな部分だけど,本書の魅力は「まえがき」「謝辞」からはじまっていることを伝えたい.

目次

本書は「アジャイルムーブメント」「原則(なぜ)」「プラクティス(どうやって)」「現実の成果(何を)」を軸に紐解いていく.特に 3章 から 6章 は「組織重力の法則」と呼ばれるアンチパターンの解説があり,原則やプラクティスを理解した上で,どう現実の成果を見極めていくか?という部分にフォーカスされている.とは言え,アジャイル関連の書籍はどれを読んでも抽象度が高くなる.何かしら自分に関係するチームを想像しながら読み進めるのが良いと思う.

  • 1章 : 「アジャイル」とは何か?なぜ重要なのか?
  • 2章 : 自分たちの北極星を見つける
  • 3章 : 顧客から始めるのがアジャイル
  • 4章 : 早期から頻繁にコラボレーションするのがアジャイル
  • 5章 : 不確実性を計画するのがアジャイル
  • 6章 : 3つの原則に従い、速くて柔軟で顧客第一なのがアジャイル
  • 7章 : あなたのアジャイルプレイブック

組織重力の第1法則

3章に載っている「組織重力の第1法則」「組織の個人は日々の責任やインセンティブと整合性がなければ,顧客と向き合う仕事を避ける」という法則だった.個人的にも顧客中心主義は理解しているけど,気を抜くと顧客目線から飛んだ意思決定をしていることに気付くという体験もあり,改めて顧客目線で考え続けることの大切さを感じられる内容だった.ソフトウェア開発に限らず,どんな仕事にも顧客はいるため,必要に応じて読み替えながら考えると良さそう.

そして,3章では「アジャイルソフトウェア開発宣言」で提唱された「包括的なドキュメントよりも動くソフトウェアを」という内容の具体例が載っている.「ソフトウェアプロダクト」に限らず「マーケティングキャンペーン」「書籍」「家の設計」などがあり,最後に「プレゼンテーション」が載っている.「包括的なドキュメント」「文字による概要」「動くソフトウェア」「ラフなスライド」とある.

agilemanifesto.org

僕自身,技術講師という仕事柄,日々スライドを作り,プレゼンテーションをしているため,とても刺さった.例えば,同僚に対するプレゼンテーションを作るときの MVP (Minimum Viable Product) はアウトライン(箇条書き)ではなく,ラフなスライドになる.実際にスライドを作って,練習をしたり,ドライランをすれば繰り返し学習できる.目的とズレたプレゼンテーションになるリスクも抑えられる.実体験からも「確かに!」と言える内容だった.「動くソフトウェア」「プレゼンテーション」で例えた内容は気付きになった.

組織重力の第2法則

4章に載っている「組織重力の第2法則」「組織における個人は,自分のチームやサイロの心地良さの中で1番簡単な作業を優先する」という法則で,読みながら「それな!」と叫んでしまったし,付箋にも大きく「それな!」と書いてしまった(笑)それほど実体験もある内容だった.ようするに,他のチームにフィードバックをもらえば,より良くなることは理解しているし,もしかしたら根本からひっくり返される可能性もある.だからこそ「自分のチームやサイロの外に出るのは危険性が高い」という判断をしてしまう.また「重力」という言葉も的を得ているように感じた.

そして,4章では「報告と批評の文化から協調的な文化」という内容に進んでいく.有名な Spotify モデルの紹介もあれば,アジャイルゾーン(オープンな場)で意思決定をする Tips も載っている(以下に箇条書きにして載せた).そのために「コラボレーション(つながり)」を大切にし,現実を見極めていく.そのために本書では必ず「良い方向に進んでいる兆候」「悪い方向に進んでいる兆候」が載っている.

  • 何を決めるかを決める
  • タイムボックスの練習をする
  • 期待を明確にする
  • 会議と呼ばない
  • 「同じ場所にいる」ことと「同期して行う」ことを区別する

WHPI (Why / How / Prototype / Iterate)

6章に載っている「アジャイルプラクティスの探求」の中で WHPI (Why / How / Prototype / Iterate) と呼ばれるプラクティスが紹介されていた.フーピーと発音する.顧客のニーズを明確に理解して進められているか?を問うフレームワークと表現することができる.今までアジャイル関連の書籍を多く読んでいると思うけど,WHPI ははじめて聞いた.本書にも書いてある通り,ソフトウェアに限らず適用できる.また Why の部分も変わる可能性があるため,全てのプロセスを Iterate するという注意事項なども書いてある.

  • Why(なぜ)
  • How(どうやって)
  • Prototype(プロトタイプ)
  • Iterate(繰り返す)

まとめ

本書は「アジャイルムーブメント」を通して「価値を顧客に届けられる組織になること」をうまく言語化している.さらにエンジニアに限らず,営業やマーケティングや人事など,あらゆる立場でも読める内容になっている点は,今まで読んできたアジャイル関連の書籍と違う.とは言え,エンジニア目線だと関連書籍も多くあるため,合わせて読むと良さそう.例えば「レガシーコードからの脱却」「Effective DevOps」「Fearless Change」「アジャイルコーチング」など.あと,最後の謝辞に親友の @ykmc09 の名前が載っていて,嬉しくなった!

みんなでアジャイル ―変化に対応できる顧客中心組織のつくりかた

みんなでアジャイル ―変化に対応できる顧客中心組織のつくりかた

  • 作者:Matt LeMay
  • 発売日: 2020/03/19
  • メディア: 単行本(ソフトカバー)

誤植

全くなかったと思う.O'Reilly のサイトにも正誤表は出ていなかった.今まで吉羽さん (@ryuzee) の本を多く読んでいるけど,どれも読みやすく,誤植もなく,出版のクオリティに驚くばかり.

www.oreilly.co.jp

非常に細かいけど,2点気になった点を残しておく.

  • P.xxiv : 現実の成果現実での成果 は細かいけど表記揺れのように感じた
  • P.157 : Your Agile Playbook Template に載っている 喫緊 は一瞬読めなかった(意図的に 緊急 と翻訳しなかったんだとは思うけど)

docs.google.com

Next.js の Static HTML Export 機能などを学べる Next.js Learn (Excel) を試した

2月頃に Next.js を学ぶために Next.js Learn (Basic) を試した.詳しくは以下の記事にまとめてある.

kakakakakku.hatenablog.com

今回はその続きと言える Next.js Learn (Excel) を試して学んだことをまとめる.Basic と比較すると,一歩踏み込んだレベルだと思う.だからこそ Next.js Learn (Basic) とセットで終わらせておくと学習効率が1番高そう.僕自身,Excel を試すまでに少し間を空けてしまったことを後悔している.

nextjs.org

Next.js Learn (Excel)

Excel では「計4種類」のコンテンツが用意されている.正確には,最近まで Lazy Loading 関連のコンテンツもあったけど,Outdated であるという理由から2月末に削除されていた.なお,削除されたプルリクエストを見ると「Next.js チュートリアルを作り直している」という記載もあり,楽しみだ!気になる!

  • Export into a Static HTML App
  • TypeScript
  • Lazy Loading Modules ⚠️ 2月末に削除された
  • Lazy Loading Components ⚠️ 2月末に削除された
  • Create AMP Pages
  • Automatic Static Optimization

github.com

環境

今回は Next.js 9.3.2 を使えるようにローカル環境を構築した.Next.js Learn (Basic) を試した前回は Next.js 9.2.1 だった.

$ npm view next version
9.3.2

1. Export into a Static HTML App

まず「Export into a Static HTML App」では,Next.js でウェブアプリケーションを静的コンテンツとしてエクスポートできる Static HTML Export 機能を学ぶ.Next.js を動かすために Node.js 環境を作る必要がなく,例えば nginx さえあれば動かせるようになる.当然ながら,良し悪しはあるため,機能として知っておくことに価値がありそう.

nextjs.org

今回も Next.js Learn (Basic) で使ったリポジトリ zeit/next-learn-demo を使って,サンプルアプリケーションを動かす.

github.com

$ cd E1-static-export
$ npm install
$ npm run dev

npm run dev を実行すると,前回と同じ Batman TV Shows の画面にアクセスできる.現時点では,まだ普通の Next.js アプリケーションとなり,SSR (Server-Side Rendering) も使っている.画面遷移をしたり,URL 直接アクセスをすると,挙動は調べられる.

f:id:kakku22:20200330152734p:plain

次に next.config.js を以下のように実装する.関数から返却している paths には,エクスポートするパス情報を含めている.今回の例で言うと //about/show/[id] で,/show/[id] は実際に TVmaze API を実行した結果から自動的にエクスポートされる.

const fetch = require('isomorphic-unfetch');

module.exports = {
  exportTrailingSlash: true,
  exportPathMap: async function() {
    const paths = {
      '/': { page: '/' },
      '/about': { page: '/about' }
    };
    const res = await fetch('https://api.tvmaze.com/search/shows?q=batman');
    const data = await res.json();
    const shows = data.map(entry => entry.show);

    shows.forEach(show => {
      paths[`/show/${show.id}`] = { page: '/show/[id]', query: { id: show.id } };
    });

    return paths;
  }
};

そのまま npm run export を実行すると out ディレクトリにエクスポートされる.今回は軽量な HTTP サーバとして serve を使って配信すると,今までと同じ Batman TV Shows の画面にアクセスできる.

$ npm install -g serve

$ npm run export
(中略)
[==  ] Exporting (1/14)Fetched show: Batman
Show data fetched. Count: 10
Fetched show: The Batman
[==  ] Exporting (4/14)Fetched show: Batman Beyond
Fetched show: The Adventures of Batman
Fetched show: Batman: The Animated Series
[  ==] Exporting (7/14)Fetched show: Batman Unlimited
Fetched show: Batman: The Brave and the Bold
Fetched show: The New Batman Adventures
[ ===] Exporting (12/14)Fetched show: Beware the Batman
Fetched show: Batman: Black and White
Exporting (14/14)

$ cd out
$ serve -p 8080

実際に out ディレクトリを確認すると,HTML や JavaScirpt など,たくさんエクスポートされている.特に out/show を見ると,id ごとに index.html がある.next.config.js に実装した通り,エクスポート時に自動的に index.html を作っていると確認できる.

$ tree out/show
out/show
├── 11464
│   └── index.html
├── 22309
│   └── index.html
├── 33618
│   └── index.html
├── 3557
│   └── index.html
├── 481
│   └── index.html
├── 504
│   └── index.html
├── 5951
│   └── index.html
├── 757
│   └── index.html
├── 900
│   └── index.html
└── 975
    └── index.html

10 directories, 10 files

2. TypeScript

Next.js は TypeScript をサポートしている.特に Next.js 9 から,より便利に使えるようになった.

nextjs.org

検証用に新規ディレクトリを作り,React と Next.js と TypeScript をインストールする.

$ npm init -y
$ npm install --save react react-dom next
$ npm install --save-dev typescript @types/react @types/node

さらに pages/index.tsx を以下のように実装する.

const Home = () => <h1>Hello world!</h1>;

export default Home;

現時点だと,以下のような構成になっている.

$ tree -L 1
.
├── node_modules
├── package-lock.json
├── package.json
└── pages

2 directories, 2 files

ここで npm run dev を実行し,ローカルサーバを起動すると,なんと tsconfig.json を自動的に作ってくれる!最終的にカスタマイズは必要だとしても,Next.js のオススメ設定をベースに実装を進められるのは特に初学者にとって良さそう.

$ npm run dev

(中略)

[ wait ]  starting the development server ...
[ info ]  waiting on http://localhost:3000 ...
We detected TypeScript in your project and created a tsconfig.json file for you.

Your tsconfig.json has been populated with default values.

自動的に tsconfig.json が作られたよね?という驚きを確認するクイズもある.前回の記事にも書いたけど,手順通りに進めるだけではなく,動作確認をしながらクイズに回答する体験は Next.js Learn の良いところだと思う.

f:id:kakku22:20200330153117p:plain

なお,自動的に作られる tsconfig.json は,デフォルトだと "strict": false になっているため,ここを "strict": true にすると型エラーになる.既に型解決をした実装も用意されているため,以下のように変更するとうまく動く.最近は TypeScript を書く機会も増えているし,試せて良かった.

import { NextPage } from 'next';

const Home: NextPage<{ userAgent: string }> = ({ userAgent }) => (
  <h1>Hello world! - user agent: {userAgent}</h1>
);

Home.getInitialProps = async ({ req }) => {
  const userAgent = req ? req.headers['user-agent'] || '' : navigator.userAgent;
  return { userAgent };
};

export default Home;

3. Create AMP Pages

Next.js なら React アプリケーションを簡単に AMP に対応させることもできる(当然ながら Valid にするためには工夫も必要になる).「Create AMP Pages」では Next.js でサポートしている2種類の設定 amp: trueamp: 'hybrid' を試す.

nextjs.org

手順は今までとは違って,突然pages/index.jsamp: true を実装する」と書かれている.少し突き放されたような雰囲気もあるため,今回はさっき使った zeit/next-learn-demo リポジトリの E1-static-export ディレクトリを再利用することにした.まず pages/index.js を以下の実装に書き換えて,npm run dev を実行する.AMP の設定を config にしている.

export const config = { amp: true };

export default function Index(props) {
  return <p>Welcome to the AMP only Index page!!</p>;
}

Chrome 拡張機能「AMP Validator」を使って確認すると,data-ampdevmode 関連のエラーは1件出るけど,ちゃんと AMP に対応していた.具体的には,HTML の html タグに AMP 関連の設定が入っていた.

<html amp="" data-ampdevmode="" i-amphtml-layout="" i-amphtml-no-boilerplate="" transformed="self;v=1" amp-version="2003261442330" class="i-amphtml-singledoc i-amphtml-standalone" style="padding-top: 0px !important;">
(中略)
</html>

chrome.google.com

次に pages/index.js を以下の実装に変更し,AMP の設定を hybrid にする.http://localhost:3000/ にアクセスすると通常のレンダリングになり,http://localhost:3000/?amp=1 にアクセスすると AMP のレンダリングになる.isAmp() で判定できる.実際に使うなら hybrid で使うことが多そう.

import { useAmp } from 'next/amp';

export const config = { amp: 'hybrid' };

export default function Index(props) {
  const isAmp = useAmp();
  return <p>Welcome to the {isAmp ? 'AMP' : 'normal'} version of the Index page!!</p>;
}

4. Automatic Static Optimization

最後は Next.js 9 の新機能「Automatic Static Optimization」を試す.簡単に言うと,ビルドをするときに getInitialPropsgetStaticPaths など動的な実装があれば Server としてビルドし,完全に静的な実装なら Static にビルドしてくれる機能となる.ただし,Next.js 9.3 で getStaticProps など,Automatic Static Optimization を改善する機能がリリースされたことにより,コンテンツ内容と画像は古くなっていて,進めながら少し困った⚠️今回は Next.js 9.3 を前提に進める.

nextjs.org

まず,pages/index.js に以下の実装をして,npm run build を実行する.

const Index = () => <h1>Hello World</h1>;
export default Index;

すると,特に / に動的な実装はなく ○ (Static) と判断されていた.

$ npm run build
(中略)
Automatically optimizing pages

Page                                                           Size     First Load
┌ ○ /                                                          266 B       58.2 kB
└ ○ /404                                                       3.15 kB     61.1 kB
+ shared by all                                                57.9 kB
  ├ static/pages/_app.js                                       957 B
  ├ chunks/87dfcf810f5ac5b1c4a6c5a9e347b3d4582d9ddb.92878c.js  10.3 kB
  ├ chunks/framework.0f140d.js                                 40 kB
  ├ runtime/main.b9d743.js                                     5.95 kB
  └ runtime/webpack.b65cab.js                                  746 B

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)(Static)  automatically rendered as static HTML (uses no initial props)(SSG)     automatically generated as static HTML + JSON (uses getStaticProps)

次に,新しく pages/agent.js に以下の実装をして,npm run build を実行する.これは getInitialProps を使ってレンダリング時に UserAgent を取得している.

const Agent = ({ userAgent }) => <h1>Your user agent is: {userAgent}</h1>;

Agent.getInitialProps = async ({ req }) => {
  const userAgent = req ? req.headers['user-agent'] : navigator.userAgent;
  return { userAgent };
};

export default Agent;

すると,/agent に動的な実装があるため λ (Server) と判断されていた.

$ npm run build
(中略)
Automatically optimizing pages

Page                                                           Size     First Load
┌ ○ /                                                          266 B       58.5 kB
├ ○ /404                                                       3.15 kB     61.4 kB
└ λ /agent                                                     400 B       58.7 kB
+ shared by all                                                58.3 kB
  ├ static/pages/_app.js                                       959 B
  ├ chunks/842ebe18e826b71a6d34d074da5a709ac83a664a.79e44c.js  8.28 kB
  ├ chunks/db577d455de274a7f6e1386d96fe5570d4bd24c0.a3bfbe.js  2.4 kB
  ├ chunks/framework.0f140d.js                                 40 kB
  ├ runtime/main.ee8296.js                                     5.95 kB
  └ runtime/webpack.b65cab.js                                  746 B

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)(Static)  automatically rendered as static HTML (uses no initial props)(SSG)     automatically generated as static HTML + JSON (uses getStaticProps)

最初はビルド時に表示される結果を見てもよくわからなかったけど,少しは理解できるようになった.Next.js Learn に感謝!

まとめ

Next.js Learn (Excel) を試した.Static HTML Export 機能や Automatic Static Optimization 機能を学べて,Next.js Learn (Basic) を試したときよりも,理解を一歩前進できたように思う.フィードバックとしては Next.js 9.3 を前提にコンテンツが更新されると良いかなと!とは言え,実際に Next.js を使ってアプリケーションを実装しないとチュートリアルレベルから抜け出せないため,プロトタイプを実装し始めた.Next.js をもっと学ぶぞ!

「ghq handbook」を読んで ghq を使った最高のリポジトリ管理を体験しよう

2020年1月に Leanpub で出版された「ghq handbook」を読んだ.本書は Leanpub で $4.99 から購入できる.

leanpub.com

リポジトリ管理を楽にするコマンドラインツール ghq 自体は前から知っていたけど,今までの運用(特定のディレクトリ直下にひたすら git clone する)で特に困ってなく,導入していなかった.本書を読みながら,今までの運用を全て ghq に移行して,今ではとにかく最高だし,もはや導入していなかった自分を悔やむ.特に ghqpeco を組み合わせた体験は本当に素晴らしい!

github.com

目次

本書は ghq の導入から活用まで網羅的に紹介されている.計24ページとなり,読むだけならすぐだし,実際に導入しながら読んでも2時間あれば終わる.個人的には導入しながら読むのが1番効果的だと思う.

  • イントロダクション
  • 基本的な使い方
  • リポジトリ取得ディレクトリの設定 (ghq root)
  • リポジトリを取得する (ghq get)
  • ローカルリポジトリの一覧・パス取得をおこなう (ghq list)
  • ローカルリポジトリを作成する (ghq create)
  • リポジトリを一括取得のレシピ集 (STDIN | ghq get)
  • ghq のこれから

インストール

今回は brew でインストールした.最新バージョン v1.1.0 を使う.

$ brew install ghq
$ ghq --version
ghq version 1.1.0 (rev:057e0ff)

ghq に入門する

まず,ghq の基本的なコマンドとして ghq getghq listghq root を試す.Go を実装するときは ${GOPATH} を考慮する必要があり,git-config を使った ghq root のカスタマイズも本書に載っている.

$ ghq get x-motemen/ghq

$ ghq list
github.com/rails/rails
github.com/x-motemen/ghq
github.com/kakakakakku/mysql-beginner-hands-on
github.com/kakakakakku/redash-hands-on
github.com/kakakakakku/sandbox-envoy-circuit-breakers
github.com/kakakakakku/sandbox-envoy-request-id
(省略)

$ ghq list --full-path
/Users/kakakakakku/ghq/github.com/rails/rails
/Users/kakakakakku/ghq/github.com/x-motemen/ghq
/Users/kakakakakku/ghq/github.com/kakakakakku/mysql-beginner-hands-on
/Users/kakakakakku/ghq/github.com/kakakakakku/redash-hands-on
/Users/kakakakakku/ghq/github.com/kakakakakku/sandbox-envoy-circuit-breakers
/Users/kakakakakku/ghq/github.com/kakakakakku/sandbox-envoy-request-id
(省略)

$ ghq root
/Users/kakakakakku/ghq

ghq get

ghq get はデフォルトだと HTTPS URLgit clone をする.もし SSH URL を使う場合は,例えば ghq get -p のように -p オプションを使える.ただし,本書にも書いてある通り,ghq 側で制御するのではなく,Git 側で制御するのが良さそう.そのために git-config の設定 url.<base>.insteadOf もしくは url.<base>.pushInsteadOf を使う.詳しくは先週の記事に書いておいた!

kakakakakku.hatenablog.com

また ghq get には「オーナー検出」の機能があり,自分のリポジトリならリポジトリ名だけを指定すれば使える.実際に kakakakakku/redash-hands-on ではなく redash-hands-on と指定しても使えた.これは便利!

$ ghq get redash-hands-on
     clone https://github.com/kakakakakku/redash-hands-on -> /Users/kakakakakku/ghq/github.com/kakakakakku/redash-hands-on
       git clone --recursive https://github.com/kakakakakku/redash-hands-on /Users/kakakakakku/ghq/github.com/kakakakakku/redash-hands-on

他にも --shallow--update--branch など,使うことになりそうなオプションもあり,覚えておく.

ghq list + peco

ghq listpeco と組み合わせると最高の体験になる.peco は今までもずっと愛用してきたため,今回は ghqpeco 対応を追加し,今のところは ^g にバインドした.シュッとリポジトリを検索して cd できるようになった.

QUERY> hands-on
github.com/kakakakakku/elasticsearch-hands-on
github.com/kakakakakku/mysql-beginner-hands-on
github.com/kakakakakku/redash-hands-on
github.com/kakakakakku/docker-hands-on

一括アップデート

本書の最後には「レシピ集」があり,ghq の基本的なコマンドを活用した Tips が載っている.個人的には「標準出力からリストを受け取れる仕組み」--parallel オプション」を組み合わせた「一括アップデート」をよく使いそう.全リポジトリだと流石に多すぎるため,例えば以下のように ghq list である程度フィルタリングしてから ghq get --update --parallel に流せる.便利!

$ ghq list hands-on | ghq get --update --parallel
    update /Users/kakakakakku/ghq/github.com/kakakakakku/docker-hands-on
    update /Users/kakakakakku/ghq/github.com/kakakakakku/elasticsearch-hands-on
    update /Users/kakakakakku/ghq/github.com/kakakakakku/mysql-beginner-hands-on
    update /Users/kakakakakku/ghq/github.com/kakakakakku/redash-hands-on

まとめ

「ghq handbook」を読みながら ghq を導入した.ghq はとにかく最高だし,もはや導入していなかった自分を悔やむ.本書は導入から活用まで網羅的に紹介されているため,まず購入してみると良いと思う.また本書は GitHub で管理されているため「実は購入せずに」読める.プルリクエストも送れる.個人的には OSS を応援する気持ちと ghq への感謝の気持ちを込めて Leanpub で購入すると良いと思う.感謝!

github.com

誤植など

本書を読んでいて,気になる誤植や表現があったけど,GitHub を見ると既に修正されていた.今回は 2020-01-05 に出版されたバージョンを読んでいるけど,定期的にリリースしてもらえると良さそう.他に気になった点を箇条書きにしておく.

  • リポジトリ URL は現在は https://github.com/x-motemen/ghq に変更されている
  • 本書本文書この文書 など,表記揺れが出ている
  • 普段遣い普段使い