【Go】bufio.Scannerを使う際の注意点

先日Goでスクリプトを書いているときに以下のようなバグに遭遇したので書き残しておきます。


以下のようなファイルがありました。

{"title": "Eloquent JavaScript, Second Edition","description": "JavaScript lies at the heart of almost every modern web application, from social apps to the newest browser-based games. Though simple for beginners to pick up and play with, JavaScript is a flexible, complex language that you can use to build full-scale applications."}
{"title": "Learning JavaScript Design Patterns","description": "With Learning JavaScript Design Patterns, you'll learn how to write beautiful, structured, and maintainable JavaScript by applying classical and modern design patterns to the language. If you want to keep your code efficient, more manageable, and up-to-date with the latest best practices, this book is for you."}
{"title": "Speaking JavaScript","description": "Like it or not, JavaScript is everywhere these days-from browser to server to mobile-and now you, too, need to learn the language or dive deeper than you have. This concise book guides you into and through JavaScript, written by a veteran programmer who once found himself in the same position."}
{"title": "Programming JavaScript Applications","description": "Take advantage of JavaScript's power to build robust web-scale or enterprise applications that are easy to extend and maintain. By applying the design patterns outlined in this practical book, experienced JavaScript developers will learn how to write flexible and resilient code that's easier-yes, easier-to work with as your code base grows."}
{"title": "Understanding ECMAScript 6","description": "ECMAScript 6 represents the biggest update to the core of JavaScript in the history of the language. In Understanding ECMAScript 6, expert developer Nicholas C. Zakas provides a complete guide to the object types, syntax, and other exciting changes that ECMAScript 6 brings to JavaScript."}
{"title": "You Don't Know JS","description": "No matter how much experience you have with JavaScript, odds are you don’t fully understand the language. As part of the "You Don’t Know JS" series, this compact guide focuses on new features available in ECMAScript 6 (ES6), the latest version of the standard upon which JavaScript is built."}
{"title": "Git Pocket Guide","description": "This pocket guide is the perfect on-the-job companion to Git, the distributed version control system. It provides a compact, readable introduction to Git for new users, as well as a reference to common commands and procedures for those of you with Git experience."}
{"title": "Designing Evolvable Web APIs with ASP.NET","description": "Design and build Web APIs for a broad range of clients—including browsers and mobile devices—that can adapt to change over time. This practical, hands-on guide takes you through the theory and tools you need to build evolvable HTTP services with Microsoft’s ASP.NET Web API framework. In the process, you’ll learn how design and implement a real-world Web API."}

(サンプルはこちらより拝借しました。)

一見するとJSONですが、[]で囲まれておらず、行末にカンマもないのでそのままではJSONとして処理することはできません。

ここでやりたかったことは、(1)各行を構造体としてデコードすること、(2)構造体に生のバイト列を保持すること、の二点です。 そのためbufio.Scannerを使い、以下のようなスクリプトを書いて処理しようとしました。

type Book struct {
    Title       string `json:"title"`
    Description string `json:"description"`
    Raw         []byte
}

func main() {
    f, _ := os.Open("./sample.txt")

    var books []Book
    scanner := bufio.NewScanner(f)
    for scanner.Scan() {
        var b Book
        bytes := scanner.Bytes()
        b.Raw = bytes

        json.Unmarshal(bytes, &b)

        books = append(books, b)
    }

    for _, b := range books {
        log.Println(string(b.Raw))
    }
}

これの出力、どうなるでしょうか。

以下のとおりです。

