大学院選びQ&A

無事に大学院のPBLの最終成果発表が終わり、卒業できそうなことがわかりました。
学業も無事に終わりましたので、春休みは無職を全力で楽しみます!

さて、本題です。
「大学院で情報系を学びたい!」となると、東京都立産業技術大学院大学(以後AIIT)と北陸先端科学技術大学院大学(以後JAIST)がよく候補として挙がります。
僕はAIITの学生なので、AIITの学生から見た比較をQ&A方式で紹介していこうと思います。
ちなみにJAISTの学生である父さんという方が「働きながら情報系の大学院を修了した 」というnoteを書かれていて、そちらにJAISTの様子が書かれているので併せて読むことをオススメします。

note.com

Q. コンピュータサイエンス(以後CS)の勉強をしたいです

A. JAISTに行きましょう

AIITではCSの授業は(ほぼ)ありませんし、取れる学位もCSではありません。
よってCSの勉強をしたい場合はAIITはオススメできません。

これは余談ですが、CSというと「データ構造とアルゴリズム」ばかりが推されていて、CSについて勘違いされてる方もいらっしゃるのではと思います。
正確ではありませんが、わかりやすく言うとCSとは「コンピュータに応用できる数学」のことです。
もしCSを勉強したいと思われている方がいれば、「本当に数学を勉強したいの?」と自問してみるといいかもしれません。

Q. 数学がわかりません

A. AIITがオススメです

JAISTはCSなので、普通に大学生レベルの数学の知識が求められるようです。
一方でAIITはCSではないせいか、統計と機械学習以外の授業では数学はほぼ求められません。

ちなみにAIITの入試は「小論文」「プレゼンテーション」なので、入試でも数学は問われません。

Q. 週末しか時間がとれません

A. JAISTがいいかも

JAISTは主に週末の金土日に授業が開講されるようです。
一方で、AIITは月〜土まで授業が開講されます。
なので、仕事の都合で夕方までに仕事を切り上げられない場合はJAISTのほうが良いかもしれません。

ちなみに、「日曜日くらいゆっくりしたい」という要望はおそらくAIITに行ってもJAISTに行っても叶いません。
最近の大学や大学院は僕らが昔在籍していたときよりも真面目になっており、ほぼすべての授業で課題が出されます。
もちろん課題は授業時間外でやることが前提になっているので、勤務時間と授業時間以外の時間を確保して取り組む必要があります。
さらに、課題の中にはチームで取り組むものもあり、社会人がチームを組んで時間の都合がつきやすいのなんて、日曜ぐらいしかないわけです。(土曜日は授業)
サラリーマンは週5日だけサラリーマンしてればいいのですが、学生は週7日、毎日が学生なのです・・・

Q. 勉強はしたいのですが、研究はしたくありません

A. AIITがオススメです

AIITは専門職大学院です。
専門職大学院はアカデミック色が薄く、AIITでは研究は必須ではありません。
代わりに1年間プロジェクト活動を行うPBLがあります。
このPBLについては、情報系ではプロダクト作成を行うことが多いです。

逆に研究をしたい人はAIITをオススメしません。
PBLの中で研究をして学会発表をするチームもありますが、非常に少数です。
また、PBL活動はチームで行うので、個人的に研究したいテーマがあったとしてもそれを研究できるとは限りません。
他のチームメンバーがNOと言う可能性があるからですね。
どうしてもやりたい研究がある場合、他メンバーの協力を得られるように色々と戦略を練っておくと良いと思います。

ちなみに、AIITで取れる学位は「専門職修士」になります。
普通の修士との違いは無いようです。
アメックスとセゾンアメックスの違いみたいなものでしょうか。

Q. お金がありません

A. 勉強が得意ならJAIST、苦手ならAIITがいいかも

JAISTの場合

JAIST奨学金が非常に充実しています。
成績が上位10%であれば、授業料が免除されるようです。
なので、成績優秀者をキープできるのであれば、受験料と入学金だけで済みそうです。

AIITの場合

一方で、AIITの場合は雇用保険制度の「専門実践教育訓練給付金」が使えます。
詳細な条件は厚生労働省のサイトで確認していただきたいのですが、

  • 雇用保険に入っている(または直近入っていた)
  • 36歳未満

の2つを満たしていると費用の50%、また、卒業後に雇用保険に入るとさらにプラスで20%を受け取れます。
つまり、学費が3割で済むということですね。
また他にも、成績優秀者向けの給付型奨学金や、都民向けの入学料半額などの制度があります。

