Angular入門 2日目

社内ツールをバックエンドをGo(goa)で、フロントエンドをAngularで作ることにした。

2日目。

今日やったこと

編集画面のフォーム周り

モデルとフォームをバインディングする辺りのコードを書いた。

「これが噂に聞いていた双方向バインディングかぁぁぁぁ!!!」とちょっと感動した。

formタグのところだけ別のComponentにして切り出してみて、データの渡し方(@Inputあたり)を確認した。でも、なんかめんどくさくなっただけかも。

モデルの修正

管理すべきデータを間違えていたので、モデルを作り直した。

Typescriptの型チェックのおかげで、ダミーデータが誤っているのもすぐ分かって快適だ。

Serviceを作った

チュートリアルを参考にしてServiceを作ってそこからダミーデータを返すようにした。
HTTP - ts - TUTORIAL

PromiseをServiceとComponentで受け渡ししてるんだけど、直接、特定の型の配列を返してはいけないんだろうか?

あと、Observerableの方が良いらしい?
Angular2のHttpモジュールを眺めてベストプラクティスを考える - Qiita

これを見てPromiseを使わないようにやろうとしてるとこで、上手くいかなくて時間切れ。なんか勘違いしてるっぽい。

次回はこの辺対応して、新規と削除までの一通りの操作できるようにしたい。

VSCodeに乗り換えた

Angularをやるにあたって、VimでTypescriptとかの開発用の設定をしないと行けないと思っていたけど、せっかくなので、何度か試しては辞めていたVSCodeを使ってみることにした。

今日でまだ2日目だけど。

VSCodeを以前試して使わなかった理由として、複雑なウィンドウ分割ができなかったからだけど、今回そこは諦めることにした。(VimではT字に分割することが多い)

アップデートしたらメニューとかが日本語になっていた。ローカライズプラグイン入れた覚えはないので、本体で対応したんだと思う。

プラグインはGo関連は以前入れていたので、AngularやTypescript関連をとりあえず追加した。

ターミナルがなんか使いやすくなっている感じ。
ng serve しておいて、エラーがあったらすぐ気付けるので良い。

コード補完も特に問題ないし、関数の簡単なヘルプが出てくれたりするのも良い。

たぶんここまで書いたことは、Vimでもプラグインを活用すれば、充分できることだと思う。ただ、その辺設定するのに疲れてしまったのも本音だ。

そういえば、メジャーなエディタにはVimキーバインドが使える系のプラグインがあるが、完全に再現できないだろうし、入れないことにしてる。

だけど、ErgoDoxにして、カーソルキーをfn+hjklで使えるようにしたからスムーズに移行できたのかもしれない。

Angular入門 1日目

社内ツールをバックエンドをGo(goa)で、フロントエンドをAngularで作ることにした。

今日やったこと

angular-cliのインストール

とりあえずこれがあれば良いっぽい。

CSSフレームワークの選定

css フレームワーク」とかでググって、見た感じが良さそうで、使いやすそうなやつを探した。

Bulma: a modern CSS framework based on Flexbox というのを使うことにした。

css周りは5年ぶりくらい。flexboxというやつでレイアウト組めるらしく、なんかすげ〜と思った。

画面作成

とりあえずバックエンドとの連携は置いといて、画面を作り込んで行くことにした。

  • プロジェクトの一覧画面
  • プロジェクトの編集画面

を作った。ほとんど見た目の調整。

ページ毎に

  1. ng g component hoge でcomponentを作る
  2. HTMLを編集
  3. routerの設定に追加

って感じでやってるけど、これで良いのかわからん。

新規作成画面は、編集画面に空のオブジェクトを渡せば良いかな。 たぶん、routerで新規用のパスを設定して、そこの初期値で空のオブジェクトを指定すれば良いんではないかという気がする。

それともformの部分を切り出して、新規と編集はそれを利用するcomponentにする、みたいなのが良いだろうか。