$ go run main.go 
2019/02/23 12:59:45 {"title": "Designing Evolvable Web APIs with ASP.NET","description": "Design and build Web APIs for a broad range of clients—including browsers and mobile devices—that can adapt to change over time. This practical, hands-on guide takes you through the theory and tools you need to build evolvable HTTP services with Microsoft’s 
2019/02/23 12:59:45 SP.NET Web API framework. In the process, you’ll learn how design and implement a real-world Web API."} you'll learn how to write beautiful, structured, and maintainable JavaScript by applying classical and modern design patterns to the language. If you want to keep your code efficient, more manageable, and up-to-date with the latest best practices, this book is for you."}
2019/02/23 12:59:45 {"title": "Speaking JavaScript","description": "Like it or not, JavaScript is everywhere these days-from browser to server to mobile-and now you, too, need to learn the language or dive deeper than you have. This concise book guides you into and through JavaScript, written by a veteran programmer who once found himself in the same position."}
2019/02/23 12:59:45 {"title": "Programming JavaScript Applications","description": "Take advantage of JavaScript's power to build robust web-scale or enterprise applications that are easy to extend and maintain. By applying the design patterns outlined in this practical book, experienced JavaScript developers will learn how to write flexible and resilient code that's easier-yes, easier-to work with as your code base grows."}
2019/02/23 12:59:45 {"title": "Understanding ECMAScript 6","description": "ECMAScript 6 represents the biggest update to the core of JavaScript in the history of the language. In Understanding ECMAScript 6, expert developer Nicholas C. Zakas provides a complete guide to the object types, syntax, and other exciting changes that ECMAScript 6 brings to JavaScript."}
2019/02/23 12:59:45 {"title": "You Don't Know JS","description": "No matter how much experience you have with JavaScript, odds are you don’t fully understand the language. As part of the "You Don’t Know JS" series, this compact guide focuses on new features available in ECMAScript 6 (ES6), the latest version of the standard upon which JavaScript is built."}
2019/02/23 12:59:45 {"title": "Git Pocket Guide","description": "This pocket guide is the perfect on-the-job companion to Git, the distributed version control system. It provides a compact, readable introduction to Git for new users, as well as a reference to common commands and procedures for those of you with Git experience."}
2019/02/23 12:59:45 {"title": "Designing Evolvable Web APIs with ASP.NET","description": "Design and build Web APIs for a broad range of clients—including browsers and mobile devices—that can adapt to change over time. This practical, hands-on guide takes you through the theory and tools you need to build evolvable HTTP services with Microsoft’s ASP.NET Web API framework. In the process, you’ll learn how design and implement a real-world Web API."}

よく見てみると1、2行目がおかしなことになっています。

どうもb.Rawが上書きされているようです。そこで以下の行をループ内に追加し、scanner.Bytes()が返す値の先頭位置を出力してみます。

log.Printf("&bytes[0] = %x\n", &bytes[0])
$ go run main.go 
2019/02/23 12:59:45 &bytes[0] = c00008e000
2019/02/23 12:59:45 &bytes[0] = c00008e14f
2019/02/23 12:59:45 &bytes[0] = c00008e2c9
2019/02/23 12:59:45 &bytes[0] = c00008e422
2019/02/23 12:59:45 &bytes[0] = c00008e5bb
2019/02/23 12:59:45 &bytes[0] = c00008e715
2019/02/23 12:59:45 &bytes[0] = c00008e86d
2019/02/23 12:59:45 &bytes[0] = c00008e000

1行目と8行目が同じ位置を指しており、最初のループの内容を8周目のscanner.Scan()が上書きしてしまっているのがわかりました。

というわけで正しい動作をするコードが以下です。

func main() {
    f, _ := os.Open("./sample.txt")

    var books []Book
    scanner := bufio.NewScanner(f)
    for scanner.Scan() {
        var b Book
        bytes := scanner.Bytes()
        b.Raw = make([]byte, len(bytes))
        copy(b.Raw, bytes)

        json.Unmarshal(bytes, &b)

        books = append(books, b)
    }

    for _, b := range books {
        log.Println(string(b.Raw))
    }
}

b.Rawにはmakeで新しいsliceをアサインしておき、scanner.Bytes()で返ってきた値をcopyすることで上書きを防ぎます。これにより以下のような正しい結果を得ることができました。

