kanejaku.org

Tweaking site design

2 Jul 2019

Nord のカラーパレットが気に入ったので使わせてもらおう。pygments のスタイルも合うように変更する。

柔らかい感じの見た目にしたいので border-radius で枠を少し丸くするように変更。あと line-height も調整した。少し行間がある方が読みやすく感じる。

Rust: Raspberry Pi (Raspbian) 向けの実行バイナリを手軽に作る

23 Jun 2019

Rust で書いたアプリケーションを手元の Raspberry Pi 3 で動かしたい。ベアメタルではなくて OS は Raspbian。

まずは raspi 上でコンパイルしてみる。遅い。自分のアプリをコンパイルするのに 60 分 (!) もかかる。アプリの開発自体は PC でやっているからそんなに頻繁に raspi 用のバイナリを作る必要はないのだけど、さすがにこれではやっていられない。

raspi 上でバイナリを作るのは諦めてクロスコンパイル環境を用意する。Rust は簡単にいろんなアーキテクチャ向けの toolchain 入れられるものの、コンパイルだけでなく Raspbian 向けの実行バイナリをリンクするには GCC のクロスコンパイラ (gcc-arm-linux-gnueabihf) が別途必要になる。開発しているマシンの OS に対する依存が少なく、かつ手軽にリンクまでできる環境を作りたい。となると Docker コンテナでクロスコンパイル環境を作れば良さそうだ。

まずは toolchain のセットアップから。DockerHub に Rust の公式イメージがあるのでこれをベースにする。加えて GCC のクロスコンパイラと Rust のarmv7-unknown-linux-gnueabihf向け toolchain をインストールする。コンテナが起動したら cargo build するようにしておく。Dockerfile はこんな感じ。

FROM rust:1.35

# コンテナ実行時に -v オプションでマウントされるのを前提としている。
WORKDIR /usr/src/myapp

RUN apt-get update && apt-get install -y gcc-arm-linux-gnueabihf
RUN rustup target add armv7-unknown-linux-gnueabihf

CMD ["cargo", "build", "--target", "armv7-unknown-linux-gnueabihf", "--release"]

続いて Rust で書いたアプリのリポジトリ配下の.cargo/configにクロスコンパイル用の設定を書いておく。

[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"

あとは Docker イメージ作って実行すれば raspi 上で動くバイナリを生成できる。

$ docker build -t myapp-cross-raspi
$ docker run -it -v "$PWD":/usr/src/myapp myapp-cross-raspi
$ file target/armv7-unknown-linux-gnueabihf/release/myapp
target/armv7-unknown-linux-gnueabihf/release/myapp: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV),
...

ただ、上記の設定だけではcargoのキャッシュがコンテナ内に保持されてしまう。つまりコンテナを作り直すたびに myapp が依存している crates をダウンロードするはめになる。これは資源の無駄なので自分は CARGO_HOME 環境変数を上書きしてホストの適当な場所を指すようにしている。

$ docker run -it -v "$PWD":/usr/src/myapp -e CARGO_HOME="$PWD"/.docker-cargo myapp-cross-raspi

補記

Docker Desktop (Windows と Mac) では最近になって Arm アーキテクチャのコンテナを x86 環境でも動かせるようになったらしい。

Building Multi-Arch Images for Arm and x86 with Docker Desktop - Docker Engineering Blog

つまり Windows と Mac ではコマンド一つ叩くだけで Rasbian 上で動くバイナリをクロスコンパイルできる。

$ docker run -it -v "$PWD":/usr/src/myapp -w /usr/src/myapp arm32v7/rust:1.35 cargo build

こっちのほうが楽だ、と一瞬思ったが、これが結構遅い。内部で QEMU 使っているようだから遅いのはしょうがない気がするが、actix-web を使った単純な hello-world でも手元のマシンで 10 分ぐらいコンパイルに時間がかかった。

参考

梅雨入り前の一日

5 Jun 2019

風鈴がちりん、となった。我が家には風鈴があるのであった。

たしか川崎大社で買い求めたものだ。存在を忘れていたが風情があって良い。