参考程度にAIITの場合の具体的な数字を。
まず、そのまますべての入学金・授業料を払うと、

入学料   ¥282,000  
授業料 ¥1,040,800  
計     ¥1,322,800  

かかります。
ざっと150万くらいですね。

ここに各種制度を適用すると、

都民の場合   -¥141,000  
給付型奨学金 -¥520,000  
訓練給付金   -¥463,260  
計        -¥1,124,260  

支払い        ¥198,540  

となり、実質2年間で20万円程度で済みます。
MacBook Pro より安い!

JAIST, AIITどちらも

もちろんこれらの他にも貸与型の奨学金はあるので、お金がない場合は検討してみるといいかもしれません。

自分の軸で選ぶ

大学院ごとに色々と特色があるわけですが、結局は自分の中で軸を組み立てて、それをもとに選んでいくしかないわけです。
僕は研究したいテーマが特に無かったので、「AIITいいじゃん」となってそのままAIITに行き、そして結果として間違ってなかったかなと思います。

こういう選ぶという行為をするときには、アジャイルが思い起こされますね。
結局はトレードオフの世界であり、何を優先して何を捨てるのかを決めるだけです。
有名な言葉でいうところの「荒ぶる四天王」や「鉄の三角形」を考える必要があるわけです。(もちろん、四天王や三角形の要素は自分で考える必要はあります。)

そんな軸選びのひとつの判断要素になれば幸いです。

Goの勉強 関数

Goの勉強をやり始めたのでメモ。
プログラミング言語 Go」を読んでる。

宣言

func name(parameter-list) (result-list) {  
        body  
}  

パラメータと同様に返り値にも名前を付けることができる
その場合は返り値の名前のローカル変数が作られる

func pi() (pi float64) {  
    pi = math.Pi // 宣言なしで変数 pi を使える  
    return  
}  

パラメータを使用しない場合、 _ を使うか、名前を省略できる

func zero(int, int) int {  
    return 0  
}  

func zero2(_ int, _ int) int {  
    return 0  
}  
  • Go にはデフォルト値や名前付き引数はない
  • 引数は値渡しされる(コピーを受け取る)が、間接的に参照されているものは影響を受ける可能性がある
  • 実装がない関数は Go 以外で実装されている

複数戻り値

複数戻り値はそのまま複数パラメータとして使用できる

func findLinks(url string) ([]string, error) {  
}  

log.Println(findLinks(url))  

戻り値にうまく名前付けをすることができれば、関数の結果の意味をドキュメント化することができる

func Size(rect image.Rectangle) (width, height int)  

エラー

  • Go にも例外機構はあるが、バグであることを示す本当に予期されていないエラーを報告するために使われ、予期されるエラーには使用されない
  • 関数がエラーを返した場合、エラーに対して対応するのは呼び出し元の責任である
  • エラーメッセージは連鎖されることが多いので、先頭を大文字にしたり改行を入れるべきではない
  • ファイル読み込み時にこれ以上入力がない場合にEOFがエラーとして返される

関数値

関数は他のプログラミング言語と同様に関数を変数に入れることができる

func square(n int) {  
        return n * n  
}  

f := square  
fmt.Println(f(3))  
  • 関数型はシグネチャで判断される。つまり func(int)func(int, int) は別の型
  • 関数型は nil と比較できるが、他の値とは比較可能ではない

無名関数

名前付き関数はパッケージレベルでだけ宣言できるが、関数リテラルはすべての式内で使用できる

strings.Map(func(r rune) rune { return r + 1 }, "HAL-9000")  

無名関数の外側の変数を参照できる。

func squares() func() int {  
        var x int  
        return func() int {  
                x++  
                return x * x  
        }  
}  

無名関数を再帰的に呼び出すためには、先に変数を定義し、その後に代入する必要がある。

無名関数はその瞬間の変数の値を補足するのではなく、変数自体を補足するので注意。

funcs []func()  
for _, item := range items {  
        funcs = append(funcs, func() string { return item })  
}  

for _, action := range funcs {  
    fmt.Println(action())  
}  

この場合、 items の最後の要素がずらずらと並ぶだけである。

可変個引数

  • 可変個引数はスライスで渡ってくる。
    • ただし、シグネチャとしては可変個引数とスライスは違う。

遅延関数呼び出し

  • defer を使用すると、その文は return のタイミングで呼ばれるようになる。

パニック・リカバー

  • panic を使用することで、システムをクラッシュさせることができる。
  • panic が使用されると、クラッシュされる前に遅延呼び出しが行われる。
  • recover を使用するとパニック状態を解消できる。
    • 一般的な規則として、他のパッケージのパニックからの回復を試みるべきでない。

