Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
事業の試行錯誤を支える コードを捨てやすくして システムをシンプルに保つ設計と工夫
Search
zuckey_17
October 27, 2023
Programming
10
4.7k
事業の試行錯誤を支える コードを捨てやすくして システムをシンプルに保つ設計と工夫
Kaigi on Rails 2023 での発表資料です。
https://kaigionrails.org/2023/talks/zuckey/
zuckey_17
October 27, 2023
Tweet
Share
More Decks by zuckey_17
See All by zuckey_17
お手並み拝見にしないオンボーディング
zuckey_17
2
1.9k
事業の試行錯誤を支えるピボットしやすいシステム設計と工夫 / Easy-to-pivot system design to support trial and error in business
zuckey_17
4
920
新規事業のOKRに寄り添う開発の意思決定 / Development decisions to lean on business OKRs
zuckey_17
1
500
Relearning Eloquent
zuckey_17
0
1.7k
Redash made inter-team communication active -
zuckey_17
2
5k
しがないラジオの作り方
zuckey_17
0
2.7k
今更聞けないReact
zuckey_17
4
1.9k
Other Decks in Programming
See All in Programming
コンテナをたくさん詰め込んだシステムとランタイムの変化
makihiro
1
140
テストケースの名前はどうつけるべきか?
orgachem
PRO
0
140
たのしいparse.y
ydah
3
120
CQRS+ES の力を使って効果を感じる / Feel the effects of using the power of CQRS+ES
seike460
PRO
0
140
KubeCon + CloudNativeCon NA 2024 Overviewat Kubernetes Meetup Tokyo #68 / amsy810_k8sjp68
masayaaoyama
0
260
採用事例の少ないSvelteを選んだ理由と それを正解にするためにやっていること
oekazuma
2
1k
テスト自動化失敗から再挑戦しチームにオーナーシップを委譲した話/STAC2024 macho
ma_cho29
1
1.3k
PHPで作るWebSocketサーバー ~リアクティブなアプリケーションを知るために~ / WebSocket Server in PHP - To know reactive applications
seike460
PRO
2
520
バグを見つけた?それAppleに直してもらおう!
uetyo
0
180
テストコード文化を0から作り、変化し続けた組織
kazatohiei
2
1.5k
fs2-io を試してたらバグを見つけて直した話
chencmd
0
240
Exploring: Partial and Independent Composables
blackbracken
0
100
Featured
See All Featured
Building an army of robots
kneath
302
44k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
665
120k
A designer walks into a library…
pauljervisheath
204
24k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
48k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
111
49k
Imperfection Machines: The Place of Print at Facebook
scottboms
266
13k
A Tale of Four Properties
chriscoyier
157
23k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
26
1.9k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
159
15k
Facilitating Awesome Meetings
lara
50
6.1k
Documentation Writing (for coders)
carmenintech
66
4.5k
The Cost Of JavaScript in 2023
addyosmani
45
7k
Transcript
事業の試⾏錯誤を⽀える コードを捨てやすくして システムをシンプルに保つ設計と⼯夫 2023-10-28 / Kaigi on Rails 2023 株式会社スタディスト
松村和輝@zuckey_17 1
2 松村 和輝 @zuckey_17 🙅「ざっきー」 🙆「ずっきー」 ⾃⼰紹介 https://twitter.com/zuckey_17 https://github.com/zuckeyM-17 https://blog.zuckey17.org/
https://medium.com/@kazuki.matsumura 2020年1⽉~現在 株式会社スタディスト • ⼩売企業向けの新規事業 『ハンクラ』の⽴ち上げリードエンジニアとして⼊社 • 現在は開発チームのマネージャーとプロダクトマネージャーを兼務
新規事業にアサインされ Webアプリケーションを作ることになりました。 Ruby on Rails を採⽤しますか? 3
4 • 少⼈数での開発でも⾼い⽣産性を出しやすい • 企業向けで、特定業種向けのサービスのため、爆発的に、想定以上にトラフィックが 伸びる可能性は低そう • すでに会社の他プロダクトでRailsで使われており、⼈の追加やスワップが容易そう • Ruby
on Rails が zuckeyが最も慣れているかつ、好きなフレームワークだ 新規事業でRuby on Railsを採⽤したときの頭の中(2020年当時)
5 新規事業でRuby on Railsを採⽤したときの頭の中(2020年当時) • 少⼈数での開発でも⾼い⽣産性を出しやすい • 企業向けで、特定業種向けのサービスのため、爆発的に、想定以上にトラフィックが 伸びる可能性は低そう •
すでに他プロダクトでRailsで使われており、⼈の追加やスワップが容易そう • Ruby on Rails が zuckeyが最も慣れているかつ、好きなフレームワークだ スピード感を持って 事業の試⾏錯誤を⽀えることができる
• パイロット顧客(2, 3社)を⾒つける ◦ = プロダクトのコンセプトに共感してくれて、実際に現場で利⽤してくれる顧客 • 「この⼈たちの業務を楽にするために開発していくぞ!!」 ◦ 実業務の利⽤による貴重なフィードバックがありがたい
◦ 実際に楽になった、便利だったという声が嬉しい ◦ 売上が⽴つ、嬉しい • 特定顧客への特殊(かもしれない)業務に寄り添う ◦ ⽴ち上げ初期では継続的な進化(機能追加)への期待が⼤きい ◦ ただ、顧客⾃⾝もその機能が本当に必要かどうかは知らない 新規事業⽴ち上げ初期の開発の様⼦ 6
⽅針転換は試⾏錯誤の証 回数をこなして事業を前に進めたい 7
作り込みをすべてそのまま残したら ⽅針転換に対応できない 8
• 試しに実装してみて、だめだったら簡単にやめられる • 徐々に変えていきたいのではなく、Drastic(劇的)に変えることができる 新規事業で重要なソフトウェアの特性 9
変化に強いソフトウェアをつくるための多くの概念やキーワードを⾒かける。 • SOLID原則 • 結合度‧凝集度 • DDD(Domain Driven Design) •
進化的アーキテクチャ • など チームでの共有‧教育には時間がかかる。 営業‧カスタマーサクセスのチームを含めた場で伝えるのが難しい。 変化に強いソフトウェア 10 Design Principles and Design Patterns 構造化設計 Domain-Driven Design: Tackling Complexity in the Heart of Software 進化的アーキテクチャ 絶え間ない変化を⽀える
コードや機能を捨てやすくし、 システムをシンプルに保つ 11
https://twitter.com/lukehannontv/status/794581557357015040 不要だと判断された機能は削除しないと利⽤者の満⾜度も下がる 12
コード/機能削除の事例を紹介 13
対象のソフトウェアについて 14
15 • 遠隔地に複数店舗を運営している⼩売企業 • 本部から店舗に作業指⽰(=施策)を配信 • 店舗は作業状況や商品棚の画像などを返す • 店舗に赴かないと現場の状況がわからず、 学びを次の施策に活かせない
ハンクラ OK OK OK OK OK NG OK OK OK OK OK OK NG OK OK OK OK OK OK NG 本部
16 Single Page Application by Vue.js Web Server & ActiveJob
Server
事例1 施策の統計情報、サマリ情報を⾒たい 17
• データが溜まると、イイ感じにまとめて ⾒たいという要求はあるある • 施策について店舗群がどのように反応し たかを把握したい 事例1. 統計情報、サマリ情報を⾒たい 18
19 事例1. サマリテーブルを作ってそれを参照できるようにする 施策 = scheme 施策サマリ = scheme_summaries
20 事例1. シンプルに作るとこんな感じ Web Server evidence 提出 enqueue UpdateSchemeSummaryJob evidence
scheme_summaries update summary Web Server API Worker create evidence
21 事例1. サマリのテーブルの周りを更新/参照する系 SchemeSummaryContoroller SchemeSummarySerializer SchemeSummary UpdateScheme SummaryJob scheme_summaries API
事例1. 閲覧する⼈、閲覧タイミングによって得たい情報は異なる 22 時間軸 施策終了 【商品部】 商品が売れ、売上が上が ることに責任を持つ 陳列までのリードタイムが 気になる
【店舗運営部】 店舗の健全な運営、コストの 削減に責任を持つ 作業負荷が想定通りで 再提出が異常に多くないか 【実施中】 思いもよらない不具合があり、 緊急対応をする可能性 督促をする閾値を越えないか 【終了後】 売上実績と比較してどうか 他の施策と比べてどうか
23 事例1. ⾒せたい場所に応じてAPIは分けたい SchemeStats Contoroller SchemeStat Serializer SchemeSummary < AR::Base
UpdateSchemeSummaryJob scheme_summaries SchemeProgresses Contoroller SchemeProgress Serializer SchemeSalesReports Contoroller SchemeSalesReport Serializer Sales 系 Model すべてのデータが⼊った scheme_sumamries からそ れぞれの利⽤箇所で必要なデータを取り出して使う
24 事例1. 画⾯が不要になったら部分的に削除 SchemeStats Contoroller SchemeStat Serializer SchemeSummary < AR::Base
UpdateSchemeSummaryJob scheme_summaries SchemeProgresses Contoroller SchemeProgress Serializer SchemeSalesReport Serializer SchemeSalesReports Contoroller Sales 系 Model どのカラムが必要なくなったのかが ⾃明ではなく、不要になったロジックの 消し忘れが発⽣してしまう可能性もある 売上系のデータは顧客の基幹システムから 落として、Excelで分析するので、この画⾯はいらない
事例1. 1つのテーブルを使い回すのではなく⽤途に対してテーブルを作る SchemeStats Contoroller SchemeStat Serializer SchemeProgress < AR::Base scheme_progresses
SchemeProgresses Contoroller SchemeProgress Serializer SchemeSalesReports Contoroller SchemeSalesReport Serializer Salesのデータ SchemeStat < AR::Base scheme_stats SchemeSalesReport < AR::Base scheme_sales_reports UpdateScheme SalesReportJob UpdateSchemeStatJob UpdateSchemeProgressJob
26 事例1. こんな感じ Web Server 提出 enqueue UpdateSchemeStatJob UpdateSchemeProgressJob scheme_stats
scheme_progresses scheme_sales_reports update Web Server Worker Batch enqueue UpdateSchemeSales ReportJob API create evidence
事例1. 画⾯が不要になったらテーブルごと削除 SchemeStats Contoroller SchemeStat Serializer SchemeProgress < AR::Base scheme_progresses
SchemeProgresses Contoroller SchemeProgress Serializer SchemeSalesReports Contoroller SchemeSalesReport Serializer Salesのデータ SchemeStat < AR::Base scheme_stats SchemeSalesReport < AR::Base scheme_sales_reports UpdateScheme SalesReportJob UpdateSchemeStatJob UpdateSchemeProgressJob 売上系のデータは顧客の基幹システムから 落として、Excelで分析するので、この画⾯はいらない ファイルごと 削除すればOK
28 事例1. テーブルを中⼼に作ると削除に踏み切りやすい • 1つのテーブルを使い回すのではなく⽤途 に対してテーブルを作る • 素直に作ることができていれば、テーブル を削除したら更新‧参照しているController や
Job もその単位で削除できる • ActiveRecord が中⼼にあるRails はこの考え ⽅があっていそう Contoroller Serializer Model (ActiveRecord::Bas e) Job Table Contoroller Serializer Model (AR::Base) Job Table
29 事例1. テーブルを中⼼に作ると削除に踏み切りやすい • 1つのテーブルを使い回すのではなく⽤途 に対してテーブルを作る • 素直に作ることができていれば、テーブル を削除したら更新‧参照しているController や
Job もその単位で削除できる • ActiveRecord が中⼼にあるRails はこの考え ⽅があっていそう Contoroller Serializer Model (ActiveRecord::Bas e) Job Table Contoroller Serializer Model (AR::Base) Job Table ファイルやディレクトリ単位で削除できるようにする 影響範囲の考慮漏れのリスクが少ない => 削除のハードルを下げる
事例2 ⼩売だけではなくメーカーにも実施結果を共有したい 30
• 商品が店頭に思ったとおりに並んでいるかどうかはメーカーも⾒たい • 各施策について閲覧したい情報は”ほとんど”同じ • メーカー企業では実店舗に臨店して、商品の陳列状況をチェックしたり並べ⽅を修正 する役割の⼈も存在する ◦ => こういう⼈も救いたいよね!
事例2. ⼩売だけではなくメーカーにも実施結果を共有したい 31
32 • 企業テーブルに企業種別(⼩売企業 or メー カー)をつけて、画⾯上では種別ごとに情報 を適宜出し分ける • ⼩売本部ユーザー /
メーカーユーザーでテー ブル、認証などのロジックは共有して省エネ 事例2. 最短で実現したいなと思ったとき
33 • ⼩売と同じようなテーブルをメー カーのためにも作る • 認証画⾯などもそれぞれ別で作る 事例2. ⼩売は⼩売、メーカーはメーカーで作る
• メーカー企業を巻き込んだら、ステークホルダーが増えてスピードダウン ◦ NDAを両者と結んで、ちょうどいい新商品が出たタイミングでお試し実施して効 果実感してもらえると良いですね => 導⼊までのリードタイムが増加 • そもそも⼀番やりたかったことは、⼩売企業の実⾏⼒の向上だったよね 34
事例2. そして1年後にわかる、メーカー向け画⾯不要説
• 「“ほとんど”⾒るものは同じ」というのは、⽢すぎるヨミ ◦ 実際に使ってみたら、⼩売だけ、メーカーだけに表⽰したいものが多々あった • もし、カラムの企業種別で分けていたら... ◦ View / Serializer
などの表⽰部分に分岐が増える ◦ v-if=”retailer.isRetailer(or Maker)”とかになるのはつらい... ▪ メーカーを削除するとき、削除漏れが発⽣する可能性が⾼まる 35 事例2. ユーザーが違う = 表⽰部分に分岐が増える
36 • ⼩売と同じようなテーブルをメー カーのためにも作る • 認証画⾯などもそれぞれ別で作る 事例2. ⼩売は⼩売、メーカーはメーカーで作る
37 • メーカー関連のコードをディレクトリ / ファイルごと削除する ◦ frontend/maker ◦ app/controllers|serializers|jobs|views|mailers/maker ◦
spec/requests|jobs/maker ◦ app|spec/models|factories/maker.rb|maker_user.rb|scheme_m aker.rb|maker_user_authentication.rb ◦ config/routes/maker.rb 事例2. メーカーと名のつくものをほぼノールックで削除
38 • メーカー関連のコードをディレクトリ / ファイルごと削除する ◦ frontend/maker ◦ config/routes/maker.rb ◦
app/controllers|serializers|jobs|views|mailers/maker ◦ spec/requests|jobs/maker ◦ app|spec/models|factories/maker.rb|maker_user.rb|scheme_m aker.rb|maker_user_authentication.rb 事例2. メーカーと名のつくものをほぼノールックで削除 表示部分も含めて冗長だなと思っていても 別々に作っていれば、 この単位で削除することができる。
39 事例2. この単位で削除することができる
40 • そもそも混ぜるな危険なものを混ぜない ◦ ⽬的ごちゃ混ぜのサマリテーブルを作ったり ◦ retailers テーブルに 企業種別で ⼩売
or メーカーのカラムをもたせたり • 短期的に記述量が少なく⾒えて速そうでも、削除まで考えるとむしろ遅い ◦ 分けるべき概念を、コードの分岐を増やさずに根っこから分ける ◦ 冗⻑に⾒えることもあるが分岐が増えそうであれば疑ってみる 削除を前提に設計する
41 • そもそも混ぜるな危険なものを混ぜない ◦ ⽬的ごちゃ混ぜのサマリテーブルを作ったり ◦ retailers テーブルに 企業種別で ⼩売
or メーカーの情報をもたせたり • 短期的に記述量が少なく⾒えて速そうでも、削除まで考えるとむしろ遅い ◦ 分けるべき概念を、コードの分岐を増やさずに根っこから分ける ◦ 冗⻑に⾒えることもあるが分岐が増えそうであれば疑ってみる 削除を前提に設計する 削除することを織り込んでおけば 設計⼿法のエッセンスは取り⼊れられている。
42 削除しすい設計はわかった。 じゃあ後はこれを使ってやっていくだけですね!
43 「え、せっかく作ったもの壊すんですか?」
44 「別のお客さんが使うかもしれないから 残しておいたほうがいいのでは?」
• たとえ機能や画⾯が使われておらず顧客に価値を提供できていないように⾒えても ⼯数をかけたモノを削除する意思決定をすることは難しい ◦ 損失回避バイアス 機能の削除を後押しするための⼯夫 45
• 複雑なシステムをメンテナンスするコスト、機能追加時により多くのコストがかかる ことについて最も把握しているのは開発者 • 開発者が機能や画⾯の削除をしたいとただ主張するだけでは削除は進まない ◦ not リファクタリング、内部品質の改善 • 意思決定を促す⼯夫が必要、開発者からアプローチできることがある
機能の削除を後押しするための⼯夫 46
• 機能のON/OFFを切り替える⼿法 ◦ A/Bテスト、限定的、段階的なリリースなどに使われることが多い ◦ ハンクラでは企業ごとに機能のON/OFFをつけることができる ◦ 特定の企業に出してみて反応を⾒ることができる ▪ 影響を抑えられるため⽐較的気軽に機能を出し⼊れできる
• だめだったら削除する / 良さそうだったら積極的に全体に公開する という運⽤を前提とする Feature Flag 47
• minispec • 開発着前、詳細な設計の前に⽤意する 「仕様案」のようなもの ◦ 解決すべき課題、規模感を事前に把握 • KPIに活⽤度などを⼊れることによって、 思った通りにいかなかったときにとるアク
ションを決めておく • 閲覧数‧利⽤頻度が思ったように増えなけ れば削除や⼿を⼊れることも検討 開発着⼿前に minispec を利⽤して期待値を調整する 48
• ログの集計‧閲覧を誰でもできるようにする • ハンクラではRedashでログとDBを統合して各機能‧画⾯の利⽤状況を把握できるよう にしている ◦ 思ったように利⽤されているか? ◦ されていなければ、顧客にヒアリングしてみる ▪
実は機能や知らなかっただけかもしれない ▪ 定量‧定性の情報をそれぞれ集められるようにする 利⽤状況を誰でも把握できるようにする 49
1 事業初期は試⾏錯誤の回数を増やすために、コードや機能は積極的に削除 していきたい 2 Rails においてコードを削除しやすくするには、 テーブルごと情報を分けて、閲覧側に分岐を極⼒いれない 3 捨てる意思決定の背中を押す雰囲気を作るのも開発者のしごと 50
まとめ
51 Rails でスピード感を持って 事業を前に進めましょう💪