午後にかけてよく晴れた日。ふらっと散歩をして気を良くした。

WebAssemblyのanyref

25 May 2019

WebAssembly にreference typesがあるとどううれしいのか、を理解しようとして書いたメモ。参照型として二つ提案されているが、ここではanyrefに着目する。

(注: Reference types は提案段階なので各種ブラウザではまだデフォルトで有効にはなっていない。Chrome で試すにはコマンドライン引数に--js-flags=--experimental-wasm-anyrefをつける必要がある。)

任意の JS の値を受け取って、それをそのまま返すidentity()という関数を wasm で作ろう。とってつけた例題だけど骨子を最小限のコードで示すために許してほしい。こういうやつ。

identity(value) === value; // => true

anyrefが存在しない現在の仕様だとこれは wasm だけでは定義できない。なぜなら wasm の関数は引数/戻り値に整数型か浮動小数点型しか指定できないから。JS には数値以外にも文字列型やオブジェクト型がある。文字列やオブジェクトを数値に変換する仕組みが JS 側に必要だ。

任意の JS の値を数値に変換する単純な方法としてぱっと思いつくのは、グローバルな配列をひとつ用意して、そこを値の格納先として使うやり方だろう。JS/wasm 間での値の受け渡しはこの配列のインデックスを使う。要はヒープみたいなもの。必要最小限の実装はこんな感じ。

let heap = [];
function toWasmValue(value) {
  heap.push(value);
  return heap.length - 1;
}
function fromWasmValue(index) {
  return heap[index];
}

Wasm の関数を呼ぶときの流れは、toWasmValue()でインデックスを取得、wasm で定義された関数の呼び出し、戻り値をfromWasmValue()で JS の値に戻す、という感じになる。

(async function() {
  const stream = fetch("identity.wasm");
  const { instance } = await WebAssembly.instantiateStreaming(stream);

  // Wrapper function of `identity`
  function identity(value) {
    const index = toWasmValue(value);
    const ret = instance.exports.identity(index);
    return fromWasmValue(ret);
  }

  console.log(identity(42)); // => 42
  console.log(identity(window)); // => window
})();

Wasm 側のコードはただ受け取ったインデックスを返すだけ。

(module
  (func (export "identity") (param i32) (result i32)
  ;; Just return the argument
  get_local 0))

これでidentity()を定義できたが、値を単純に JS → wasm → JS と引き回したいだけなのになんだか面倒だ。しかも今の実装は実用に耐えない。toWasmValue()を呼ぶたびにヒープが大きくなるし、オブジェクトへの参照が消えないのでリークが起きる。きちんと使えるものを作ろうと思うと、不要になった値をヒープから削除しなければならないし、必要に応じてフラグメンテーションも解消しないといけない。

要はメモリ管理が必要になるのだけど、GC がある JS の上にメモリ管理機構を作るのは冗長だと思える。wasm 側で値を操作しないなら(単純に JS に引き渡すだけなら)、その値への参照を wasm に渡すのを許可してもいいのではないか。そうすれば値の生存期間の管理は JS 側の GC に任せられるし、値の変換も不要になる。

…こんな感じでanyrefが提案されたんだろう、と自分は理解した。

実際にanyrefを使って書き直すと以下のようにだいぶすっきりする。JS 上にヒープを作る必要はない。JS 側の GC が参照の生存管理をする。

(async function() {
  const stream = fetch("identity_anyref.wasm");
  const { instance } = await WebAssembly.instantiateStreaming(stream);

  console.log(instance.exports.identity(42)); // => 42
  console.log(instance.exports.identity(window)); // => window
})();

Wasm 側のコードは引数と戻り値の型を変えるだけ。wat2wasmで以下をコンパイルするときは--enable-reference-typesフラグをつける。

(module
  (func (export "identity") (param anyref) (result anyref)
  ;; Just return the argument
  get_local 0))