$ go run main.go 
2019/02/23 13:01:51 {"title": "Eloquent JavaScript, Second Edition","description": "JavaScript lies at the heart of almost every modern web application, from social apps to the newest browser-based games. Though simple for beginners to pick up and play with, JavaScript is a flexible, complex language that you can use to build full-scale applications."}
2019/02/23 13:01:51 {"title": "Learning JavaScript Design Patterns","description": "With Learning JavaScript Design Patterns, you'll learn how to write beautiful, structured, and maintainable JavaScript by applying classical and modern design patterns to the language. If you want to keep your code efficient, more manageable, and up-to-date with the latest best practices, this book is for you."}
2019/02/23 13:01:51 {"title": "Speaking JavaScript","description": "Like it or not, JavaScript is everywhere these days-from browser to server to mobile-and now you, too, need to learn the language or dive deeper than you have. This concise book guides you into and through JavaScript, written by a veteran programmer who once found himself in the same position."}
2019/02/23 13:01:51 {"title": "Programming JavaScript Applications","description": "Take advantage of JavaScript's power to build robust web-scale or enterprise applications that are easy to extend and maintain. By applying the design patterns outlined in this practical book, experienced JavaScript developers will learn how to write flexible and resilient code that's easier-yes, easier-to work with as your code base grows."}
2019/02/23 13:01:51 {"title": "Understanding ECMAScript 6","description": "ECMAScript 6 represents the biggest update to the core of JavaScript in the history of the language. In Understanding ECMAScript 6, expert developer Nicholas C. Zakas provides a complete guide to the object types, syntax, and other exciting changes that ECMAScript 6 brings to JavaScript."}
2019/02/23 13:01:51 {"title": "You Don't Know JS","description": "No matter how much experience you have with JavaScript, odds are you don’t fully understand the language. As part of the "You Don’t Know JS" series, this compact guide focuses on new features available in ECMAScript 6 (ES6), the latest version of the standard upon which JavaScript is built."}
2019/02/23 13:01:51 {"title": "Git Pocket Guide","description": "This pocket guide is the perfect on-the-job companion to Git, the distributed version control system. It provides a compact, readable introduction to Git for new users, as well as a reference to common commands and procedures for those of you with Git experience."}
2019/02/23 13:01:51 {"title": "Designing Evolvable Web APIs with ASP.NET","description": "Design and build Web APIs for a broad range of clients—including browsers and mobile devices—that can adapt to change over time. This practical, hands-on guide takes you through the theory and tools you need to build evolvable HTTP services with Microsoft’s ASP.NET Web API framework. In the process, you’ll learn how design and implement a real-world Web API."}

bufio.Scannerを使うときは気をつけよう、という話でした。

アプリケーションのパフォーマンス分析

詳解システム・パフォーマンス5.4はアプリケーションに対するパフォーマンス分析の手法についてまとめられています。

以下の順で分析をすることが勧められています。

①スレッドの状態の分析

はじめにアプリケーションのプロセスがどの状態で一番時間を過ごしているのかを確認します。取りうる状態およびその計測ツールは以下の通りです。

  • 実行中:top
  • 実行可能:schedstat
  • 無名ページング(無名ページのページイン待ち):遅延アカウンティング
  • スリープ:pidstat -d、遅延アカウンティング、iotop
  • ロック:トレーシングツール
  • アイドル

目標は出来るだけ多くの時間をアイドル状態で過ごさせることです。アプリケーションの性質によってはスリープやロック状態がアイドルに等しいこともあるので注意です。

②CPUのプロファイリング

アプリケーションがCPUリソースを消費しているのはなぜかを知るために、スタックトレースをサンプリングします。解析にはフレームグラフなどの可視化ツールが有効です。DTraceで実行中の関数のみトレーシングする例があげられていますが、ツールはおそらくアプリケーションの言語に依存するでしょう。

システムコールの分析

システムコールを分析することによりスレッドがなぜその状態にいるのか、どのシステムコールがどこから呼び出されたのかを探ります。主にスリープやロック状態が対象で、実行可能や無名ページングにある場合には後述のUSEメソッドを使用します。ツールはオーバーヘッドを気にしない場合はstraceを、オーバーヘッドを最小にしたい場合はDTraceなどを使用します。(straceはシステムコール呼び出し時にブレークポイントを設定する侵食型なのに対し、DTraceはトレース情報をカーネル内でバッファリングするバッファードトレーシングという方式を採用しているためオーバーヘッドが小さい。)

④I/Oのプロファイリング

I/O関連のシステムコールに限定してその種類とコンテキスト(スタックトレース)を分析します。ツールは主にDTraceを使います。

⑤ワークロードの特性の把握

アプリケーションに送られてくるワークロードの解析を行います。

⑥USEメソッド

使用率・飽和・エラーの計測によりリソースのボトルネックを探します。実行可能状態や無名ページングの原因はリソースの飽和にある(それぞれCPUとメモリ)ためUSEメソッドが効果的です。

⑦ドリルダウン分析

実際にアプリケーションを読み込んでいく分析です。場合によってシステムライブラリなどの低レイヤー領域に踏み込むこともあります。

⑧ロック分析