雑感

Angularのフルスタック感がRailsのそれと近い感じがして、初めは拒否反応があったんだけど、しばらく触ってみると面白くなってきた。

久しぶりのjavascriptと思っていたけど、Typescriptはまたなんか違う感じだった。型があるので、安心感がある。

Goと過ごした1年間

今日で仕事納めだったので、振り返っておく。

今年はGoのコードをたくさん書けた1年間だったと思う。

  • サービス基盤の一部をGoで開発した
  • 新人研修の主な言語としてGoを教えた
  • 既存のRailsで作ったサイトのリプレースをGoでやった
  • 社内で使うツールをGoで作っている
  • goaを触り始めた

サービス基盤の開発

去年の後半から始まって、今年の3月末にリリースが完了した。モバイルアプリ用のpush配信周りの実装を担当したが、APNSに関連してHTTP/2を使ったやりとりとかも経験できて面白かった。

周囲の特に上司の理解と協力もあって、社内でGoを使ったプロジェクトの実績が作れたのは大きかった。 前例ができたからか、以降「Goでやります」と言いやすくなったし、リプレースのプロジェクトにもつながったと思う。

新人研修

自分のチームに配属になったのが6月からで、それからGoを教えて、社内で使うツールを作ってもらった。とりあえず年末を目処にそこそこ使える形のあるものはできたので良かったと思う。

研修が始まる前には、プログラミング自体を経験したことがない、という人にGoを教材としてプログラミングを教えることが正解なのかどうか、かなり悩んだ。

現状Goでの、プログラミングが未経験という人に向けた情報が少ないと思う。なので、参考になる事例も見当たらず、本当に研修を全うできるのか?という不安があった。

正直言うと(本人にも伝えたが)途中で辛くなって、Railsでなんかパッと動くやつを課題に設定した方が、研修としては面白かったのでは?とか思ったこともあって、モチベーションが低かった時もあった。

最終的には、そこそこのコードは普通に書けるねという感じになってきているし、良かったと思う。

研修をしてわかったことは、新人でもGoで書いたコードは普通に質が高いというか、誰が書いても同じようなコードになるのが不思議だなと。瑣末なところはもちろん色々あるんだけど、おかしなコードを書いているってことは感じたことがない。

リプレース

Railsで作ったサイトをリプレースした。もともと小規模なサイトだったので、Goで一から作ろうということになって、3サイトをリプレースした。

リリースしてからリソースのグラフをたまに見ているが、Railsで起きていた徐々にメモリ消費が増えていくということもなく、安定している。

サーバーのスペックを落としても充分さばけると思うし、お客さんの費用に直結するので、省リソースでサイトが運用できるというのは良いことだと思う。

ついでに社内のサービスと接続するためのAPIクライアントも作れたので、ますますGoでプロジェクトを進めやすくなった。

社内ツールもろもろ

chatops(ってもう死語?)とかその辺でslackのbot作ったりとか、他にも細々としたツールを作っていて、なんか作る時にはGoで作るようにしている。

やっぱりポータビリティというか、コンパイルしてコピーして動くっていう手軽さは大きい。

goa

Goでウェブアプリケーション作るときに、あまり大きな(リフレクションを使うような黒魔術的)フレームワークは採用したくない。でもチーム開発する以上ある程度のルールは必要で、goaを使えばその辺を解消できると思う。

例えば、基本的なバリデーションとか細々した実装がそこそこあってちょっとしんどい、みたいなところがラクできそう。

goa自体はAPIサーバーを前提としていると思うけど、管理画面とかHTMLを返したいし、その辺を独自ジェネレーターとかDSL拡張とかで対応できないか試行錯誤しているところ。

apexと組み合わせてAWS lambdaで動かしたりしたい。

おわりに

特にまとめはない。

Goをやるぞ!と言って実際に実績が積めているのは大変嬉しいことだし、もっと社内でも普及活動をしていこうと思う。