anyrefが解きたい課題は分かった。では実際の問題に対してanyrefはどううれしいのか。多分ほとんどの開発者には特段メリットはないんじゃないか。というのも、こういう低レイヤの変換やメモリ管理はすでに Emscripten や wasm-bindgen が面倒を見てくれているから。これらのフレームワーク自体にとってはanyrefがあるとラッパー関数なんかを削減できてうれしいと思う。開発者にとってもランタイムのサイズが減って間接的にうれしいかもしれない。

提案の概要にはここで説明した以外の動機も書いてある。むしろ主眼はそちらかもしれなくて、reference types はほかの提案の土台としての側面が強そう。

補記

anyrefWebAssembly.Globalの型やWebAssembly.Tableの要素型としても指定できる。

参考

再帰的なデータ構造のイテレータを手書きする

11 May 2019

amos.me - Recursive iterators in Rust が面白かった。以前 AST をたどるイテレータを書いたときに同じような問題に遭遇した記憶がある。そのときは既存のイテレータやアダプタを組み合わせてうまい具合にやる方法が思いつかず、結局自分でイテレータを実装した。イテレータの内部では状態を管理する列挙型と、今どのノードをたどっているのかを記憶するスタックを使用する。

上記のエントリで出てくる例題に対して実装するとこんなかんじ → Rust Playground

うまく既存のイテレータやアダプタを使って関数型言語っぽい書き方をできるようになりたいなあと思う一方、自分にはどうも手続き的なコードのほうが理解しやすい。イテレータを組み合わせて書いてあるコードはすっきりしていて賢いと思うんだけど、理解が追いつかないことが多い。Rustを使い始めてそこそこ経つので慣れの問題だけじゃないかもしれない。

ニューヨークでベーグルを食べた

5 May 2019

4 月に出張でトロントとニューヨークを訪れた。渡航前に引いた風邪を引きずってしまったせいで体調が悪く、しんどい旅となった。

トロントではあまり観光できなかったが、後半少し回復したのでニューヨークを少し観光することができた。ニューヨークを訪れるのは二度目。最初に訪れたときに食べたベーグルが美味しかったので、今回もベーグルを食べようとお店を巡った。

最初に訪れたのは Tompkins Square Bagels。界隈でベストなベーグル屋さんはどこ?と現地の同僚に聞いたら教えてくれたお店である。

ドライトマトが入ったクリームチーズを挟んでもらった。翌日まで顎がつかれるぐらい噛みごたえのある生地で自分好みの食感であった。

別の日にはアッパーウエストサイドにある Aboslute Bagles を訪問した。ここは前回ニューヨークに来たときに一番印象に残っていたので再訪しようと思っていたお店だ。朝 9 時ぐらいについたのだけど、けっこうな行列ができていた。ただ、店内で食べていく人はあまりいないので待ち時間はそれほどでもない。どれを食べようかと悩んでいる間に行列は掃けた。

定番のサーモンが入ったスプレッドにしよう思っていたのだけど、陳列されていたブルーベリーのやつが美味しそうだったので少し悩んだ結果ブルーベリーに変更した。ベーグルはそれに合いそうなプレーンを選択。

これが正解で、とても美味しかった。写真ではわからないかもしれないが、ここのベーグルはかなり大きい。一食分としては半分でも多いくらい。それでも完食してしまった。おかげでこの日はお昼が入らなかった。再度ニューヨークを訪れる機会があればここのベーグルはまた食べたい。

最終日の空港に向かう前に訪れたのはBrooklyn Bagel & Coffee Company。ここではスプレッドを頼まずベーグル単体で購入した。種類はプレーンと全部入り(Everything)。

これは結局食べる余裕がなくて帰国後冷凍保存した。これも一つが大きいので食べごたえがありそうであった。

TypeScriptの型チェックと仲良くする

6 Feb 2019

TypeScript のコンパイルエラーを一時的に抑止したい場面は多々ある。この記事では、自分が型エラーを回避するのに便利だなと思っている機能を状況に応じて 3 つ紹介したいと思う。想定している文脈は、趣味プロジェクトで、フレームワークを使わない素のフロントエンド開発。

Type Guards

状況: このエレメントは<foo>なんだからbarっていう属性があるのに TypsScript はそれを分かってくれない。

