DRYな備忘録

Don't Repeat Yourself.

datastore: invalid entity type

問題

cloud.google.com/go/datastore

datastore package - cloud.google.com/go/datastore - pkg.go.dev

を使ってDatastore  |  Google CloudにデータをPutしていて、掲題のエラーを得た。

ev := models.Event{/* なんらかの値 */}
if _, err := tx.Put(key, ev); err != nil {
    return err
}
datastore: invalid entity type

調査

まずエラーメッセージが貧弱なので、定義を知りたい。

Search · datastore: invalid entity type · GitHub

あった google-cloud-go/datastore.go at 1063c601a4c4a99217b45be0b25caa460e7157a1 · googleapis/google-cloud-go · GitHub

f:id:otiai10:20210905185048p:plain

あらためて、順当にPutを掘っていく。

f:id:otiai10:20210905190549p:plain

結論

Getのみならず、Put系であっても、Structの値はPointerである必要がある。

ev := models.Event{/* なんらかの値 */}
- if _, err := tx.Put(key, ev); err != nil {
+ if _, err := tx.Put(key, &ev); err != nil {
    return err
}

雑感

  • たしかにエラーメッセージとして十分だとは思うが、自作パッケージをつくるなら、もうちょっと丁寧に返したい
  • 最近、WETもDRYもぜんぜん書いてなくてさみしい

DRYな備忘録として

ameshコマンド & amesh Slack bot の最近の話

このエントリは Go 2 Advent Calendar 2020 - Qiita の8日目です。

背景

  • もう2年前になりますが、ソフトウェアを主業としない業界に転職しました
  • 最近はストレス解消にコードを書いています。仕事ではいっさいコード書かない
  • ameshコマンド、amesh-botは便利なので今でもガンガン開発しています
  • そろそろ艦これウィジェットのサーバサイドをHerokuからGCPに引っ越したい

ameshつくったの、もう5年前じゃん。

tl;dr

  • GAE/Go 1.12+の環境で動くようにリファクタリングしました
  • 「予報」コマンドをつくりました
  • Slack AppとしてDistributeしました(Submitはまだ)
  • それにともなってFirestore使うようにしました
  • 今まで0.07円だったんですけど、公開したら614円になりました

github.com

CLIとWebアプリケーションを含むプロジェクトの構成について

ameshプロジェクトは、ameshコマンドと、amesh-botという2つのユースケースを提供しています。さらに、他のプロジェクトからもimportできるpackageとしてのインターフェースもあります。

当初は、以下のようなファイル構成で作成していました。

.
├── bot
├── amesh
│   └── main.go
└── lib

このコマンドラインツールをインストールしようとすると go get github.com/otiai10/amesh/amesh というように、amesh/ameshをgetする必要があります。これは、一時期けっこう見たタイプだと思いますたとえばgithub.com/robfig/revel/revelとか。

revel、いっぺん死んだかと思ったら、ひさしぶりに見に行ったらふつうに1.0.0が最近リリースされててびっくりした。 この情報を見つけただけでもこのアドカレ書いた意味あったかもしれん。

いつぞやはお世話になりました、revel。

あとはservice/owner/foo/cmd/fooみたいなパターンもよく見ますが、ameshに関してはかっこよさを優先してgo get github.com/otiai10/ameshとしたくて、ルートにmain.goを配置しました。

.
├── bot # Slackのwebhookを受けるサーバの定義
├── cli # コマンドラインアプリケーションの定義
├── lib # 外部プロジェクトがimportできるもの
└── main.go # コマンドのエントリポイント

Slack AppのDistributeにあたって、Firestoreの利用

データを保存する必要があるため、GAE/GoからFirestoreへの接続をしました。が、めっちゃかんたんだったのであんまり特筆すべきことはないです。

これ見てやりました。

pkg.go.dev

ちなみに

気温も見れます

マイナンバー通知カードが見つかったら、GitHub Sponsorを始めると同時に「Add to Slack」ボタンを公開したいと思います。

マイナンバー通知カードどこ〜

誰か俺のマイナンバー通知カードを見つけてくれ

DRYな備忘録として

スターティングGo言語

スターティングGo言語

Go言語による並行処理

Go言語による並行処理

改訂2版 基礎からわかる Go言語

改訂2版 基礎からわかる Go言語

GoでWASMでHello World

背景

  • 一応GoもやってるしWebのフロントエンドもある程度やっているのに、WASMなにも触ったこと無いのはよくないので触りたい
  • WASMというものが一体何なのか、何ができるかも知らない

tl;dr

  1. Goで書いたコードをwasmにするフラグをつけてビルドすると.wasmが手に入る
  2. 本質的には上記がすべてであるが
    1. このwasmをkickするためのwrapperなJSもGoは提供してくれている
    2. 好きなようにサーバを立てて、このwasmファイル、およびwrapperなJSがブラウザから読める状態にすればよい

参考

成果物

github.com

ログ

cd $GOPATH/src/github.com/otiai10
mkdir hello-go-wasm
cd hello-go-wasm
git init
go mod init
mkdir server
mkdir client

とりあえず以下のような感じでサーバつくった

.
├── client
└── server
    ├── main.go
    └── views
        └── index.html

つぎにWASMの準備

# wrapperなJSをGOROOTから持ってくる
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" ./server/static/js

index.htmlに以下を追加

<head>
   <script src="/public/js/wasm_exec.js"></script>
   <!-- 神経質に public/wasm に分けなくてもいいとは思いつつ -->
   <script>
       const go = new Go();
       WebAssembly.instantiateStreaming(fetch("public/wasm/main.wasm"), go.importObject).then((result) => {
           go.run(result.instance);
       });
   </script>
</head>

いよいよ、wasmになるであろうGoを書く。 ./client/main.goを以下のように書いた

package main

import "fmt"

func main() {
    fmt.Println("これがconsoleにprintされるん?")
}

んで、ビルド

GOOS=js GOARCH=wasm go build  -o ./server/static/wasm/main.wasm ./client/main.go

で、これをサーバに読ませる

go run server/main.go

f:id:otiai10:20201103130408p:plain
できたじゃん。ヤバ

かんたんだった。DOMの操作とかはsyscall/jsで出来そうなので、今回はいいや、となりました。

所感

DRYな備忘録として

たぶん今どきなPythonプロジェクトのはじめかた

ただの備忘録として

ls -la /usr/local/bin | grep python
mkdir ~/proj/python/my_project
cd ~/proj/python/my_proj
python3.8 -m venv .venv
source ./.venv/bin/activate
# .venvの中にコンテキストが移動している
which python
python -V
which pip
pip -V

# 依存はrequirements.txtよりsetup.pyに書くほうがわかりやすいっぽい
pip install .
pip install .[tests]

参考

github.com

DRY

Googleスプレッドシートで値の抽選

問題

こういうリストがあって、ここからランダムに値を抽出したい。

解決

= INDEX(A:A, RANDBETWEEN(1, COUNTA(A:A)), 1)

おしまい

解説

  • INDEX: 値を参照、行、列を指定して取得する
  • RANDBETWEEN: 2つの整数の間の数をランダムに返す
  • COUNTA: 参照における値のあるセルの数を返す
= INDEX(
    A:A, '← INDECの第1引数(参照)候補値の一覧。今回はA列全体
    RANDBETWEEN(
        1, '← 1行めから抽出したいので1
        COUNTA(A:A) '← 値があるぶんだけ抽出したいのでCOUNTA
    ),  '← INDEXの第2引数(行)RANDBETWEENの出力が入る
    1  '← INDEXの第3引数(列)今回はA列固定なので1
)

注意

  • それぞれのセルが独立してRANDを計算するので、複数抽出した場合に重複を許します
  • COUNTAが値の歯抜けに対して弱いという話をどっかで見ましたが、とりあえず動いたんで検証してません 🤪

DRYな備忘録として