続・GoでパスワードなどをPrintfで出力させたくない

前回、GoでパスワードなどをPrintfで出力させたくない - kawaken's blog というのを書いたけど、 その後 GoStringer というインターフェースがあることを知ったので再度試してみた。

前回のおさらい

前回上手く隠蔽できずに出力されてしまったのが、以下。 %+v だと出力されないんだけど、%#vだと出力されてしまう…

type Password string

func (p Password) String() string {
    return "FILTERED"
}

type User struct {
    Name     string
    Password Password
}

func main() {
    u := &User{
        Name:     "namae",
        Password: Password("pass"),
    }

    fmt.Printf("%#v", u)
    // &main.User{Name:"namae", Password:"pass"}

}

https://play.golang.org/p/1BT9E4dM17

GoStringerを実装する

package main

import (
    "fmt"
)

type Password string

func (p Password) String() string {
    return "FILTERED by String"
}

func (p Password) GoString() string {
    return "FILTERED by GoString"
}

type User struct {
    Name     string
    Password Password
}

func main() {
    u := &User{
        Name:     "namae",
        Password: Password("pass"),
    }

    fmt.Printf("%#v", u)
    // &main.User{Name:"namae", Password:FILTERED by GoString}

}

https://play.golang.org/p/H_ccstzjCC

よっしゃー!うまく隠蔽された。

これでログとかに意図せず出力されることが回避できそう。

GoでパスワードなどをPrintfで出力させたくない

RailsのLoggerだとリクエストパラメータにパスワードなどが含まれていると、FILTEREDといった感じで生の情報が出力されない。

Goでも、例えば、以下のような構造体Userを fmt.Printf("%#v", u) で出力したときに Password が隠れて欲しい。

type User struct {
    Name     string
    Password string
}

ノーガード

特に何もしないと、そのまま出力される。

type User struct {
    Name     string
    Password string
}

func main() {
    u := &User{
        Name:     "namae",
        Password: "pass",
    }

    fmt.Printf("%+v", u)
    // &{Name:namae Password:pass}
}

https://play.golang.org/p/HZuuaXwS4O

そりゃそうだ。

Password を Stringer にしてみる

fmtで出力されるとき、StringerだとStringが呼ばれるはず。

type Password string

func (p Password) String() string {
    return "FILTERED"
}

type User struct {
    Name     string
    Password Password
}

func main() {
    u := &User{
        Name:     "namae",
        Password: Password("pass"),
    }

    fmt.Printf("%+v", u)
    // &{Name:namae Password:FILTERED}
}

https://play.golang.org/p/hmNsB0yrbk

お、できた!?

"%#v" には勝てない

%+v だと出力されないんだけど、%#vだと出力されてしまう…

type Password string

func (p Password) String() string {
    return "FILTERED"
}

type User struct {
    Name     string
    Password Password
}

func main() {
    u := &User{
        Name:     "namae",
        Password: Password("pass"),
    }

    fmt.Printf("%#v", u)
    // &main.User{Name:"namae", Password:"pass"}

}

https://play.golang.org/p/1BT9E4dM17

ポインタ型にしてみる

ポインタ型にしたらどうだろう。

type Password string

func (p Password) String() string {
    return "FILTERED"
}

type User struct {
    Name     string
    Password *Password
}

func main() {
    p := Password("pass")
    u := &User{
        Name:     "namae",
        Password: &p,
    }

    fmt.Printf("%#v", u)
    // &main.User{Name:"namae", Password:(*main.Password)(0x1040a120)}

}

https://play.golang.org/p/_pcSzrx64p

アドレスが出力されるので、とりあえずパスワードはわからない状態になった。

まとめ

  • とりあえずStringerにする
  • 構造体のフィールドとしてはポインタ型にしておく

で良いんだろうか?

もっと良い方法ないだろうか。