例えばオーディオを再生するページを静的に記述したとする。

<audio id="my-audio"></audio>

このオーディオに対して再生位置をリセットするスクリプトを書きたい。書いている側からするとmy-audioHTMLAudioElementであることが分かっている。getElementById('my-audio')の返り値はHTMLAudioElementだからと思って以下のように書くとコンパイラに怒られる。

const audioEl = document.getElementById("my-audio");
// NG: `[ts] Property 'currentTime' does not exist on type 'HTMLElement'. [2339]`
audioEl.currentTime = 0;

この場合は Type guards に頼る。if 文で型の整合性をチェックすると、コンパイラがコントロールフローを解析して型を限定してくれる。以下では if 文以降audioElHTMLMediaElementであることが保証される。

const audioEl = document.getElementById("my-audio");
if (!(audioEl instanceof HTMLMediaElement)) {
  throw new Error("#my-audio is not an HTMLMediaElement");
}
// OK: At this point TS compiler knows `audioEl` is an HTMLMediaElement.
audioEl.currentTime = 0;

冗長だけど if 文以降に型チェックの恩恵を受けられることを考えるとトレードオフとしては悪くない。asを使う方法もあるけれど、 Type Guards を使ったほうがより安全になる。

参考: Advanced Types · TypeScript

Non Null Assertion Operator

状況: 関数foo()nullundefinedじゃない値を返すのが分かってるのに TypeScript がそれを分かってくれない。

2D の絵を描きたいとする。ブラウザ上で 2D の絵を描くにはHTMLCanvasElementを用意してそれに対してgetContext('2d')を呼んで描画コンテキストを取得する。だけど TypeScript はgetContext()nullを返すかもしれないと文句を言ってくる。

// NG: [ts] Type 'CanvasRenderingContext2D | null' is not assignable to type 'CanvasRenderingContext2D'.
//          Type 'null' is not assignable to type 'CanvasRenderingContext2D'. [2322]
const ctx: CanvasRenderingContext2D = canvas.getContext("2d");

この場合は!を末尾につけている。これはNon Null Assertion Operatorというやつで、式の末尾に!をつけるとコンパイラはその式がnullundefinedを返すことがないと仮定するようになる。nullundefinedを返す式にしか使えないけど、Type guards を使うよりも簡潔に型を限定できる。

// OK
const ctx: CanvasRenderingContext2D = canvas.getContext("2d")!;
ctx.clearRect(0, 0, width, height);

ただ Type guards と違ってコンパイラが null や undefined にならないことを保証してくれるわけでは無い、という点に注意。

参考: TypeScript 2.0 · TypeScript

@ts-ignore

状況: window に一時的にデバッグ用のプロパティを追加したいけど TypeScript がそれを許してくれない。

開発の初期段階ではブラウザのデベロッパーツールを使っていろんな検証をしたい。例えば自作のAppオブジェクトの状態をデベロッパーツールで確認したいとする。そんなときには手っ取り早くアクセスできるオブジェクト、例えばwindowにそのオブジェクトをぶら下げるのが簡単だろう。でも単純にそれをやろうとするとコンパイラが怒る。

const app = new App(...);
// NG: [ts] Property 'app' does not exist on type 'Window'. [2339]
window.app = app;

こういう状況では@ts-ignoreを使っている。@ts-ignoreをコメントとして書くと、以後の一文だけはコンパイラは何もエラーを出さなくなる。tsconfig.json などで一括にエラーを抑止するのは避けたいけど、この一文だけ見逃して欲しい場面で重宝する。

const app = new App(...);
// @ts-ignore
window.app = app; // OK
...
console.log(window.app); // NG

あくまで@ts-ignoreの直下の行だけエラーを出力しないようになるだけなので、ほかの場所でappを使おうとするとコンパイラに怒られる。自分は@ts-ignoreをDevToolsを使ったデバッグや調査をしたいときや、トリッキーなimportをしている場所のエラーを抑止したいときなんかに使っている。

参考: TypeScript 2.6 · TypeScript

参考文献

