Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
社内勉強会vol.3@ごーふぁー荘
Search
Aya Ebata
December 05, 2022
Programming
810
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
社内勉強会vol.3@ごーふぁー荘
ごーふぁー荘 その2
https://gophersou.connpass.com/event/267138/
Aya Ebata
December 05, 2022
More Decks by Aya Ebata
See All by Aya Ebata
JEP 526: Lazy Constants
aya_ebata
0
75
Flutterハンズオン 5
aya_ebata
0
110
JEP 480: Structured Concurrency
aya_ebata
0
300
Flutterハンズオン 4
aya_ebata
0
180
Flutterハンズオン 3
aya_ebata
0
110
Flutterハンズオン 2
aya_ebata
0
120
Flutterハンズオン 1
aya_ebata
0
150
あたらしい もじれつの かきかた
aya_ebata
0
150
社内勉強会vol.2@ごーふぁー荘
aya_ebata
1
820
Other Decks in Programming
See All in Programming
AI × TiDD / 2026.09.05 Redmine 大阪
tokudiro
1
180
JPUG勉強会 OSSデータベースの内部構造を理解しよう(第2回)
oga5
0
270
AHC070解法紹介
eijirou
0
130
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
260
Ghostty + Neovimで作る 透明でカッコ良い開発環境
j341nono
0
110
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
190
Building an Out-of-Order CPU
latte72
1
790
速く作れる。その次は、速く確かめられる開発へ 〜AIネイティブ開発を支える、Shift Down〜 / Can build fast. Next, moving to development where we can verify fast.
rkaga
5
4.2k
iOSDC Japan 2026 - Swiftで作って学ぼう!データベース自作入門
kaseken
2
310
XP祭りでしか伝わらないフリップネタ #xpjug
murabayashi
0
150
cdk deploy JawsSonic #MARATHONしながらAWSリソースをデプロイしてみよう
akihisaikeda
2
140
巨大モノリシックアプリ モダン化大作戦
ktcryomm
1
1.1k
Featured
See All Featured
Java REST API Framework Comparison - PWX 2021
mraible
34
9.7k
Marketing to machines
jonoalderson
1
5.8k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
280
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.8k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
1
410
Automating Front-end Workflow
addyosmani
1369
210k
Documentation Writing (for coders)
carmenintech
77
5.5k
Product Roadmaps are Hard
iamctodd
55
13k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
900
How to Talk to Developers About Accessibility
jct
2
550
The agentic SEO stack - context over prompts
schlessera
0
940
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
530
Transcript
アンチパターン対策会議!!!! 作成者:えばた あや 2022/12/05
自己紹介 株式会社Alumnote えばた あや ◆プロフィール • 株式会社AlumnoteでバックエンドをGoで書いています! • ラーメン二郎が好きです!
会社紹介 国内大学・教育機関の財政難を解決するために、 大学の財務構造(資金調達手段)のアップデートを目指しているスタートアップです。 大学支援者ネットワークのデータベース化〜拡大活性化、寄付募集の最大化を実現する Vertical SaaSの開発・提供と大学実務のハンズオン支援を行っています。 エンジニアメンバーがまだ少ないため、 ごーふぁー荘にて社内勉強会を開催することになりました!
こんな感じのサービス作ってます CRMツール 決済基盤 ・エクセルなど複数のシステムに分散 している卒業生・寄付者名簿を 名寄せ・統合して管理 ・名簿情報をさまざまな項目で簡単に フィルタリングして抽出 ・HTMLメールをパソコン画面上で 簡単に作成し、名簿から配信可能
・配信したメールの到達率、開封率など の分析機能も標準で提供 ・寄付決済、会費決済向けの様々な 決済手段をワンストップで提供 ・決済情報は名簿情報と自動的に連携 大学支援者・関係者の名寄せ〜名簿管理 寄付マーケティングに必要なツール群 寄付者のデータが名簿に 自動連携される決済ツール コミュニティ ・卒業生検索・キャリアサービスなど 在校生や卒業生への便益提供が可能 ・名簿情報と自動連携されており、 最新の個人情報に更新できる 在校生・卒業生ネットワークの アクティベーション
目次 2 gormアンチパターン 3 SQLアンチパターン 4 まとめ 1 背景
今日は、 みんなとディスカッションしながら 登壇できたらいいなって思ってます! コアなGoエンジニアが少ないと Goな話できなくて寂しいのじゃ
レビューの時に、GoのライブラリやDBの使い方の勘違いを発見!!>< ↓ 今後も同じミスを起こさないようにするために振り返り&改善をしていきたい!!! ※ 今回はPostgreSQLとgorm v2使ってます 背景
まずはgromのアンチパターンから!
以下のソースコードの問題はなんだろう? 前提: 以下に該当するレコードが1件インサート済み gormアンチパターン type Organization struct { Name string
StartYear int } db.Where("id = ?", oid).Updates(Organization{ Name: "ほげ", StartYear: 0, })
答え: Updatesはゼロ値を更新しないのでStartYearが更新されない gormアンチパターン type Organization struct { Name string StartYear
int } db.Where("id = ?", oid).Updates(Organization{ Name: "ほげ", StartYear: 0, })
答え: Updatesはゼロ値を更新しないのでStartYearが更新されない ゼロ値とは 変数を宣言してその後値を代入しなかった時に入ってるデフォルトの値 例: gormアンチパターン UPDATE "organizations" SET "name"='ほげ'
WHERE id = '12345' var i int // intのゼロ値は0 var s string // stringのゼロ値は"" fmt.Printf("i: %d, s: %s", i, s) // 「i: 0, s: 」が出力される
対策: Updatesを使う場合はmapかSelectを使って書く必要がある! gormアンチパターン type Organization struct { Name string StartYear
int } db.Model(&Organization{}). Where("id = ?", oid). Updates(map[string]interface{}{ "name": "ほげ", "start_year": 0, })
対策: Updatesを使う場合はmapかSelectを使って書く必要がある! gormアンチパターン type Organization struct { Name string StartYear
int } db.Select("name", "start_year"). Where("id = ?", oid). Updates(Organization{ Name: "ほげ", StartYear: 0, })
以下のソースコードの問題はなんだろう? 前提: 以下に該当するレコードが1件インサート済み gormアンチパターン type Organization struct { ID uuid.UUID
Name string StartYear int } o := Organization{ ID: oid, Name: "ほげ", } if o.ID == uuid.Nil { // エラー処理 } db.Save(&o)
答え: Updatesメソッドと違ってSaveメソッドは渡されなかったものはゼロ値で更新される gormアンチパターン type Organization struct { ID uuid.UUID Name
string StartYear int } o := Organization{ ID: oid, Name: "ほげ", } if o.ID == uuid.Nil { // エラー処理 } db.Save(&o)
答え: Updatesメソッドと違ってSaveメソッドは渡されなかったものはゼロ値で更新される gormアンチパターン UPDATE "organizations" SET "name"='ほげ',"start_year"=0 WHERE "id" =
'12345'
対策: Firstメソッドで1件該当するレコードを取得してからその値を使って更新する gormアンチパターン type Organization struct { ID uuid.UUID Name
string StartYear int } var o Organization db.Where("id = ?", oid).First(&o) o.Name = "ほげ" db.Save(&o)
最終的にAlumnoteでのgormの書き方は… 各ユースケースに合わせたメソッドというよりも、汎用的に更新するメソッドとして作っているので UpdatesメソッドではなくてSaveメソッドを用いて実装した - どのカラムを更新するかはユースケース層で各ユースケースに合わせて実装 - Updatesメソッドは特定のカラムを更新するために使うイメージだったため、Saveメソッドを 利用 - それによりUpdatesで引っかかりがちなところを避けて行けるようになった!
- SaveメソッドはIDがない場合はinsertになってしまうけど、現状気にするのはここだけ になった もっといい方法あるよとか、こんなアンチパターンもあるよ、とかあれば教えてください!!w gormアンチパターン
つぎはSQLのアンチパターン!!!
やりたかったこと - 似ている人の組み合わせをDBに保存して、関連する似ているユーザを一塊にして返す - pagenationしたい 例: - AさんはBさんと似ている - AさんはCさんと似ている
- CさんはDさんと似ている - EさんはFさんと似ている SQLアンチパターン
元のデータの持ち方 imported_user_id: インポートしたユーザのID original_user_id: インポートしたユーザに似たユーザのID imported_user_diffsテーブル SQLアンチパターン ID imported_user_id original_user_id
1 B A 2 C A 3 D C 4 F E
APIで出力したい形 { data: [ { ids: [“1”, “2”, “3”], //
imported_user_diffsテーブルのid(後で使うから一応渡しておく data: [ // 似ているユーザの一塊を配列にしたもの {id: “A”(ユーザの情報も一緒に返す)}, {id: “B”(ユーザの情報も一緒に返す)}, {id: “C”(ユーザの情報も一緒に返す)}, {id: “D”(ユーザの情報も一緒に返す)}, ], }, { ids: [“4”], data: [ {id: “E”(ユーザの情報も一緒に返す)}, {id: “F”(ユーザの情報も一緒に返す)}, ], }, ], total: 2, } SQLアンチパターン
この設計のデメリット - 似ているユーザを一塊にするSQLが一筋縄で書けない - 厳密に言うとPostgreSQLだと再帰ができるので書けるけど…スマートとは思えない - pagenationができない SQLアンチパターン
この設計のデメリット - 似ているユーザを一塊にするSQLが一筋縄で書けない - 厳密に言うとPostgreSQLだと再帰ができるので書けるけど…スマートとは思えない - pagenationができない 調べてみたらアンチパターンと言うことが判明した!!! SQLアンチパターン
ナイーブツリー 自分自身と自分自身の親を持つことで木構造を表現するアンチパターン 今回の例で言うとこういう木構造になる SQLアンチパターン A B C D E F
ナイーブツリーのデメリット - 親であるAの子供一覧を取得しにくい - 末端のDから親を辿るのが難しい - Cが削除されるとDの繋がりがなくなる…(Aが親だと言う事実は消したくない SQLアンチパターン
今回Alumnoteではこんな感じに対応しました SQLアンチパターン ID imported_user_id original_user_id 1 B A 2 C
A 3 D A 4 F E
今回Alumnoteではこんな感じに対応しました - original_user_idの値を木構造で言う1つ上のノードの値ではなくて、親の値を持つようにした - 閉包テーブルに近い設計にした - imported_user_id = original_user_idの値は持たなかった -
本来閉包テーブルにはimported_user_id = original_user_idの値を含めるが、もしユー ザを追加したときにimported_user_diffsテーブルにimported_user_id = original_user_idの値を追加するの忘れるとデータがおかしくなる - なくても表現できたのでimported_user_id = original_user_idの値はない方向にした SQLアンチパターン
それにより以下が改善 - original_user_idで絞って検索することで簡単に似ているユーザを一塊にすることができるよ うになった! - ユーザの削除があっても関係性が崩れなくなった! - original_user_idでGROUP BYすることで、pagenationもできるようになった! SQLアンチパターン
まとめ gormアンチパターンというよりも使い方間違えって感じだったけど、書き方を間違えるとデータに すごい影響があるということに気付けた! SQLアンチパターンは実際設計の時点で知識が足りなくてアンチパターンになってしまったが、それ によってナイーブツリーを知ることができた!
募集中! Alumnoteでは正社員・業務委託として一緒に働いて頂ける方を募集中! 応募お待ちしてます! バックエンド https://herp.careers/v1/alumnote/PVuMatXQrdmn フロントエンド https://herp.careers/v1/alumnote/N8ujo5TyyP8h