競合のチェックと長すぎるロック保持をチェックします。解析にはCPUプロファイリングと同じ手法を使います。

⑨静的パフォーマンスチューニング

最後にアプリケーションの構成を分析し、より効果的な構成がないかどうか探ります。


以上9つの分析方法がありますが、全てをする必要はありませんし順番を入れ替えても問題ありません。大切なのはルーチン化しておき、分析が必要となった時に素早く、繰り返しできることだと想像します。

パフォーマンス分析の手法

詳解システム・パフォーマンス5.2項はパフォーマンス分析とチューニングのためのメソッド・アンチメソッドです。

メソッド・アンチメソッド

  • 街灯のアンチメソッド
  • ランダム変更アンチメソッド
  • 誰かほかの人を避難するアンチメソッド
  • アドホックチェククリスト
  • 問題の記述
  • 診断サイクル
  • ツールメソッド
  • USEメソッド
  • ワークロード特性の把握
  • ドリルダウン分析
  • レイテンシ分析
  • メソッドR
  • イベントトレーシング
  • ベースライン統計
  • パフォーマンスモニタリング
  • 待ち行列理論
  • 静的パフォーマンスチューニング
  • キャッシュチューニング
  • マイクロベンチマーキング
  • キャパシティプランニング

重要そうなものを詳しく見ていきます。

街灯のアンチメソッド

「たまたま知っている観察ツールをとりあえず使ってみる」というメンタリティ。問題が見つかったとして、それが今直面している問題の解決になるとは限らない。

ランダム変更アンチメソッド

ここがおかしそうだなというところにとりあえず変更を加えてみて、直ったらラッキーという手法。当然運に頼ることになり、結果として遠回りになる。

アドホックチェックリスト

あらかじめ検査すべき項目をリストアップしておく手法。頻繁なメンテナンスが必要。

問題の記述

問題に対処するときのルーチンであり、問題を受け取った時に聞いておくべき項目。

  1. 問題の内容
  2. 既存の問題か新規の問題か
  3. 最近変更はあったか
  4. その問題はレイテンシあるいは実行時間で表現できるか
  5. 問題の影響範囲
  6. 環境・バージョン・構成

USEメソッド

すべてのリソースについて、使用率・飽和・エラーをチェックする。はじめにリソースのリストを作成し、その後先の3つの指標とリソースの組み合わせを検討し、重要な組み合わせに目星をつけて優先的に調べる。

ワークロード特性の把握

システムがどういう入力を受けているのかを分析する。

  • 負荷をかけているのは誰か(プロセスID)
  • なぜ負荷がかかっているのか
  • 負荷の特徴:IOPS、スループット、Read or Write、...
  • 時系列的な変化

パフォーマンス計測ツールがどこから情報を取得しているのか

詳解システム・パフォーマンス4.2には各パフォーマンス計測ツールの情報ソースについてまとめられています。

www.amazon.co.jp

基本的にLinuxを前提とし、Solarisシステムに関しては省略します。

カウンタのための情報ソース

  • /procディレクトリ:プロセスごとおよびシステム全体に関するデータが格納されています。取得できるデータの例として、プロセスごとにはリソース制限、メモリの使用状況、CPU実行時間など、システム全体としてはディスクI/O統計、メモリ使用状況、ネットワーク関連、ロードアベレージなどがあります。
  • /sysディレクトリ:デバイスドライバに関する情報ソースで、デバイスごとのデータを取得することができます。(拡張され、カーネル全体に関する統計も取得できるようになっています。)

トレーシングのための情報ソース

プロセスごとのトレーシングにptraceシステムコール、uprobeがあり、カーネルレベルのトレーシングにtracepoint、kprobeが提供されています。またネットワークのスニッフィング(tcpdumpの情報ソース)としてlibpcapライブラリと/proc/net/devが用意されています。

その他

スレッドごとの各種レイテンシを取得するための遅延アカウンティングというソースがあります。

パフォーマンス計測ツールの分類

詳解システム・パフォーマンス4.1にはパフォーマンス計測ツールの分類について書かれています。

www.amazon.co.jp

ひとえにパフォーマンス計測のツールと言っても、その特徴ごとに分類することができます。 主な観点は以下の2つです。

  • 全てのイベントに対する集計(=カウンタ)かイベントごとの集計(=トレーシング)か
  • システム全体に対する統計かプロセスごとの統計か