Revised Revised 型の国のTypeScript は非常に良い入門書。一日ぐらいかけて目を通しておくと TypeScript の気持ちがわかるようになると思う。自分は技術書典3で紙の本を購入した。

TypeScriptのunsafeな操作まとめ では TypeScript の型検査が常に有効ではないことを議論している。

Rustでwasm用カスタムアロケータを書く

14 Jan 2019

Wasm とホスト間での関数呼び出しでは数値しか受け渡すことができないので、文字列や配列をやり取りするときには wasm インスタンスのメモリを経由する必要がある。例えば文字列をホスト(JavaScript)から wasm に渡したいときは一度 wasm インスタンスのメモリ領域に文字列を書いてから、書いた場所のアドレスとサイズを関数に渡す。これは数値以外の情報をやり取りする場合は wasm 側にメモリアロケータが必要であることを意味している。

Rust が生成する wasm がメモリ割り当てをどうやっているのかを調べて、自分でナイーブなアロケータを作るところまでやったので、その過程で理解したことをエントリにしておこうと思う。

ここではホスト環境としてブラウザ(JavaScript)を想定している。また wasm のインスタンス化の際にはメモリを import せず wasm 内で管理することを前提とする。

WebAssembly のメモリ

WebAssembly は単純なメモリモデルを採用していて、メモリは連続したバイト列として表現される。初期化時にある一定のサイズが確保されて、必要に応じて領域を広げることができる。ただし一度確保した領域を縮小することはできない。メモリ領域の伸張は 64KB のページ単位で行う。

Wasm インスタンスのメモリは JavaScript からは ArrayBuffer として見える。例として[1,2,3]という配列を JS から wasm に&[u32]として渡したいとしよう。JS 側のコードはこんな感じになる。

// `wasm` is an WebAssembly.Instance.
const arg = [1, 2, 3];
const arr = new Uint32Array(wasm.memory.buffer);
const addr = wasm.allocBytes(arg.length * 4);
arr.set(arg, addr / 4);
wasm.someFunc(addr, arg.length);
wasm.freeBytes(addr);

wasm.memory.bufferから見える ArrayBuffer が wasm インスタンスのメモリ。wasm 側のアロケータの仕事は、wasm.memory.bufferをヒープ領域として扱い、そのヒープを適宜伸張しながら malloc()/free()相当の機能を提供すること。上記ではそれらをwasm.allocBytes()wasm.freeBytes()として定義している。

wasm からメモリ領域を伸張するにはmemory.grow命令を使う。この命令は引数を二つとる。一つは新たに確保するページの数。もう一つは対象となるメモリ領域を指定するインデックス。このインデックスには常に 0 を指定する。仕様の上では wasm インスタンスは複数のメモリ領域を参照できるようになっているが、これは将来の拡張のために用意されているもの。現時点では一つの wasm インスタンスにつきメモリ領域は一つしか存在しない。

アロケータの実装

Rust 側での実装に話を進めていく。Rust から WebAssembly のmemory.grow命令を呼ぶにはwasm32::memory_grow()を使う。以下の Rust のコードをコンパイルすると、

#![cfg_attr(target_arch = "wasm32", feature(stdsimd))]
use core::arch::wasm32;
fn f() -> usize {
  const MEMORY_INDEX: usize = 0;
  unsafe { wasm32::memory_grow(MEMORY_INDEX, 1) }
}

以下の wasm が生成される。

(func (;1;) (type 1) (result i32)
  i32.const 1
  memory.grow)

memory_grow()は成功すると伸張前のメモリのサイズをページ単位で返す。言い換えれば、新規に確保されたメモリの開始アドレスは戻り値に 64KB を掛けることで求められる。また伸長に失敗したときはusize::max_value()を返す。以下のようなラッパーを書くと malloc()に近い使い勝手になる。

unsafe fn grow_pages(num_pages: usize) -> *mut u8 {
    let num_pages = wasm32::memory_grow(MEMORY_INDEX, num_pages);
    if num_pages == usize::max_value() {
        process::abort();
    }
    (num_pages * PAGE_SIZE) as *mut u8
}

