その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

「公式ガイドブック SORACOMプラットフォーム」が出ます

公式ガイドブック SORACOMプラットフォーム

公式ガイドブック SORACOMプラットフォーム

出ます,出るのです.
ソラコムプラットフォームの概観やその設計思想,実際のユースケースに応じた参考アーキテクチャなどが満載されている楽しい本です!!
ソラコムをすでにご利用の方にもそうでない方にもお役立ちな情報が記されていると確信しております.

いやー久々に商業誌に文章を書きました (WEB+DB PRESS Vol.81以来なので5年ぶりくらいでしょうか?).とは言っても本当にほんの一部なのですが……

手に取ってもらえると嬉しいです,よろしくお願いします!!

YAPC::Tokyo 2019に参加してきた & LTしてきた #yapcjapan

遅くなりましたが,表題のとおりです.YAPCが東京に凱旋してきたので参加してきました.

yapcjapan.org

じつはこのような形で事前に関わっていたりもします:

blog.yapcjapan.org

んで,LTをやってきました.資料は以下です.

AWS LambdaでPerlを動かすというテーマのLTで,これはかつてブログにも書いた内容だったのですが,ここらで一丁LTにでもしてみるか〜となり,なったという感じです.

ありがたいことにベストLTをいただきました.大感謝です.


さて今回のYAPCはなんやかやPerlの話題が多く,まだまだホットではあるな〜とは思うものの,charsbarさんの発表にあったように「年々CPAN Authorの数が減少している」など少々寂しい話題もあり,いろいろ考えさせられるものがある回でした.とはいえtokuhiromさんのキーノートにもあったように,なんやかやperlは便利なので今後も使っていく気はしており,まあここらへんはやっていくことになるのであろう……

次回の開催地・会場はまだ未定とのことでしたが,楽しみに待ちたいと思います.今回も運営の皆さんお疲れ様でした,ありがとうございました.

Jacksonでtop levelのpropertyを省略してMap<K, V>をserializeしたいんですけどってとき

public static class Something {
    private Map<String, String> prop;
}

をJacksonでserializeすると

{
  "prop": {
    "foo": "bar"
  }
}

と,トップレベルにpropのようなpropertyが出てくるので微妙……となるシチュエーションがまれによくあります.

で,どうすると良いかというと @JsonUnwrappedを使うという方法がまず考えられると思うんですが,これは問題があって期待通りに動かない.かれこれ6年くらいチケットがオープンになっています: @JsonUnwrapped not supported for Map-valued properties · Issue #171 · FasterXML/jackson-databind · GitHub

public static class Something {
    @JsonUnwrapped
    private Map<String, String> prop;
}

つまりこれは動かない.というわけでどうするかと言うと,チケット中にも示されているように@JsonAnyGetterを使うという方法があります.

public static class Something {
    private Map<String, String> prop;

    // workaround: https://github.com/FasterXML/jackson-databind/issues/171#issuecomment-117794241
    @JsonAnyGetter
    public Map<String, String> getProp() {
        return prop;
    }
}

このようにすると,

{
  "foo": "bar"
}

というふうにトップレベルのpropertyが省略された,MapのKey-Valueがそのままserializeされることとなります.よかったよかった.

gowrtr - goコード生成支援ライブラリ

gowrtr (go writerと発音します) というgoのコード生成支援ライブラリ (ジェネレータ群) を書きました.

github.com

Synopsisに書いたように,

package main

import (
	"fmt"

	"github.com/moznion/gowrtr/generator"
)

func main() {
	generator := generator.NewRoot(
		generator.NewComment(" THIS CODE WAS AUTO GENERATED"),
		generator.NewPackage("main"),
		generator.NewNewline(),
	).AddStatements(
		generator.NewFunc(
			nil,
			generator.NewFuncSignature("main"),
		).AddStatements(
			generator.NewRawStatement(`fmt.Println("hello, world!")`),
		),
	).
		EnableGofmt("-s").
		EnableGoimports()

	generated, err := generator.Generate(0)
	if err != nil {
		panic(err)
	}
	fmt.Println(generated)
}

のようなコード (ジェネレータ) を書いてやると

// THIS CODE WAS AUTO GENERATED
package main

import "fmt"

func main() {
        fmt.Println("hello, world!")
}

というようなコードが生成されるというようなライブラリです.
この例だと生成結果があまりにシンプルなので,逆に記述量が増えてアレな感じになっていますが,ある程度生成結果が大きくなるようなものだと便利に使えるはず……です (後述のImmutabilityの話題もご覧ください).詳細につきましてはGoDocをご覧ください (Exampleも示してあります).


特徴としては

  • 生成したコードにコードフォーマッタ (gofmt, goimports) を適用することができる
  • ライブラリの各メソッドはimmutableに振る舞う

というものが挙げられます.

前者は生成結果にgofmtをかけることによって「生成コードのフォーマットが統一される」というメリットと「Syntaxチェックができる」というメリットを享受できることに加え,goimportsを適用することによって「コード生成のためのジェネレータを書いているときに『何をimportするか』を考えなくても (記述しなくても) 良くなる」というメリットを得ることができます.

後者については各ジェネレータの各メソッドが暗黙的に内部状態を変更しないので,利用者はジェネレータのスナップショットを任意のタイミングで取得することができます.これによりジェネレータの再利用が可能になると同時に,そこからジェネレータを派生させていくようなコードが書きやすくなるというメリットがあります.