カウンタ

受信したネットワークパケットの数など、イベントの回数を集計するツールです。

  • システム全体を計測:vmstat, mpstat, iostat, netstat, sar
  • プロセスごとの計測:ps, top, pmap

トレーシング

1つのHTTPリクエストなどイベントごとにデータを集計するツールです。ロギングも一種のトレーシングと考えることができます。

  • システム全体の計測;tcpdump, snoop, blktrace, iosnoop, execsnoop, dtruss, DTrace, SystemTap, perf
  • プロセスごとの計測:strace, truss, gdb, mdb

その他

プロファイリングはターゲットに対しサンプリングを行って計測するツールです。間隔を指定して使います。

例)oprofile, perf, DTrace, SystemTap, cachegrind, Intel VTune Amplifier XE, Oracle Solaris Studio

計算理論の基礎:オートマトン

計算理論の基礎を読んでいるので整理のために少しまとめておきます。

www.amazon.co.jp

計算理論の3大分野

他の分野同様計算の理論もいくつかの分野に分かれていますが、そのなかでも重要なのが以下の3つの分野です。 計算の理論における根本的な疑問は計算機の本質とその能力の限界にあり、各分野別の角度からその答えを探っています。

  • 計算の数学的モデル(オートマトン)... 計算の数学的モデルとその性質・能力
  • 計算可能性 ... 計算機が解決できる問題とそうでない問題の違い
  • 計算の複雑さ ... 問題の難しさを決める要因について

オートマトン

第1巻のテーマはオートマトンです。計算機に対し入力として文字列の集合を与えた時にそのモデルで認識できるかどうかなどが議論の中心になります。本書で紹介されている計算モデルは

の3つです。(チューリング機械は計算可能性への導入として第2巻に収録されています。)

有限オートマトン

はじめに紹介される計算モデルは有限オートマトンと呼ばれるものです。ここで有限なものは記憶領域であり、この制約のためこのモデルの能力は他のモデルに対し限られています。 有限オートマトンの正式な定義は以下の5つの値の組で表されます。

  • 状態の集合
  • 入力アルファベットの集合
  • 遷移関数
  • 開始状態
  • 受理状態の集合

入力された文字列が受理状態で終了するときこれを"認識する"と言います。またある有限オートマトンで認識される文字列の集合(=言語)を正規言語と呼びます。つまりある有限オートマトンに対応する正規言語が1つ存在します。

この文字列の集合である言語に対して3種類の演算(和集合演算、連結演算、スター演算)を定義することができ、その総称を正規演算と呼びます。そしてこの正規演算を使って正規言語を表現したものを正規表現と呼びます。

決定性と非決定性

先の定義で表される有限オートマトンというのは決定性という性質を持ちます。非決定性の方が捉えやすいでしょう。ある入力に対して遷移先状態が複数存在し、枝分かれが起きるときこれを非決定的と言います。逆にどの入力アルファベットに対しても遷移関数が1つの状態を出力するとき決定性を持ちます。この2つを区別し決定性有限オートマトンDFA: Deterministic Finite Automata)と非決定性有限オートマトン(NFA: Nondeterministic Finite Automata)という名前がつけられています。また正規演算を使って簡潔化したNFAを一般化非決定性有限オートマトン(GNFA: Generaristic Nondeterministic Finite Automata)と言います。

直感的には非決定性有限オートマトンの方が表現力があるように感じます。しかし驚くべきことにこのDFAとNFAは能力の点において等価です。本書にはこの証明が記載されているので興味がある人は読んでみてください。このためDFAを使うかNFAを使うかはケースバイケースで使いやすい方を選ぶことになります。本書では正規演算の閉包性を証明するためにNFAが紹介されました。

ある言語に対応する有限オートマトンが存在するかどうか、つまり有限オートマトンの能力の限界、ある言語が有限オートマトンで認識可能かどうかはポンピング補題と呼ばれる定理を用いて背理法により確認することができます。

プッシュダウン・オートマトン

次に紹介されるのはさらに強力な言語を記述できる文脈自由文法(CFG: Context Free Grammer)とそれを認識する計算モデルであるプッシュダウン・オートマトンPDA: Push-Down Automata)です。この文脈自由文法では正規表現で表すことのできなかった再帰的な構造も扱うことができ、プログラミング言語の仕様やコンパイラといった応用例があります。この文脈自由文法を用いて記述された言語を文脈自由言語(CFL: Context Free Language)と呼びます。