下準備ができたのでアロケータを書いていく。今回はアロケータを作るうえで必要なパーツを説明するのが主眼なので、Memory Allocators 101という記事を参照にして単純な first-fit のアロケータを作成した。コードは Github にあげているのでここではインタフェースのみ載せておく。

struct Heap {
    // ...
}

impl Heap {
    unsafe fn alloc(&mut self, size: usize) -> *mut u8 { /* ... */ }
    unsafe fn dealloc(&mut self, ptr: *mut u8) { /* ... */ }
}

ポインタを安全でない方法でキャストしたりするので割り切って全体を unsafe にしている。もっと Rust 力があれば安全に書けるかもしれないが、後述する GlobalAlloc が unsafe なのであまり頑張っても意味がないかもしれない。

GlobalAlloc

さらに、さきほど作成したアロケータを Rust のVec<T>Stringなどの標準ライブラリのメモリ割り当てにも使うようにする。ホスト環境とのデータのやり取りのみに自作のアロケータを使う場合はこの作業は不要だが、デフォルトのアロケータはバイナリサイズが大きく(10KB ぐらいになる)、使用するアロケータは一つに統一しておいたほうが良い。

標準ライブラリのアロケータを自前のものに差し替えるには以下の二つを行う。

  • GlobalAllocトレイトを実装する型を作る
  • その型の static なグローバル変数を#[global_allocator]属性をつけて定義する

GlobalAllocを実装するには以下の二つのメソッドを実装する。Layoutはサイズとアライメントを保持する構造体。

unsafe fn alloc(&self, layout: Layout) -> *mut u8;
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);

これら二つのメソッド、&mut selfではなく&selfを取る。これは GlobalAlloc を実装する型が static なグローバル変数として使われることからくる制約だろう。

とはいえメモリの割り当てと解放にはアロケータの状態を変更しなければならない。こういう場合の Rust のイディオムは内部可変性を使うことだろう。ここではUnsafeCell<T>を使う。内部可変性を提供する型を書く際は排他制御をして各種の競合に注意しなければならないが、Rust は WebAssembly 向けのスレッドはまだサポートしていないので今回はシングルスレッドを前提にする。

struct CustomAlloc {
    heap: UnsafeCell<Heap>,
}

impl GlobalAlloc for CustomAlloc {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        (*self.heap.get()).alloc(layout.size())
    }

    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
        (*self.heap.get()).dealloc(ptr)
    }
}

unsafe impl Sync for CustomAlloc {}

static ALLOC: CustomAlloc = CustomAlloc {
    heap: UnsafeCell::new(Heap { /* ... */ }),
};

UnsafeCell<T>Syncを実装しないので、シングルスレッドで使う前提でSyncを明示的に実装している。これを忘れるとCustomAllocを static な変数として使おうとしたときにコンパイラに怒られる。

これで実装は一通り完了したのであとは実際に使ってみる。

wasm-bindgen

冒頭に説明したように wasm とホスト環境で文字列や配列をやり取りする際には面倒な手順を踏む必要がある。文字列を渡す場合を例に具体的なステップを見てみると、(1) ホスト側からメモリ領域を確保するよう wasm インスタンスに要求する、(2)ホスト側で wasm のメモリ領域に文字列の内容を書く、(3)データを書いたアドレスとサイズを wasm の関数に渡す、(4)wasm の関数では渡されたアドレスとサイズから String なり &str に変換する、という作業が必要になる。

この部分も自作しようかと考えたが、結構煩雑になるのでこの変換部分は wasm-bindgen に頼ることにした。wasm-bindgen を使うとホスト(JavaScript)と wasm 側両方のラッパーを作ってくれるのでとても楽になる。

extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn to_uppercase(s: &str) -> String {
    s.to_uppercase()
}

あとはビルドして wasm-bindgen の CLI で後処理をすれば最終的な wasm/JS ができる。wasm-bindgen はデフォルトだと Webpack で処理する前提の ES modules 形式で出力するが、オプションを指定することでブラウザで直接読み込める形式にすることもできる。