さて,Javaにはsquare/javapoetというライブラリがあって,これはJavaコードの生成支援を行うライブラリなのですが,gowrtrはこのライブラリに着想を得て作られました.
まだできたてのライブラリなのですが,一部の自前環境に適用したところうまくワークしているのである程度動くのではないでしょうかというステータスです.が,もしかしたら足りない機能や記法のサポートがあるかもしれません.ご意見・ご要望をお待ちしております.

ぜひご利用くださいませ.

go-errgen書いた

goのstructにエラー定義を書いておけば良い感じで「エラーを返却する関数」をコード生成するツールであるgo-errgenを書きました.

github.com

Synopsisに書いてあるとおり,

package mypkg

//go:generate errgen -type=myErrors
type myErrors struct {
	FooErr error `errmsg:"this is FOO error"`
	BarErr error `errmsg:"this is BAR error [%d, %s]" vars:"hoge int, fuga string"`
}

みたいな感じでstructにエラー定義を書いて,go:generate を設定してから go generate を実行すると

package mypkg

import "errors"
import "fmt"

func FooErr() error {
	return errors.New("[ERR-1] this is FOO error")
}

func BarErr(hoge int, fuga string) error {
	return fmt.Errorf("[ERR-2] this is BAR error [%d, %s]", hoge, fuga)
}

func MyErrorsList() []string {
	return []string{
		`[ERR-1] this is FOO error`,
		`[ERR-2] this is BAR error [%d, %s]`,
	}
}

という感じのコードが my_errors_errmsg_gen.go として生成されるというツールです.

これはエラーメッセージに「通し番号が付いたprefix」を付与したerrorを返却する関数をコード生成します.もし errmsg に加えて vars パラメータが定義されている場合はその値が関数の引数パラメータとして利用され,かつ fmt.Errorf() によってsprintf互換のプレースホルダにbindされます.


主なモチベーションとしては,

  • 集権的にエラーを定義して管理したい (エラー定義が散在するとつらい)
  • エラーの特定を行う際にエラーコードを利用したい

というのがあり,特に後者はいろいろなチームから多く利用されるコンポーネントであれば必須に近い機能でしょう.で,集権的にエラーを管理するにしても,手でエラーコードを記述するようにしたところでうっかりミスってしまう可能性もありますし (例えばエラーコードを重複させてしまうとか),そこんところは機械的にやりたいな〜という気持ちからerrgenを作ったという感じです.

errgen -type=myErrors -prefix=My-Prefix のように -prefix を付与すると [My-Prefix-1] のようにprefixを自由に設定することもできます.


この手の仕組みはプロジェクトごとに自作しがちだったんですが,毎度毎度書くというのも面倒だったのでこの度汎用的に使えるようツール化したという次第です.

ご利用くださいませ.

golangのstruct custom tagをうまいことparseして値を引っこ抜きたいってとき

type Foo struct {
	Bar string `buz:"qux" iyan:"bakan"`
}

における `buz:"qux" iyan:"bakan"` を良い感じで buz => "qux", iyan => "bakan" のように取得したいというケースでは以下のようにするとよい:

tagKeyValue := reflect.StructTag(`buz:"qux" iyan:"bakan"`)
buz := tagKeyValue.Get("buz") // => "qux"
iyan := tagKeyValue.Get("iyan") // => "bakan"

という具合でreflect.StructTagを使うと良い感じでできます.よかったよかった.

……クソ,なんのためにこんなものを書いてしまったんだ!!!! 良いお年を!!!!

github.com

superuserに対する「ふつーのuser」にどういう名前を付けるべきか

TL;DR

  • unprivileged users
  • ordinary user
  • standard user

などが良いようだ.ordinaryとかstandardはuserに限らず他の種別でも使えそう.

会話の様子

shinpei0213 [14:11]
特権ユーザー root user 一般ユーザー xxxx user
xxxx なんて言えばいいの

moznion [14:12]
prisoner
単にuserだと問題が出るケースってことですよねえ

shinpei0213 [14:12]
そうそう
なるホディウスでした

moznion [14:13]
prisonerは完全に問題があるw

shinpei0213 [14:13]
だめかな
だめか

moznion [14:13]
「囚人」

shinpei0213 [14:13]
normal userだとへん?
でもadd user するときに prisoner とか渡さないっけ
わたさないな
なにかと勘違いしている

moznion [14:13]
jailingの文脈で思いついたw
normal,僕は変だと思わないっすけど,ネイチブの人とかはどう思うのかな
limitedにするとか?

shinpei0213 [14:14]
ah

moznion [14:14]
restrictedとか

shinpei0213 [14:14]
とりあえずnormalにする。azs
restricted いいね!!!!
それにします。天才かよ

moznion [14:15]

sunglasses

ichigotake [14:19]
Unprivileged users と表現しているところもあるようですね
>Unprivileged users can use the su and sudo programs for controlled privilege escalation.
https://wiki.archlinux.org/index.php/users_and_groups

moznion [14:19]
unprivillegedよさそう

ichigotake [14:19]
Unprivileged users でググってみると結構ヒットする

shinpei0213 [14:20]
第二の天才現る

moznion [14:20]
(タイプしにくいことを除くと
↑の僕のpostもタイポしてるしw
unprivilegedのほうが文脈としては正しそうな雰囲気ある

ichigotake [14:28]
英語版wikipedia を見るとこういう表現もあるようだ
standard user
ordinary user
https://en.wikipedia.org/wiki/Superuser