文脈自由文法は以下の4つの値の組で定義されます。

  • 変数の集合
  • 終端記号
  • 変数 → 変数および終端記号、で構成される書き換え規則(rule)の集合
  • 開始変数

この文脈自由文法を設計する際のポイントは以下の4つです。

  • CFLを小さなCFLの和集合に分解して考える
  • 言語が正規であればDFAからCFGに変換する
  • 2つの部分文字列がお互いに関連するときのパターン
  • 再帰構造に対するパターン

1つの言語に対して様々に書き換え規則を表現することができますが、その中でも最も単純化された表現をChomski標準形と呼びます。

さて先ほどの有限オートマトンは記憶領域に制限がありましたが、この制限を取り除き無限の記憶領域を与えます。ただし今回はそのアクセス方法に制限があり、スタック(First In First Outのデータ構造)としてしか使用できないとします。この計算モデルをプッシュダウン・オートマトンと呼びます。PDAの定義は以下の6つの値の組で表されます。

  • 状態の集合
  • 入力アルファベットの集合
  • スタック・アルファベットの集合
  • 遷移関数
  • 開始状態
  • 受理状態の集合

遷移関数は状態の集合を返すため非決定性を持ちます。先に書いたとおりこのPDAにより認識される言語を文脈自由言語と呼びまたある言語に対しそれを認識するPDAが存在する時その言語を文脈自由言語と呼びます。

有限オートマトンと同様にポンピング補題を使うことによりPDAの限界=ある言語を認識するPDAが存在するかどうかを証明することができます。

チューリング機械

さてプッシュダウン・オートマトンには記憶領域へのアクセス方法に制限がありました。この制限を取り除き、テープ上に記録したどの領域にも自由にアクセス可能にした計算モデルをチューリング機械と呼びます。チューリング機械の持つ性質として、受理状態あるいは拒否状態に入った時点で停止すること、ループという永久に停止しない状態が存在することがあります。このチューリング機械はコンピュータに対する正確なモデルになっており、チューリング機械の能力の限界を調べることはコンピュータにできないことを知ることに繋がります。定義は以下の7つの値の組で表されます。

  • 状態の集合
  • 入力アルファベットの集合
  • テープ・アルファベットの集合
  • 遷移関数
  • 開始状態
  • 受理状態
  • 拒否状態

チューリング認識可能であるとはある言語に対し認識可能(受理・拒否・ループのいずれかの終了状態であることがわかる)なチューリング機械が存在することであり、チューリング判定可能であるとはある言語に対し判定可能(受理・拒否のいずれか)なチューリング機械が存在することを言います。

このチューリング機械にはいくつかの亜種が存在し、テープを2本もつなどそれぞれ変更点がありますが、自由なアクセスが可能な無限の記憶領域という本質は共通しており、一方でもう一方をシミュレート可能なため能力の点では等価です。

ある問題の解を求めるアルゴリズムがそれをチューリング機械上でのステップを示すことと等価であることをChurch–Turing提唱といいます。それによりある問題を解くアルゴリズムが存在するかどうかをチューリング機械の判定可能性により確かめることができます。

まとめ

ざっくりした説明になってしまいました。詳しくは書籍の方をご覧ください。それぞれの数学的証明もじっくり掲載されているので証明から理解したい人にもおすすめです。

2018年を振り返る

こんにちは。いつにも増して筆不精ですが年の瀬なので今年一年を振り返っておこうと思います。

昨年の振り返りにもあるように今年は効率的な学習を強く意識しました。

kentakudo.hatenablog.com

具体的には一年を四半期に区切りそれぞれテーマを絞って学ぶスタイルをとりました。それぞれ以下のテーマです。

それぞれ個別にみていきます。

1〜3月:デザインパターン機械学習

こちらにまとめてあります。

kentakudo.hatenablog.com