Goの勉強 コンポジット型

Goの勉強をやり始めたのでメモ。
プログラミング言語 Go」を読んでる。

配列

  • 固定長で型が同じ必要がある
  • 以下のように宣言できる

      var a [5]int  
      var b [5]int{1, 2, 3, 4, 5}  
      var c [...]int{1, 2, 3, 4, 5}  
      var d [...]int{99: -1}  
    
  • 初期値がない場合はそれぞれの要素にゼロ値が適用される
  • == で比較可能
  • 関数の引数として配列を渡すと、参照ではなくコピーが渡される

スライス

  • 可変長で型が同じ必要がある
  • スライスにはポインタ、長さ、容量がある
  • 配列の部分配列みたいなもの
    • スライスには基底配列がある
    • 以下のようにスライスを生成すると同じサイズの基底配列が自動的に生成される

      s := []int{0, 1, 2, 3, 4, 5}  
      
  • スライスは == で比較不可能
    • slice == nil のみ比較可能
      • ただし、空かどうかを調べたい場合は len(slice) == 0 を使う
  • スライスのゼロ値は nil
  • make を使用すると型、長さ、容量を指定してスライスを生成できる
  • append を使うことでスライスに値を追加できる
    • append した結果の基底配列が、元のスライスの基底配列と同じかどうかはわからない

マップ

  • ハッシュテーブル
  • キーと値はそれぞれで型を指定する必要がある
  • キーの型は == で比較可能でなければならない
    • 精度や NaN があることから、 float 系をキーで使うことは推奨されない
  • 以下のように作成できる

    go m := make(map[string]int) var m map[string]int{ "taro": 11, "jiro": 8, }

  • delete を使用して要素を削除できる
  • 存在しないキーにアクセスするとゼロ値が返る
  • マップに要素が存在するかについては以下のようにチェックする

      item, ok := m["saburo"]  
      if !ok {  
          // ...  
      }  
    
  • マップの要素のアドレスを取得することはできない
  • マップをループした際の取得順はランダムになる

構造体

type Student struct {  
    ID   int  
    Name string  
}  

のように宣言できる。

  • 名前付き構造体は自身のフィールドに同じ型のフィールドを持てない
    • 持ちたい場合は自身の型のポインタを使う
  • 空構造体 struct{} を使う人もいるが、筆者はあまり好きではないらしい
  • すべてのフィールドが比較可能であれば、構造体も比較可能である
    • よって、マップのキーに構造体を指定することもできる
  • 無名フィールドを使うことで、ネストされた構造体でも短いドットでアクセスできる
    • デリゲーションみたいなイメージ?
    • ただし、本当に無名ではなく、暗黙的に無名フィールドの型名と同じ名前が割り当てられている
  • フィールドタグを付けることで、メタデータを付与することができる

      type Movie struct {  
          Year int `json:"released"`  
      }  
    
    • 慣習的に key:"value"の形式で書く
    • JavaDocみたいな感じかな

テンプレート

  • テキストテンプレートを使うことで文字列に変数を埋め込むことができる

      const templ = `合計{{.TotalCount}}件  
      ---  
      {{range .Items}}  
      ID: {{.ID}}  
      Title: {{.Title}}  
      {{end}}  
      `  
      text, err := template.New("text").Parse(templ)  
      err := text.Execute(os.Stdoutm items)  
    
    • {{.}} で現在の要素のアクセスできる
    • {{range}} {{end}} でループ
    • めちゃくちゃ使いづらい
      • JSやPHPに比べると面倒
      • IDEが補完してくれない
  • HTMLテンプレートを使うことでエスケープをしつつ文字列に変数を埋め込むことができる
    • 変数の型を template.HTML にすることで、エスケープなしで出力することができる

Goの勉強 基本データ型

Goの勉強をやり始めたのでメモ。
プログラミング言語 Go」を読んでる。

整数

  • Goの整数には符号付き、符号なしがある。
  • runeint32 の同類語で、 byteint8 の同類語
    • runeUnicodeのコードポイントであることを強調し、 byte は生データであることを強調する。
  • uintptr はポインタの値のすべてのビットを保持する。

浮動小数点数

  • ゼロ除算の結果は NaN になる。
  • NaN == NaNfalse になる。

複素数

仕事では使わなさそう。

ブーリアン

JSのような以下のコードは書けない。

fmt.Print(1 || 0)  
// invalid operation: operator || not defined on 1 (untyped int constant)  
// JSの場合は 1 が返る  