$ cargo build --release --target wasm32-unknown-unknown
$ wasm-bindgen --browser --no-modules target/wasm32-unknown-unknown/release/wasm_custom_allocator_example.wasm --out-dir public/dist

wee_alloc

アロケータを差し替える主な動機はバイナリサイズの削減だろう。今回は理解を深める目的で自分でアロケータを書いてみたが、実用的には独自アロケータを書くよりもwee_allocを使うのが良いと思う。アロケータは unsafe なコードがどうしても多くなるし、unsafe なコードをきちんと書くのは相当難しい。

参考

正月休み

4 Jan 2019

実家に帰ったり、おせち食べたり、三社参りしたり、わりと普通の年末年始を楽しんだ。年末に崩した体調も回復した。ToDoリストの進捗は芳しからず。辞書ビューアをひと段落させたかったがコーディングはあまり進まなかった。

年をまたいだことだしサイトのトップページのリストを年単位でグループ分けすることにした。日記的なエントリを書きやすくなると思う。

ひそかに期待していたsteps to phantasienの更新はないらしい。休みの期間にちょくちょくチェックしていたのだけど残念。

2018年の振り返り

30 Dec 2018

今年は Github の草を生やすのを日課にしていた。内容は二の次で些細な変更、例えばタイポの修正とかでもいいから毎日コードを書く。対象はほぼプライベートリポジトリ。

旅行してたり体調不良の時以外は埋まっている。習慣化できたのは良かった。ただ草をはやすのを目標にすると、難しいコーディングを避けて簡単なバグ修正をしたり、小さい検証コードを書いたりしがちであった。十分な時間を確保できないと、まとまったコードを書く気にならないのが問題だったと思う。来年はもうちょっと意味のあるコードを書くようにしたい。

あと学生だった時以来のブログを再開した。文章を書く練習をしたい、というのと学習したことを記憶に定着させたい、というのが動機。勉強したことを忘れないように記事にする、というのは nhiroki さんが言っていて、実際に効果あるなあと感じている。技術的な内容に限定する気はないので今後は日常の事とか趣味のこととか書いていきたい。shinh さんの日記みたいな、思ったことをふらっと書くスタイルとかやってみたいし、森田さんのブログみたいなちょっと詩的な感じのやつとか憧れたりする。

Rust

技術的なところでは今年一番時間を使ったのが Rust の勉強。本が 2 冊出たのと、Raph Levienが最近凝っているらしいというので勉強を続けている。自作の辞書ビューアを Rust で書き直したりしているが、まだ手になじまない。実際のアプリを作ろうとしたときに制約がきつくてつらい、イディオムがわからない、みたいな気持ちになる。Rust を学習すること自体は楽しいので来年も続けると思う。

LeetCode

コーディング面接対策で有名なサイト。面接で聞かれそうな問題が豊富にある。競技プログラミングは早々に挫折した身なのだけど、こちらは基礎的なアルゴリズムやデータ構造を知っていれば自分にも解ける問題が多い。動的計画法が苦手だという意識があったので 4 月 5 月あたりに集中的に解いていた。これまでのところ Solved は 113 個。今後もちょっとづつ解いていこうと思っている。

英語

昨年の 12 月から英会話スクールに通っている。ちょうど一年過ぎたぐらい。この間スクールが定めるレベルを一つクリアした。割と効果を実感していて、壊れた英語でもしゃべること自体の抵抗感がなくなった。受講料が高いのでコストパフォーマンスに見合うかどうかは正直わからないが、来年も続けようと思っている。あとひとつレベルをクリアしたい。

散歩とポッドキャスト

健康と趣味(町散策)を兼ねてできるだけ歩くようにしている。ここ数年は一日 10km ぐらい歩くのを目標にしていて、今年もだいたい達成できた。散歩しているときはいつもポッドキャストを聞いている。最近はポッドキャストの番組が増えてうれしい。今年よく聞いた番組たち:

写真

長いこと買うか悩んでいた Sony α7R III を冬前に購入した。写真撮るのが一段と楽しくなった。街撮りメインだけどポートレートとかも練習したい。