Overview
タイトルの通りです。
node_modules などのディレクトリがあると一度開くだけで Explorer がとても広がってしまうのが鬱陶しなくなってしまったので非表示にすることにしました。
手順
Setting.json に以下を追加するだけです。
"files.exclude": { // 略 "**/node_modules":true, // 追加 "**/.vscode":true, // 追加 },
これはたまに書いてる自分自身の思考の dump の一つです。
思考を吐き出してるだけなので、所々話が飛んでるかもしれないですがご愛嬌で。
Go では A little copying is better than a little dependency. という諺があり、これは依存 < 冗長を選択した方がいいケースがあることを示している。
プログラミングのお作法としての DRY を否定しているかのような諺であるが、実際にプロダクト開発をしていくにつれてこの諺の示すところの片鱗が少し見えてきたので、実体験を元にして文章にまとめてみる。
ref: https://go-proverbs.github.io
言ってしまえば、プロダクトを実際に作っている時には、DRY の原則に基づいた方が効率がいいと思う。
同じコードを2度以上書くのは面倒くさい(※1)
ただ、DRY の原則に則ってプロダクトのコードを書いてきたにもかかわらず、ある時からこの DRY の原則に従って生み出されたものに嫌気がさすタイミングがある。 それはどういうタイミングなのか、と考えると依存が大きく、かつ依存先の処理を理解しないと影響が範囲が読めずに「コードを簡単に変更できない」という事態に遭遇した時だ。
プロダクトは長く使われる中で改善され、改変されていく。刹那的なプロダクトや個人開発で自由気ままに開発しているプロダクトであればまぁ好きに書いてくれていいが、社会に対して何らかの価値を提供し、継続的に運用されているプロダクトは、常に何らかの改善や機能の追加がなされていく。
この改善や機能追加のタイミングで既存のコードに手を加える時、あるいは自分たちが使ってるライブラリや環境が古く、ソフトウェアが危険(セキュリティなど)に晒される可能性がある時に、既存のコードを変更したりライブラリを入れ替えたりする作業が必要になる。
これはソフトウェアエンジニアとして仕事をしていれば当然直面する課題であり、都度対応していかないといけない問題でもある。
しかしながら、一度コードを変更するときにその影響範囲について必ず調査をする。 なぜなら、いくらソフトウェアが危険に晒されてるからといって、プロダクトの振る舞いを変えたり、不具合を誘発しては事業そのものに影響が出る。あくまで事業に影響が出ないように、安全にプロダクトを改善するためにも、実際自分が今から変えようとしてるコードはどこに影響が出るのか?ということは必ず事前に調査し、明らかにしておく必要がある。
ちょっとしたコードの変更やロジックの修正、もしくはコードの削除、局所的にしか使われていないライブラリや共通処理の改善であれば話は早い。そこだけ入れ替えれば作業は完了する。
しかし、ちょっとした修正をするつもりが、該当箇所の依存先の実装に問題があったとしたらどうだろう?依存先のコードは、対応したかった箇所とは別の箇所でも使われているかもしれない。依存先の依存先でまた問題のある実装が見つかるかもしれない。 もしかしたら依存先のコードの修正はプロダクト全体に影響が出るところかもしれない。
プロダクトを開発する時には DRY の原則にしたがって実装したコードが、プロダクトを運用する時になって足枷になることは実は頻繁に発生する。
コピペを嫌って脳死で共通化した処理や、DRY の原則に基づいて開発当時は有用だった依存が運用フェーズになって重荷になる、要はプロダクトの中の情報のあり方やドメインが変わってきたときに脳死で DRY したり便利だと思っていた汎用処理がプロダクトの変更の重荷になる、ということが発生する。
※1. そもそもの DRY の原則とは「単なる重複をなくすことでない」ので誤認なきよう -> Don't repeat yourself - Wikipedia
繰り返しになるが、そう入っても同じ処理を何度も書くのは面倒くさい。それはそうだと思う。
意味で考えるにはコードそのものよりも HTML で考えてみるとわかりやすい。
(これは前に僕の尊敬するエンジニアから教わった例えをそのまま記載している。)
<h1>見出し1</h1> <h2>見出し2_1</h2> <h2>見出し2_2</h2>
という HTML の構造を考えた時に h2は同じことが書かれてるな? と思って
<h1>見出し1</h1> <h2> 見出し2_1 見出し2_2 </h2>
こんな風に共通化する人はいないだろう?
DRY は極端にいえばこういうことすら肯定してしまう原則とも捉えられかねない。
h1 と h2 で意味するところが違う。それどころかページのレイアウトそのものにも影響を与えてしまう。
同じ処理だから脳死で共通化するとこういうことすら肯定してしまう。
重要なのは「共通化の意味」をちゃんと考えることだ。分かれていることに意味があるならそれは「意味のある冗長」であり、共通化するべきでない。
HTMLでの例えは多少乱暴かもしれないが、プロダクトのコードを書いてるとふとこうしたことを平気でしてしまいそうなくらい、共通化の悪魔の引力は強い。
処理として同じ文脈で同じ処理を書いているなら共通化するのが原則だが、文脈が違うなら共通化はするべきではない。
共通化処理については上記に述べたとおりであるが、広く使われているOSSや自作ライブラリに依存するケースについて考えてみる。
自分はこれについては1つの見解を持っていて、見出しにあるように「継続的な更新が提供される場合のみ汎用的なライブラリに依存するべき」と考える。 継続的な更新が提供されない限りは、自作ライブラリすら作らない方がいい、という見解で、もし作るのであれば、プロダクト開発から離れてもなお、メンテナンスされ続ける体制を作っておくくらいのことをして初めて自作ライブラリをプロダクトに適用良いのだと思う。
おそらくこれを満たすものというのは、AWSやGCP謹製のライブラリや、OSSとして広く定着しているものに限られる。個人で作ってるプロジェクト等のライブラリに依存するのは極力避けておくほうが、開発時期は負担が大きいかもしれないが、長期的な運用まで見据えると旨味が大きい。
まぁそうは言ってもスケールする、継続するかもわからないプロダクトの開発において大事なのはスピードで、運用を見据えて多少冗長な実装をとって時間を食ってしまうことがそもそも事業的に許容されないケースというのは絶対に存在する。
※ 自作のライブラリのメンテナンスなんか考えてる人はさらに稀かもしれない。
実際に困った時になって「依存してるのが辛いな〜」とか「冗長に書いても良かったんじゃないかな〜」と思うことがほとんどだと思う。とすれば1つの観点として持っておきたいのは、依存や共通化はしてもいいけど、それが「どれだけ捨てやすい」のか?ということではないだろうか?
影響範囲を局所的にしておく、捨てやすい(or 入れ替えやすい)ように作っておくなど、プロダクトを開発するときに頭の片隅に置いておきたい観点は存在するので、それを引き出しとして持っておくことが大事なのかなと思う。
当初書きたかった内容からは多少逸れてしまったが、自分のキャリアで大規模なプロダクトの開発を経験する中で Go の A little copying is better than a little dependency. という諺の言わんとしてるところの片鱗を考え始めるようになった。
ほんと、プロダクト開発は奥が深くて面白い。
go get でプライベートリポジトリを fetch するのに、コケてその調査で時間を溶かすことが何度か重なったので対応方法について記載します。
またプライベートリポジトリに依存してるプロジェクトで Github Actions を回すときもプライベートリポジトリの取得部分でハマったのでそちらについても記載します。
何もしないままプライベートリポジトリを go get すると
go get -u github.com/PRIVATE_REPO github.com/PRIVATE_REPO@vX.X.X: verifying module: github.com/PRIVATE_REPO: reading https://sum.golang.org/lookup/github.com/PRIVATE_REPO: 410 Gone server response: not found: github.com/PRIVATE_REPO: invalid version: unknown revision v0.0.1
というようにエラーが出て module を fetch することはできません。
これを解消するには以下の3つの設定を行います。
git config --add --global url."git@github.com:".insteadOf https://github.com
export GOPROXY=direct
export GOPRIVATE=github.com/PRIVATE_REPO
Github Actions でも何もせずにプライベートリポジトリを pull しようとすると以下のエラーに遭遇してmodule を取得することができせん。
go: github.com/PRIVATE_REPO: invalid version: git fetch -f origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/runner/go/pkg/mod/cache/vcs/3703b101c339d9fd970d99639a980444379be4a036303c73173fe24bc3ab8ac5: exit status 128: remote: Invalid username or password. fatal: Authentication failed for 'https://github.com/PRIVATE_REPO'
プライベートリポジトリを fetch するためには Actions がプライベートリポジトリへのアクセス権限を持っているが必要になります。
このため、Actions でビルドされるステップの中でビルドに使われているコンテナ内の git の設定でアクセス権を付与します。
アクセス権についてはプライベートリポジトリを見ることができるユーザーごとの Personal Access Token を取得します。 取得方法については Setting > Developer setting > Personal access token からユーザーごとのアクセストークンを払い出すことができます。この時に repo にチェックをつけて access token を生成し、それを Actions の secrets に加えます。
Actions を定義している yml には以下の設定が追加されます。
jobs: build: steps: - name: github private modules access run: git config --global url."https://${{ secrets.GO_MODULES_TOKEN }}:x-oauth-basic@github.com/".insteadOf "https://github.com/"
※ リポジトリの Settings > Secrets で生成した個人の Access Token を GO_MODULES_TOKEN
を key にして追加します。
これで Github Actions 上でもプライベートリポジトリを fetch できるようになります。
タイトルの通りです。
gcloud components update
したら python のバージョン違いで gcloud コマンドが動かなくなったのでその解決方法について記載します。
Traceback (most recent call last): File "/Users/$UserName/google-cloud-sdk/lib/gcloud.py", line 104, in <module> main() File "/Users/$UserName/google-cloud-sdk/lib/gcloud.py", line 62, in main from googlecloudsdk.core.util import encoding File "/Users/$UserName/google-cloud-sdk/lib/googlecloudsdk/__init__.py", line 23, in <module> from googlecloudsdk.core.util import importing File "/Users/$UserName/google-cloud-sdk/lib/googlecloudsdk/core/util/importing.py", line 23, in <module> import imp File "/usr/local/Cellar/python@3.9/3.9.0_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/imp.py", line 23, in <module> from importlib import util File "/usr/local/Cellar/python@3.9/3.9.0_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/importlib/util.py", line 2, in <module> from . import abc File "/usr/local/Cellar/python@3.9/3.9.0_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/importlib/abc.py", line 17, in <module> from typing import Protocol, runtime_checkable File "/usr/local/Cellar/python@3.9/3.9.0_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/typing.py", line 26, in <module> import re as stdlib_re # Avoid confusion with the re we export. File "/usr/local/Cellar/python@3.9/3.9.0_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/re.py", line 124, in <module> import enum File "/Users/$UserName/google-cloud-sdk/lib/third_party/enum/__init__.py", line 26, in <module> spec = importlib.util.find_spec('enum') AttributeError: module 'importlib' has no attribute 'util'
要は python 3.9 には Google Cloud SDK は対応してねーよってことらしいです。
どうやら brew を使って python をインストールしていると意図せず裏側で最新の python が最新にあってしまっていたようで( brew upgrade
した時とかの弊害) gcloud コマンドから参照する python のバージョンが最新にあってしまっていました。
これを解決するためにたまたま pyenv
を入れていたいので pyenv 経由で 3.8 をインストールして合わせました。
pyenv install 3.8.0 pyenv global 3.8.0 source .zshrc python --version Python 3.8.0
これで再度 gcloud
コマンドを実行したら正常に動作しました。
firestore でドキュメントを操作するベースとなる方法を記載します。 ※ Go の実装で書いてます。
ref: https://godoc.org/cloud.google.com/go/firestore
ctx := context.Background() client, err := firestore.NewClient(ctx, "$projectID") if err != nil { // TODO: Handle error. } ref, err := client.Collection("$CollectionName").Doc("$DocumentID").Get(ctx) if err != nil { // TODO: Handle error }
ref: https://godoc.org/cloud.google.com/go/firestore#DocumentRef.Get
ctx := context.Background() client, err := firestore.NewClient(ctx, "$projectID") if err != nil { // TODO: Handle error. } dss, err := client.Collectipn("$CollectionName").Documents(ctx).GetAll() if err != nil { // TODO: Handle error } dsts := make([]*DistStruct, len(refs)) for i, ss := range dss { var dst = DistSturct{} if err := ss.DataTo(&dst); err != nil { // Handle Error } dsts[i] = &dst }
ref:
公式のドキュメントに記載されている実装方法は https://godoc.org/cloud.google.com/go/firestore#DocumentIterator を取得してからループで一つ一つマッピングしていく実装方針が記載されていますが、https://godoc.org/cloud.google.com/go/firestore#DocumentSnapshot を先に取り出したほうがその後 Slice にマッピングする時に Slice を length 指定でメモリ効率化できるので実装方針としてはそちらを採用する方がいいのでは?と思いました。
ctx := context.Background() client, err := firestore.NewClient(ctx, "$projectID") if err != nil { // TODO: Handle error. } src := map[string]interface{}{} ref, result, err := client.Collection("$CollectionName").Add(ctx)
ref: https://godoc.org/cloud.google.com/go/firestore#CollectionRef.Add
ctx := context.Background() client, err := firestore.NewClient(ctx, "$projectID") if err != nil { // TODO: Handle error. } updates := []firestore.Update { {Path: "$updateTargetField", Value: interface{}{} } } if err := client.Collection("$DocumentName").Update(ctx, updates); err != nil { // TODO: Handle error. }
ref: https://godoc.org/cloud.google.com/go/firestore#DocumentRef.Update
firestore.FieldPath
Update
構造体の中に FieldPath
がありますが、ある Document 内部の Filed が入れ子の場合に特定の field を更新したい場合に使います。
ref: https://firebase.google.com/docs/reference/node/firebase.firestore.FieldPath
// A FieldPath is a non-empty sequence of non-empty fields that reference a value. // // A FieldPath value should only be necessary if one of the field names contains // one of the runes ".˜*/[]". Most methods accept a simpler form of field path // as a string in which the individual fields are separated by dots. // For example, // []string{"a", "b"} // is equivalent to the string form // "a.b" // but // []string{"*"} // has no equivalent string form. type FieldPath []string
ref: https://github.com/googleapis/google-cloud-go/blob/master/firestore/fieldpath.go#L31-L43
そのため以下のような構造のドキュメントを考えた時に
type Article struct { User User `json:"user" firestore:"user"` } type User struct { Name string `json:"name" firestore:"name"` Age int64 `json:"age" firestore:"age"` }
Article 内部のユーザーの名前を変更したい時に以下のような FieldPath を組み立てることになります。
fp := []string{"user", "name"} update := []firestore.Update {FieldPath: fp, Value: "Taro"} if err := client.Collection("Article").Update(ctx, update); err != nil { // TODO: Handle error. }
if err := client.RunInTransaction(ctx, func(ctx context.Context, tx *firestore.Transaction){ // Transaction }); err != nil { // TODO: Handle error. }
ref: https://godoc.org/cloud.google.com/go/firestore#Transaction
以下のような Struct を考える。
type User struct { ID int64 Name String CreatedAt time.Time UpdatedAt time.Time }
time.Time の時刻型をもつフィールドがある時、MySQL の時刻型のカラムをそのまま Scan しようとすると以下のエラーが出る。
sql: Scan error on column index 3: unsupported Scan, storing driver.Value type []uint8 into type *time.Time
解決策としては接続する時に ?parseTime=true
をつける。
すごい久しぶりに sqlx を使ったら色々忘れてたので備忘録です。
driver の種類は下記を参照 https://github.com/golang/go/wiki/SQLDrivers
例えば MySQL を Driver として選択したい場合には MySQL を使うパッケージで
import _ "github.com/go-sql-driver/mysql"
とする必要があります。
これは別に sqlx に限った話じゃないですが完全に忘れてました笑
sqlx のメリットの1つに db.Query
を使ったときにマッピングするカラムを全て指定しないといけないと言う標準の sql/database
のデメリットを回避し、DB のテーブルに対応する struct を定義してき、db.StructScan
を使うとマッピングを自動でやってくれると言うのがあると思いますが、この db.StructScan
には Struct 以外を当てることはできません。
Slice で取り出したいときは以下のようにします。
type User struct { id ing64 `db:"id"` name string `db:"name"` age int64 `db:"name"` } rows, err := db.Queryx("SELECT * FROM user WHERE age > 20") users := make([]*User, 0, 0) for rows.Next() { user := User{} if err := db.StructScan(&user); err != nil { // handle error } users = append(users, &user) }
追記: README 見たら db.Select
が使える。ORM っぽく使いたいならアリかも。
取り出したいカラムは指定しろってことですね。 つまり以下のようなクエリは発行しても struct にマッピングできません。
テーブル: User - id INT - name VARCHAR - age INT
type User struct { ID int64 `db:"id"` Name string `db:"name"` } rows, err := db.Queryx("SELECT * FROM user where id = ?", 1) if err != nil { // error handling } user := User{} for rows.Next() { if err := rows.SturctScan(&user); err != nil { // missing destination name age が発生する } }
取り出したいカラムを制限したい場合はクエリで取り出すフィールドを指定する必要があります。
type User struct { ID int64 `db:"id"` Name string `db:"name"` } rows, err := db.Queryx("SELECT id, name FROM user where id = ?", 1) if err != nil { // error handling } user := User{} for rows.Next() { if err := rows.SturctScan(&user); err != nil { // missing destination name age が発生する } }
特に避けていたわけではないですが、これ!っていうメリットが特に感じていなかったので ghq を使っていなかったのですが、ふと思い立って使い始めたのでその記録です。
GIthub の README に書いてある通りです。
$ go get github.com/x-motemen/ghq
※ brew でもインストールできます。
ghq での探索対象を設定します。
ghq の設定には ~/.gitconfig
の設定を使います。
自分は普段 ~/src/github.com
というディレクトリ構成で個人のPC環境を作っているので、 .gitconfig
に以下の設定を追加しました。
[ghq] root = ~/src/github.com
これで ghq list
を実行した時に local の ~/src/github.com
を探索対象にしてくれます。
ちなみにdefault では ~/ghq
になるみたいです。
エイリアス を設定して、一発で cd $(ghq root)/$(ghq list | peco)
を使えるように .zshrc
に以下を追加しました。
alias g='cd $(ghq root)/$(ghq list | peco)'
peco とセットにして使うことでインクリメンタルサーチを使えてかつ、その指定したディレクトリに移動までできるようにしています。
調べればわかることばかりですが、ghq をとりあえず探索のみで使っているけどシンプルでいい感じです。
ディレクトリ移動は楽になりました。
local 環境で VSCode で作業することがほぼベースになってきたので、VSCode と GitHub を連携させて VSCode 上からできることを増やすために設定を追加したのでその記録を記載します。
VSCode は少し前から VSCode単体で GitHub と連携できるようになっています。
https://vscode.github.com/ で Add GitHub for Visual Studio Code
を選択すれば連携できます。
VSCode からも左下のアカウントマークを押下して、連携シーケンスに移行できます。
連携すると設定周りが Sync されるようです。今まで VSCode での設定の共有といえば Setting Sync でしたが今後は VSCode 備え付けの GitHub ログインで良さそうです。
設定の同期機能については以下に詳しく記載されています。
GitHub 上の PullReuqest や Issue を VSCode 上から操作できるようになります。
コードレビューするときはローカルでチェックアウトして実際のコードをみながらレビューする、ということを手間に思うことがあって(それもどうなんだ、、、というツッコミはあると思います。)提出されたファイル差分のみでレビューすることが多かったのですが、VSCode 上でチェックアウトできますし、そのまま VSCode 上で補完や Code Jump も使えるので、これでどれくらいレビューが楽になるのか、その辺を使いながら見てみようと思います。
こういったツールは今までもいくつか出てましたが、private リポジトリも含めて連携しちゃうので権限周りを考えるとちょっと及び腰でした。ただ、このツール自体は GitHub 純正のものなので、全面信頼するわけではないですが、ある程度信頼性があると踏んで使い始めてみてます。
概要は以下に記載してあります。
GUI から Issue を作成します。
テンプレートが作成されますので、Issue に記載したい内容を載せて右上のチェックマークを押下します。
Issue が作成されます。Open Issue で実際の Issue に遷移できます。
実際に作成された Issue は以下です。
まずコードを変更します。 今回はテストなので、自分の学習ログの Readme を書き換えます。
また事前以下のことをやっておきます。
実際に VSCode から Pull Request を作成します。
ベースとなるブランチを選択します。デフォルトは master に対する Pull Request になります。
Pull Request のタイトルを選択します。
大体書いてある通りですが
Pull Request のタイトル名を入力して Enter を押します。そしたら Pull Request が作成されます。
実際にPull Request が以下のように作成されます。
GitHub 純正の VSCode の Theme。 見やすい気がするので使ってみてます。
GitHub がマイクロソフトの傘下になってからというもの VSCode 関連のインテグレートの進化が凄すぎて、いろいろついていけてませんでしたが、VSCode と GitHub をベッタベタに密結合させると VSCode が優秀な Github クライアントになるので、今後もいろいろ試してみようと思います。
タイトルの通りです。 いつからか、VSCode でマウスを使って範囲選択を行うときに選択された範囲が Column Select Mode の状態になってしまってました。 意図してそうしていたならともかく意図せずに On になっていたので VSCode が急に使いづらくなってました。
こういうやつ。
#vscode adds column selection mode 😱 Very nice pic.twitter.com/TbBmpwonM0
— Steve Ariss (@SteveAriss) 2020年3月24日
便利だけど、マウスカーソルでの選択にも影響出るとは知らずにびっくりしました。
メニューバーにある Selection
から Column Select Mode
を Off にします。
Cmd + Shift + *
でも On/Off を変更することができます。
上記のエントリを読んで試しに、VSCode + TabNine の組み合わせをセットアップしたら gopls を使っているにも関わらず、Go の自動補完が爆速になって開発者体験がめちゃくちゃ向上したのでその手順を記載しています。
と言うのも、元々 Intelij を使っていたのですが、gopls の開発活発化に合わせて、ここ1年くらいは VSCode + gopls の環境で作業をしていました。ただ、どうしても VSCode と gopls をセットで使う場合に、langage server との通信ラグがコードの補完と微妙にあってなく、僕が思ってる速度でコードが書けないと言う課題がありました。
そんな中使い続けてたら Go を暗記し始めたので、実質補完いらないみたいな世界線に最近片足突っ込み始めてますが笑
まぁめちゃくちゃPCのメモリを食うのでまぁファンが鳴り止まない、と言う自体もあって何かいいツールはないものか(ここで Intelijにまた戻るのか?)探し続けてたところ、TabNine を知りました。
僕はこんな機会があるまで全然知らなかったんですが、 深層学習を用いることで、より精度の高い入力補完を実現
するツールのようです。
(すごい世の中ですね。)
Goを使う場合は基本的には gopls がついてくるので、特に何かをインストールする必要はありません。
最新、と言うか master の gopls を使いたい場合は go get -u golang.org/x/tools/gopls
で取得します。
VSCode の setting.json
は以下のようにします。
"format": false, "autoComplete": true, "rename": true, "goToDefinition": true, "hover": true, "signatureHelp": true, "goToTypeDefinition": true, "documentSymbols": true, "workspaceSymbols": true, "findReferences": true, "diagnostics": true, "documentLink": true, "goToImplementation": true,
余談ですが、最近 gofmt を off った状態で使用しています。どうやら VSCode 側の format on save (go.formatTool
で指定したツール) とバッティングせずに動作が少し改善?されるような気がしてます。
詳しいところは追っかけてませんが、gofmt を true にしていたときは大きなファイルに変更を加えると VSCode の fmt のプロセスがなかなか終わらずファイルが save されない、と言う状況を起こしてしまっていました。
gofmt を off って状態でも VSCode 側での goimports に任せるようにした場合、特に fmt や import で困ることもなかったので、結果としては保存時のストレスは最近の作業に限って言うとなくなりました。
参考にしたエントリに記載されているように TabNine のプラグインをインストールします。
プラグインを入れたらソースコードのどこかに TabNine::config
を打ちます。そうするとデフォルトブラウザ TabNine の設定画面が開きます。
ブラウザが開かれるとわかりますが、 http://127.0.0.1:5555/{$任意の文字列}
と言うURLになっています。このURLはユーザーごとに違うのかまではわかりません。僕の環境では払い出されるURLは毎回同じでした。
エントリには設定方法が記載されていますが、202007 時点では v2.8 系が出ており、これは特に設定等もいらずに TabNine::config
で設定を開いたと同時にモデルのDLが始まっていました。
TabNine には Local モードと Cloud モードがあります。Cloud モードはクラウド上にある TabNine のサーバー上でコードの自動補完を検査するようです。これは意図せずコードが外部に流出してしまう可能性があるので業務レベルで使いたい場合は Local 一択でしょう。
ちなみにクラウドの機能をフルで使うには有償版に乗り換えないといけないっぽいです。セットアップ時はメールアドレスを入力して送信するだけでしたが。。。(ベータ版はもう終わったのだろうか。)
設定画面に activation するための key を入力するところがありましたし、Cloud 版を試してみたい方は有償版に切り替えて使ってみて欲しいです。
深層学習による、コードの補完サポート、と言う立ち位置なので、独自のパッケージ構成や変数定義については完全には追従してません。特にローカル版においては。
頻出パターンなどを含めて学習したモデルを使って自動補完の候補を出力しているので、プライベートなリポジトリの結果が反映されないのも当たり前といえば当たり前ですが。。。
ただ、多少のシグネチャの揺れは合ってもある程度実用に耐えそうな感覚はあります。これから使い倒していくうちに見方が変わるかもしれません笑
思いの外開発者体験が向上したので興味がある方は是非1度使ってみてください。
正直まだ使い始めたばかりなので、しんどいところを経験してないですが、もし何かあればまたアップデートをかけようと思います。
VSCode で MySQL を使うときのプラグインについて記載します。
主に達成したいことは以下です。
以下の2つのうちどちらかを入れておけば問題なさそうです。
注意点はくれぐれも *.sql ファイルで発火する SQLServer
はインストールしないことです。これは Azure 向けのエクステンションであるので MySQL のシンタックスが使えないことがあります。
ずっとおかしいなぁなんでエラー出るんだろうと思ってましたが、後から description 読んでそりゃそうだろ...みたいな気持ちになりました。
フォーマットをかけて欲しくない + 簡単な MySQL の補完だけしてほしい、という要件であればいいので、以下の Extention が特に変なことをしない、という点で良さそうでした。
もうこれでいいんじゃないか説があります(上記の全ての extention がフォーマットかかってしまう)