文字列

  • 文字列はスライスのようにアクセスできるが、何バイト目であるかであって何文字目かではない。
  • 文字列連結は + を使う。(どこかの言語のように . で繋げない)
  • "s" は文字列リテラルで、エスケープシーケンスが使える。
  • `s` は生文字リテラルで、エスケープシーケンスが使えない。

定数

  • 定数はコンパイル時に評価できる値
  • const宣言では iota が使える。 iota はゼロから始まり、順番に個々の項目ごとに1増加する。

Goの勉強 プログラム構造

Goの勉強をやり始めたのでメモ。
プログラミング言語 Go」を読んでる。

名前

  • 大文字と小文字は区別される。
  • 予約語と事前宣言がある。 trueやintは事前宣言なので、宣言で使うことができる。
  • キャメルケースで書く

ポインタ

ポインタはアドレスを指す。
以下のようなコードも安全

var p = f()  

func f() *int {  
  v := 1  
  return &v  
}

f() を呼び出した後も引き続きローカル変数 v のアドレスが参照され、 v も破棄されない。

タプル代入

x, y = y, x  

のようなことができる。

型宣言

type PersonName string  

のようにして型を作ることができる。

name := PersonName("たなか")  

のように型変換を行うことでその型のインスタンスを作れる。

パッケージ初期化

init 関数を使うことでそのファイルのプログラム開始時の挙動を設定できる。
init 関数は呼び出すことも参照することもできない。

Goの勉強 チュートリアル

Goの勉強をやり始めたのでメモ。
プログラミング言語 Go」を読んでる。

インストール

公式サイトからインストールできる。
前にやったときはインストーラなんてなかった気がするけど、最近はあるみたい。

GOPATH, ROOTPATH

よくわかってないけどGoLandの場合は設定すると動かなくなる。

フォーマット

とりあえず gofmtgoimports を設定しとけば良さそう。
GoLandではFileWatchers で設定できる。

変数

var s string  
s := ""  

のように書く。
初期値を設定しなかった場合はゼロ値が入るので、上の2つは同じ意味。

定数

const (  
    seconds  = 60  
    minutues = 60  
    hours    = 24  
)  

のように書く。コンパイル時に値が確定しているものを定数として扱う。

条件分岐

if

if a > 0 {  
}  

また、変数宣言なども同時に行える。

if err := request.ParseForm(); err != nil {  
}  

こちらのほうがスコープが短くなるので良いらしい。

switch

switch variable {  
case 1:  
    return "one"  
case 2:  
    return "two"  
default:  
    return "other"  
}  

PHPと違って次のcaseには抜けない。次のcaseに抜けさせたい場合は fallthrough を使う。

タグなしswitchもある。

switch {  
    case num > 0:  
        return "正の数"  
    case num == 0:  
        return "ゼロ"  
    default:  
        return "負の数"  
}  

これは便利。PHPにもきてほしい。

ループ

とりあえず以下の2通り。whileなどない。

for i := 0; i < 10; i++ {  
}  

for index, value := range array {  
}  

引数

基本は値渡しではなく参照渡しになる。
ポインタを使うケースもあるが、使い分けはまだわかってない。

コマンドライン引数

args := os.Args()  

で取れる。

マップ

items = make(map[int]string)  

のように書ける。PHPのように何でも有りの連想配列ではなさそう。

ゴルーチン

非同期処理。

func main() {  
    ch := make(chan string)  
    go fetch("https://example.com", ch)  
    go fetch("https://example.org", ch)  
    fmt.Println(<-ch)  
    fmt.Println(<-ch)  
}  

func fetch(url string, ch chan<- string) {  
    res, err:= http.Get(url)  
    if err != nil {  
        ch <- fmt.Sprint(err)  
        return  
    }  
    ch <- res.Status  
}  

のように書く。
go でゴルーチンを作成し、それぞれのゴルーチンが非同期で動作する。
channel を使ってやり取りをする。いずれかのゴルーチンがチャンネルに対して受信・送信をするとそのゴルーチンは待機状態になり、他のゴルーチンが受信・送信することで処理が再開される。

無名関数

handler := func() {  
}  

名前付き型

type Point struct {  
    X, Y int  
}  

noshと私

たまには技術以外のことでも。

最近、 nosh を利用してます。

nosh.jp

僕は5月頃から使っていて、なんだかんだで既に90食くらい注文しているっぽい。
だいぶいい感じなので紹介したいと思います。

nosh is 何