記事にあるように、もともとはデザインパターンとネットワークをテーマにする予定でしたがDL4USのコースに当選したため丸々二ヶ月機械学習を勉強していました。デザインパターンに関しては有名な本二冊(「オブジェクト指向における再利用のためのデザインパターン」「増補改訂版Java言語で学ぶデザインパターン入門」)を読んだもののよく理解できず、またネットワークも「UNIXネットワークプログラミング〈Vol.1〉」を途中まで読んでOS周りの知識が足りないためそこを補ってから読んだ方が早く理解できそうだという結論に達しました。機械学習はDL4USとCourseraのオンラインコースプログラマ向けの本をいくつか読んでかなり楽しく学べた一方、残念ながら根本的に興味が薄いなということを認識しました。機械学習を専門にすることは想像できないですが、機械学習には何らかの形で関わりたいと思っているのでさらに踏み込んで勉強したい分野です。

4〜6月:オペレーションシステム

こちらまとめです。

kentakudo.hatenablog.com

とても難しかったです。難しかっただけに「あ、わかったかも」という瞬間の気持ち良さも強く、機械学習とは対照的に勉強することでますます興味が増した分野です。(機械学習も難しかったんですけどね。。)Raspberry Piを使うというアイデアは勉強している途中に思いついたものですが「なにか作る」という点でとても学習効果の高いものだったので同じ形ではないにせよ他の分野を学ぶときにも活かせそうなアイデアだと思います。完成まで至らなかったですし、IoTという視点でも来年はもっとラズパイで遊ぼうと思っています。

7〜9月:テスト、オブジェクト指向、セキュリティ

こちらがまとめになります。

kentakudo.hatenablog.com

この三ヶ月間は「勉強したいと思っている残り物詰め込み期間」ということでテーマを三つ、それぞれひと月ずつ勉強しました。初めの二ヶ月は「テストとTDDはどう違うのか」という疑問から始まり、オブジェクト指向に到るまで関連の有名な本を中心に読んでいきました。実用の面から言って一番役に立った期間でした。TDDを日頃の業務で即実践できるので段違いに身に付くスピードが早かったです。オブジェクト指向を理解することで結果として1月に挫折したデザインパターンもかなり理解が進みました。セキュリティに関しては分野に触れた程度の理解に止まっており、もう一度学びたい、次はCTFにも出てみたい、と思っています。

10〜12月:デザイン、DevOps

当初はデザインのみを学ぶ予定でしたが本業の都合と、デザインにそこまで気持ちが向かなかったことがあり2つのテーマを平行して勉強する形になりました。結果としてどちらも中途半端になってしまい「一度に一つ」を守ることがいかに大切かを再認識しました。デザインはいくつか本を読んだのに加えDesignLab 101のオンラインコースおよびUAL: Central Saint Martinで一週間グラフィックデザインショートコースを受講しました。とくにショートコースは"mind blowing"な経験で始まる前は不安でいっぱいでしたが終わってみると一週間頭を使いっぱなしで楽しくてたまりませんでした。いきなりWebデザインやIllustratorを始めるよりもグラフィックデザインを学ぶ方が「デザインとはなにか」という点を学ぶことができるのでおすすめです。「デザイナーになろう!」とはなりませんでしたが、とても楽しかったのでタイミングがあれば違うコースを受講してみようかなと思います。最終的に目標としていたポートフォリオサイトのデザインはかろうじて達成できたかなと思うので興味ある方はぜひご覧ください。笑

読書リスト