簡単に言うと、「定期的におかずを届けてくれるサービス」。

Twitter とかで色んな漫画家がPRしてるので有名かも。

  • 定期的におかずが届く
  • おかずは主菜1品と副菜3品のセット
  • 主食(ごはん)は付いてない
    • パンはメニューとしてあるけどお値段高め
  • おかずは冷凍食品(なのでクール便で届く)
  • 届く間隔や個数は自由に設定できる
  • メニューは自分で選ぶこともできるし、おまかせにすることもできる
  • サブスクしかない
    • お試しで1回注文したい人は、サブスクに入って注文して即やめる感じになりそう?

自分はこうしてる

僕は6食/週で注文してます。
昼晩の食事を考えると週に14食なので、だいたい半分はnoshにしてる計算。
残りは学食を使ったり、外食したりしてます。

メニューは選ぶのが面倒なのでおまかせにしてます。
おまかせは結構偏りが多く、半分が鶏料理になってたりすることもあります。
僕は偏りがあってもあまり苦じゃないタイプなのですが、気にする人は自分でメニューを選択したほうがいいかも。

で、食事としてはだいたい以下のセットにして食べてます。

  • おかず: noshを解凍
  • ごはん: 事前に炊いて冷凍しといたのを解凍
  • 汁: インスタントのスープをつくる

特にスープを付けてからはだいぶいい感じになりました。
汁物大事。

nosh を使って良かったこと

食事を考える手間が省ける

自分的にはこれが一番大きいです。
「今日の晩ごはん何食べようかな」を考える手間が省け、冷凍庫の一番上に入ってるやつを食べるだけ。

特に忙しい時は、自分の世話のコストがなかなか馬鹿にならないし、かといって自分の世話をおろそかにすると巡り巡って効率が下がります。
食事について考えなくていいのは大事ですね。

普通に美味しい

不味くはない。美味しい。
ただ冷凍食品なので、基本的に水分多めです。
パリパリやサクサクとはご縁がないです。

痩せた

これは僕だけかもしれないですが、1食あたりの食事量がコンスタントになるので痩せました。
食事の量も、女性向けな感じの量で、男性的にはちょっと足りないぐらいかもしれません。

お腹は空くんですが、外に買い出しに行く気力も出ないので、結果的に痩せた感じですね。
無気力の勝利。

容器がかさばらない

1食ごとに別々の容器に入ってるのでゴミが増えそうな感覚はありますが、容器は重ねることができて、全然かさばりません。
僕は食べ終わったら軽くゆすいで、6食分の容器を重ねてまとめてポイしてます。

noshを使う際に気をつけたいこと

主食は自分で用意する必要がある

noshで届くのはおかずだけなので、ごはんやパンは自分で用意する必要があります。
noshでも一応パンのメニューはあるんですけど、1食あたりの金額を考えると割高です。

僕は週末に3合くらい一気にごはんを炊いて、冷凍してます。

冷凍庫を圧迫する

一人暮らし用の冷凍庫付き冷蔵庫を使ってる場合、6食入れるとパンパンです。
他の冷凍食品を入れておくスペースもないです。
なので、noshを使う際には冷凍食品はあらかじめ消費しといたほうがいいし、noshを使いはじめると冷凍食品は買えません。

洗い物は無くならない

noshだけで食事が完結しないので、基本的に洗い物は発生します。
でも調理器具を洗う必要がないのでラク。(炊飯器くらい)

安くはない

僕の場合、送料込みで6食で5000円くらいなので、1食800円くらい。
ここにごはん代とスープ代が加算されるので、外食と同じくらいのお値段はしてます。

1度の配達の量を増やせば少しはマシになるんでしょうが、そうすると冷凍庫のスペースが足らなくなるので、あまり現実的ではないです。
noshのために冷凍庫を別で買うのも微妙ですし、そもそも置くスペースがないです。

健康にいいのかはわからない

添加物とかどうなんだろう、気にしたことないからわからない。
でも、たとえ副菜が付いてても野菜の摂取量は圧倒的に足りないはず。

引きこもりが加速する

ただでさえリモートワークで引きこもり気味なのに、noshを使うとさらに引きこもりが加速します。
外食するためには外に出る必要があるし、自炊するためには食材を買うために外に出る必要があるんですが、noshにすると外に出る必要が全くありません。

まとめ

という感じで、良い部分もあれば気をつけたい部分もあるんですが、僕には結構フィットしていていい感じです。
たぶん普段から自炊してる人には向かないでしょうし、普段から外食や中食してる人には結構良いんじゃないかなと思います。