昨年に続き読書リストをあげておきます。

  1. オブジェクト指向における再利用のためのデザインパターン
  2. Java言語で学ぶデザインパターン入門
  3. ITエンジニアのための機械学習理論入門
  4. プロフェッショナルシリーズ 深層学習
  5. 詳解 ディープラーニング TensorFlow・Kerasによる時系列データ処理
  6. Python Machine Learning — Second Edition
  7. はじめてのOSコードリーディング
  8. プログラムはなぜ動くのか
  9. 30日でできるOS自作入門
  10. Linuxのしくみ
  11. はじめて読む486
  12. Linux カーネル読解室
  13. BareMetal で遊ぶ Raspberry Pi
  14. はじめて学ぶソフトウェアのテスト技法
  15. 知識ゼロから学ぶソフトウェアテスト
  16. ソフトウェアテスト技法
  17. テスト駆動開発
  18. 実践テスト駆動開発
  19. The Art of Software Testing
  20. リファクタリング
  21. エクストリームプログラミング
  22. レガシーコード改善ガイド
  23. Agile Testing
  24. オブジェクト指向でなぜつくるのか
  25. クリーンコード
  26. アジャイルソフトウェア開発の奥義
  27. パターンハッチング
  28. ソフトウェアアーキテクチャ(POSA)
  29. エンタープライズアプリケーションアーキテクチャパターン
  30. プログラミング作法
  31. 不正アクセス対策
  32. 体系的に学ぶ 安全なWebアプリケーションの作り方
  33. おうちで学べる セキュリティのきほん
  34. この一冊で全部わかるセキュリティの基本
  35. 動かして学ぶ セキュリティ入門講座
  36. セキュリティコンテストチャレンジブック
  37. サイバーセキュリティプログラミング — Pythonで学ぶハッカーの思考
  38. ハッカーの学校
  39. HACKING:美しき策謀
  40. Object oriented software construction
  41. データベース実践入門
  42. インターフェイスデザインの心理学
  43. さよなら、インターフェイス
  44. なるほどデザイン
  45. 新しいシェルプログラミングの教科書
  46. レイアウト、基本の「き」
  47. 詳解シェルスクリプト
  48. Layout Essentials 100 design principles for using grids
  49. 「シェル芸」に効くAWK処方箋
  50. 入門vi
  51. You can draw in 30 days
  52. Ansible: Up and Running, 2nd Edition
  53. Terraform: Up and Running
  54. 初めて作るクラウドインフラ Amazon Web Service ネットワーク入門
  55. Amazon Web Service in Action
  56. AWS System Administration
  57. CentOS 7 構築・運用・管理パーフェクトガイド

計57冊

総評

昨年「来年学びたいこと」として

を挙げていました。

昨年紹介したこちらの記事および今年読んだ「本を読む本」におけるシントピカル読書、シントピカル学習を実践した結果、言語処理系には手をつけられませんでしたが体感として目指していたところの85%は達成していると思うので成功の年だったといっていいんじゃないかと思います。

来年は

取り組みたい課題が2つあります。

一つ目は積年の課題であるアウトプットです。これまで意識的にインプット偏重の学習をしていました。駆け出しのプログラマとして正しかったとは思うものの、アウトプットが苦手である以上言い訳である感じは拭えません。学習効率改善の余地としてアウトプットは最大のボトルネックである他、プログラマとしてやっていく以上もう少しプレゼンスがあった方が都合がいいなと思います。反応があった方が楽しいですしね。水物でもありますし気にしすぎもよくないので、期待値低めで頑張りたいと思います。

二つ目は専門性に関してです。昨年までのデタラメな学習からテーマを絞った学習にシフトして効率という面では大きく進歩しました。しかしいまだに「広く浅く」という印象が強く「これが僕の強みです」と言えるものを持っていないのがコンプレックスです。来年は一つのテーマに腰を据えて自分の強みにしていくことを始めたいなと思います。


諸々の事情がありここのところこれからについてモヤモヤ考える日々を過ごしています。大学を卒業して強い希望もなく"とりあえず"でプログラマを選んだ時に「3年間全力でやってやめてしまおう」と冗談半分で思っていましたがあっという間に3年半が経過してしまいました。「やり尽くした」という境地には至っていませんが機会に恵まれ3年間でとても多くのことを学べました。あいかわらずプログラマとしてやっていくことには強い希望もなく、それ故にプログラマとして到達できるところもたかが知れているなと思うんですけども他にやりたいことがあるわけでもないし、なんだかんだプログラマが向いているなとも思うので結局これまで同様に「走りながら考える」というのを続けるしかないかなというのが今の所の結論です。

プログラマとしてやっていくにしてもそれはそれで一つ違うフェーズに入るかなと思います。一つには「3年間」という意識が常にあったこと、もう一つはある程度自信がついてきたことです。これまでは「なんとか追いつかなくては」という意識でやっていたし、とくにメルカリという環境にあっては同年代で何歩も先にいる同僚がごろごろいる中でビハインドを取り返すという強いモチベーションがありました。一方常に「これじゃダメだな」と思っていたのは、いいプログラマというのはいいプログラムを書ける人ではなく、プログラムにより問題を解決する人だということです。もちろんもう知識は必要ないというつもりはないですがそれ自体には終わりがないことですしタイミングもいいのでそろそろ問題解決にフォーカスすべき時期にきたかなという感じがします。じゃあ具体的にどうするのと言われるとそれはまだよくわかってないんですけどね。特に僕はコミュニケーションもだいぶ苦手ですし自分に合った問題解決スタイルを探すのが当面の目標になりそうです。