$30 off During Our Annual Pro Sale. View Details »

森羅万象に「いいね」するためのデータ構造

 森羅万象に「いいね」するためのデータ構造

Kaigi on Rails 2022 にて『森羅万象に「いいね」するためのデータ構造』の発表をしました。
https://kaigionrails.org/2022/talks/pndcat/

===概要===

サービス開発をしていると「いいね」の実装に対面することは多いでしょう。例えば EC サービスの場合、商品へのいいね、クチコミへのいいね、ブランドへのいいねなど、いろいろな対象に「いいね」をするケースが考えられます。さらには、ログインユーザーの「いいね」と、非ログインユーザーの「いいね」を作ることもあるかもしれません。

しかし、あらゆるものに「いいね」できるシステムを作るのは容易ならざることです。普通に実装するだけでは関連するコードは肥大化し、データベースのテーブルもどんどん増えていくばかりです。

似ているけど少し違う「いいね」を実装するにあたって、失敗してしまったデータ設計、そこにあった悩みや苦しみ、それらを解決していくリファクタリングの道すじを説明します。

なっちゃん

October 24, 2022
Tweet

Other Decks in Programming

Transcript

  1. © 2022 Cookpad Inc. ৿ཏສ৅ʹʮ͍͍Ͷʯ͢ΔͨΊͷ
 σʔλߏ଄ ΫοΫύουגࣜձࣾ ͳͲ΍· ͳͭ͜ /

    @pndcat
  2. • ͳͲ΍· ͳͭ͜ / @pndcat • ΫοΫύουגࣜձࣾ 2017೥ʙ • 2ຊ໨ͷτʔΫͷ

    @osyoyu ͱҰॹʹಇ͍͍ͯ·͢ • ࡢ೥ @asonas ͕ൃද͍ͯͨ͠αʔϏεͷ։ൃͷ࿩ • ήʔϜΛͨ͠Γɺਪ͠׆ಈΛ͍ͯ͠·͢ 2 ࣗݾ঺հ
  3. • ର৅ऀ ◦ ৽نαʔϏεΛϦϦʔεͯ͠গ͠ܦͪɺϦϑΝΫλϦϯάΛ ߟ͍͑ͯΔਓ ◦ ϙϦϞʔϑΟοΫؔ࿈Λͬ͘͟Γ஌͍ͬͯΔਓ ▪ ࣌ؒͷ౎߹্ɺৄࡉʹ͍ͭͯ͸࿩͠·ͤΜ ◦

    kei-s ͞ΜͷൃදʢΞιγΤʔγϣϯͷϦϑΝΫλϦϯάʣ Λฉ͘ਓ 3 ͸͡Ίʹ
  4. • ৽نαʔϏεʹ͓͚Δʮ͍͍Ͷʯͷཁ݅Λߟ͑Δ • αʔϏε౰ॳʹઃܭͨ͠σʔλߏ଄ • ࣦഊͨ͜͠ͱ • ʮ͍͍Ͷʯͷσʔλߏ଄ͷ࠶ݕ౼ʙϦϑΝΫλϦϯά 4 ࿩͢͜ͱ

  5. 5 • ৯඼ؔ࿈ͷاۀͱϢʔβʔΛͭͳ͙ίϛϡχέʔγϣ ϯϓϥοτϑΥʔϜ ϝʔΧʔζλ΢ϯͱ͸

  6. 6 • اۀ͕ɺ঎඼Λ঺հͨ͠Γɺ঎඼ʹ߹͏Ϩγϐ΍೔ৗ ͷτϐοΫΛ౤ߘ͢Δ ϝʔΧʔζλ΢ϯͱ͸ τϐοΫ ঎඼ ※ػೳ໊͸τϐοΫε

  7. 7 • Ϣʔβʔ͕ɺاۀͷൃ৴ʹ͍͍Ͷ΍ίϝϯτΛ͢Δ ϝʔΧʔζλ΢ϯͱ͸ ίϝϯτ ͍͍Ͷ

  8. • ԿΛ͍͍Ͷ͢Δʁ → ʮ঎඼ʯɾʮτϐοΫʯ • 1ͭͷϞϊʹରͯ͠Կճ͍͍ͶΛ͢Δʁ → 1ճ • ͲΕ͘Β͍ͷظؒͰ࡞Δʁ

    → ૣ͘!!! 8 ʮ͍͍ͶʯػೳΛ࡞Δ ঎඼ τϐοΫ
  9. • ʮ঎඼ʯͱʮτϐοΫʯʹɺ1ճʮ͍͍ͶʯΛ͢Δͷ ͸೉͘͠ͳͦ͞͏ 9 ʮ͍͍ͶʯΛ͢Δ͚ͩɾɾɾʁ

  10. • ʮ঎඼ʯͱʮτϐοΫʯʹɺ1ճʮ͍͍ͶʯΛ͢Δͷ ͸೉͘͠ͳͦ͞͏ • ͔͠͠ɺ ◦ ʮ͍͍Ͷʯͷର৅͕ࠓޙ૿͑Δ͔΋͠Εͳ͍ 10 ʮ͍͍ͶʯΛ͢Δ͚ͩɾɾɾʁ

  11. • ʮ঎඼ʯͱʮτϐοΫʯʹɺ1ճʮ͍͍ͶʯΛ͢Δͷ ͸೉͘͠ͳͦ͞͏ • ͔͠͠ɺ ◦ ʮ͍͍Ͷʯͷର৅͕ࠓޙ૿͑Δ͔΋͠Εͳ͍ ◦ ϩάΠϯ͍ͯ͠ͳ͍Ϣʔβʔ΋ʮ͍͍ͶʯΛ͍ͨ͠ 11

    ʮ͍͍ͶʯΛ͢Δ͚ͩɾɾɾʁ
  12. • ͍͍Ͷͷର৅ ◦ ঎඼ ◦ τϐοΫ • ͍͍ͶΛ͢Δଆ ◦ ϩάΠϯϢʔβʔͷ͍͍Ͷ

    ◦ ϩάΠϯ͍ͯ͠ͳ͍Ϣʔβʔͷ͍͍Ͷʢಗ໊͍͍Ͷʣ • ʮ͍͍Ͷʯͷର৅͸ࠓޙ૿͑Δ͔΋͠Εͳ͍ 12 ٻΊΒΕ͍ͯΔʮ͍͍Ͷʯػೳ
  13. • ର৅ผɺ͍͍Ͷɾಗ໊͍͍Ͷ͝ͱʹςʔϒϧΛ࡞Δ ◦ product_likes ◦ product_anonymous_likes ◦ topic_likes ◦ topic_anonymous_likes

    • ϙϦϞʔϑΟοΫؔ࿈ • STI 13 ʮ͍͍Ͷʯͷσʔλߏ଄
  14. • ର৅ผɺ͍͍Ͷɾಗ໊͍͍Ͷ͝ͱʹςʔϒϧΛ࡞Δ ◦ product_likes ◦ product_anonymous_likes ◦ topic_likes ◦ topic_anonymous_likes

    • ϙϦϞʔϑΟοΫؔ࿈ • STI 14 ʮ͍͍Ͷʯͷσʔλߏ଄ ։ൃ͕ਐΉͱ࢓༷ɾৼΔ෣͍ɾڍಈ͕มߋ͞Ε͏Δ มߋʹ଱͑ΒΕΔΑ͏ʹγϯϓϧͳσʔλߏ଄ʹ͢Δ → ର৅ผɺ͍͍Ͷɾಗ໊͍͍Ͷ͝ͱʹςʔϒϧΛ࡞Δ
  15. 15 ॳظͷςʔϒϧߏ଄ product_likes product_id user_id product_anonymous_likes product_id like_identifier products id

    name ộ User ID (number) User ID ͕ͳ͍ͷͰϥϯμϜͳจࣈྻΛੜ੒ (string)
  16. 16 ॳظͷςʔϒϧߏ଄ product_likes product_id user_id product_anonymous_likes product_id like_identifier products id

    name ộ User ID (number) User ID ͕ͳ͍ͷͰϥϯμϜͳจࣈྻΛੜ੒ (string) ҟͳΔσʔλΛಉ͡ΧϥϜʹೖΕΔͷ͸ෳࡶ ͍͍Ͷͱɺಗ໊͍͍Ͷ͸ผͷςʔϒϧͰఆٛ
  17. • ʮ͍͍Ͷʯͷର৅͕૿͑ΔͨͼʹɺςʔϒϧɾϞσϧɾ ίϯτϩʔϥʔΛຖճ௥Ճ͢ΔͷͰͭΒ͍ ◦ ঎඼ɺτϐοΫɺΫνίϛɺίϝϯτ (8ςʔϒϧ) 17 ࣦഊͨ͠ͱ͜Ζ product_likes product_id

    user_id product_anonymous_likes product_id like_identifier topic_likes topic_id user_id kuchikomi_likes kuchikomi_id user_id comment_likes comment_id user_id topic_anonymous_likes topic_id like_identifier comment_anonymous_likes comment_id like_identifier kuchikomi_anonymous_likes kuchikomi_id like_identifier
  18. • ʮ͍͍Ͷʯͷର৅͕૿͑ΔͨͼʹɺςʔϒϧɾϞσϧɾ ίϯτϩʔϥʔΛຖճ௥Ճ͢ΔͷͰͭΒ͍ ◦ ঎඼ɺτϐοΫɺΫνίϛɺίϝϯτ (8ςʔϒϧ) • ͍͍Ͷ਺ͷूܭόονͰɺ৽͍͠ର৅ͷूܭΛ๨Εͨ 18 ࣦഊͨ͠ͱ͜Ζ

    ͋Δ࣌ؒ (time) Ҏ߱ʹ࡞੒͞Εͨʮ͍͍Ͷ਺ʯΛूܭ͢Δ
  19. • ঎඼ɺτϐοΫɺίϝϯτɺΫνίϛͷʮ͍͍Ͷʯͷ ৼΔ෣͍͸શ෦ಉͩͬͨ͜͡ͱ͕Θ͔ͬͨ ◦ Ϣʔβʔ͕ʮ͍͍ͶʯΛ͢Δ ◦ ʮ͍͍Ͷʯ਺Λදࣔ͢Δ ◦ ʮ͍͍Ͷʯ਺ͷूܭΛ͢Δ 19

    ਅʹʮ͍͍ͶʯʹٻΊΒΕ͍ͯΔػೳͱ͸ʁ
  20. • ঎඼ɺτϐοΫɺίϝϯτɺΫνίϛͷʮ͍͍Ͷʯͷ ৼΔ෣͍͸શ෦ಉͩͬͨ͜͡ͱ͕Θ͔ͬͨ ◦ Ϣʔβʔ͕ʮ͍͍ͶʯΛ͢Δ ◦ ʮ͍͍Ͷʯ਺Λදࣔ͢Δ ◦ ʮ͍͍Ͷʯ਺ͷूܭΛ͢Δ •

    ࠓޙ΋ʮ͍͍ͶʯผͷৼΔ෣͍͸ͳͦ͞͏ 20 ਅʹʮ͍͍ͶʯʹٻΊΒΕ͍ͯΔػೳͱ͸ʁ
  21. • ϙϦϞʔϑΟοΫؔ࿈: 1ͭͷϞσϧΛෳ਺ͷϞσϧʹؔ࿈͚ͮΔ ◦ Like ϞσϧΛ࡞Δ ◦ ڞ௨ͷৼΔ෣͍Λ͢Δ৔߹͸ڧྗͳσʔλߏ଄ ▪ if

    จΛॻ͘ͱഁ୼͢Δ • STI: ܧঝΛ࢖ͬͯςʔϒϧΛ1ͭʹ͢Δ ◦ ProductLike ͸ Like Λܧঝ͢Δ ◦ ֤ʮ͍͍ͶʯΫϥεͰৼΔ෣͍Λগ͠ม͑Δ͜ͱ͕Ͱ͖Δ ▪ ࣗ༝౓্͕͕ΔͷͰෛ࠴͕ੜ·ΕΔՄೳੑ͕ߴ͍ 21 ৽͍͠ʮ͍͍Ͷʯͷσʔλߏ଄ͷީิ
  22. • ϙϦϞʔϑΟοΫؔ࿈: 1ͭͷϞσϧΛෳ਺ͷϞσϧʹؔ࿈͚ͮΔ ◦ Like ϞσϧΛ࡞Δ ◦ ڞ௨ͷৼΔ෣͍Λ͢Δ৔߹͸ڧྗͳσʔλߏ଄ ▪ if

    จΛॻ͘ͱഁ୼͢Δ • STI: ܧঝΛ࢖ͬͯςʔϒϧΛ1ͭʹ͢Δ ◦ ProductLike ͸ Like Λܧঝ͢Δ ◦ ֤ʮ͍͍ͶʯΫϥεͰৼΔ෣͍Λগ͠ม͑Δ͜ͱ͕Ͱ͖Δ ▪ ࣗ༝౓্͕͕ΔͷͰෛ࠴͕ੜ·ΕΔՄೳੑ͕ߴ͍ 22 ৽͍͠ʮ͍͍Ͷʯͷσʔλߏ଄ͷީิ • ʮ͍͍Ͷʯ͸ɺڞ௨ͷৼΔ෣͍ͰදݱͰ͖Δ • if จΛઈରʹॻ͔ͳ͍ͱ͍͏ڧ͍ҙࢤͰϙϦ ϞʔϑΟοΫؔ࿈ʹ͢Δ
  23. • ݁ہʮ͍͍Ͷʯ͸ɺ୯७ͳ࢓༷ͩͬͨ ◦ ͔͠͠ɺαʔϏε։ൃΛਐΊͳ͍ͱΘ͔Βͳ͍ • ࠷ॳ͸มߋʹ଱͑ΒΕΔΑ͏ͳσʔλߏ଄ʹ͢Δ • ࣮૷͕ෳࡶʹͳͬͨΒσʔλߏ଄Λݟ௚͢
 • ϙϦϞʔϑΟοΫؔ࿈ͷσʔλߏ଄ͷ࿩ͱɺϦϑΝΫ

    λϦϯάͷ࿩Λ͠·͢ 23 ඞཁͳλΠϛϯάͰσʔλߏ଄Λݟ௚͢
  24. 24 ৽͍͠σʔλߏ଄: likes (Like) product_likes product_id user_id product_anonymous_likes product_id like_identifier

    topic_likes topic_id user_id topic_anonymous_likes topic_id like_identifier likes likable_id likable_type user_id anonymous_likes likable_id likable_type like_identifier • likes ͱ anonymous_likes ͷ2छྨʹ·ͱΊΔ ◦ user_id ͱ like_identifier ͸ҟͳΔσʔλͷͨΊɺಉ͡ςʔϒϧʹ͸͠ ͳ͍
  25. 25 4ͭͷϞσϧ͕1ͭͷ Like ϞσϧͰදݱ before after ʮ͍͍Ͷʯͷର৅͕૿΍ͤΔʂ ৿ཏສ৅ͷ Like Ϟσϧ

    🌲
  26. 1. ৽چͷʮ͍͍Ͷʯςʔϒϧʹॻ͖ࠐΉ (Write) 2. چ͍͍ͶΛ৽͍͍ͶʹϚΠάϨʔγϣϯ (όον) 3. ৽͍͠ʮ͍͍ͶʯΛ࢖͏ (Read) 4.

    چ͍͍ͶͷϞσϧͱςʔϒϧΛ࡟আ 26 ϦϑΝΫλϦϯά (Ҡߦͷઓུ)
  27. 27 1. ৽چͷʮ͍͍Ͷʯςʔϒϧʹॻ͖ࠐΉ (Write)

  28. 28 1. ৽چͷʮ͍͍Ͷʯςʔϒϧʹॻ͖ࠐΉ (Write)

  29. 29 2. چ͍͍ͶΛ৽͍͍ͶʹϚΠάϨʔγϣϯ (όον) product_likes product_id user_id likes likable_id 


    likable_type user_id VQTFSU@BMM͸ϚΠάϨʔγϣϯʹศརʂ
  30. 30 3. ৽͍͠ʮ͍͍ͶʯΛ࢖͏ (Read) • ྫ: ঎඼ͷ͍͍Ͷ

  31. 31 3. ৽͍͠ʮ͍͍ͶʯΛ࢖͏ (Read) • ͢΂ͯͷ͍͍Ͷͷ߹ࢉ (঎඼ɺτϐοΫ etc...)

  32. 32 3. ৽͍͠ʮ͍͍ͶʯΛ࢖͏ (Read) • ͢΂ͯͷ͍͍Ͷͷ߹ࢉ (঎඼ɺτϐοΫ etc...) શ͍͍Ͷʹڞ௨ͷॲཧΛॻ͘ͱ͖͕ศར

  33. 33 4. چ͍͍ͶͷϞσϧͱςʔϒϧΛ࡟আ • ৽͍͍ͶΛࢀরͨ͠Βɺچ͍͍Ͷͷॻ͖ࠐΈΛফ͢ • چ͍͍ͶͷϞσϧɾςʔϒϧΛ࡟আ
 • ϙϦϞʔϑΟοΫؔ࿈΁ͷҠߦ͕׬ྃ🎉

  34. • ProductLikesController ͱ TopicLikesController͸ɺ΄ ΅ಉ͡ ◦ ʮ͍͍Ͷʯͷॻ͖ࠐΈͱྫ֎ॲཧΛຖճॻ͘ͷ΋େม ◦ ʮ͍͍Ͷʯͷॻ͖ࠐΈͱྫ֎ॲཧΛ Concern

    Ͱڞ௨Խ͢Δ ▪ ஫ҙɿϨίʔυߋ৽͢Δʹؔ͢Δ΋ͷ͚ͩΛڞ௨Խ 34 ޻෉ͨ͠ͱ͜Ζ
  35. 35 Likable module -JLFΛ࡞੒ TFU@MJLBCMFΛ CFGPSF@BDUJPOͰݺͿ ྫ֎ॲཧ

  36. • create ϝιουͷத਎͸ Likable module ʹ • set_likable Ͱ likable

    Λࢦఆ͢Δ ◦ likable =ʮ͍͍Ͷʯ͞ΕΔର৅ͷ͜ͱ (ྫ: product) 36 ֤ LikesController ͕؆ܿʹʂ Products::LikesController Topics::LikesController
  37. • ࣅ͍ͯΔ͚Ͳͪΐͬͱҧ͏ʮ͍͍Ͷʯͷઃܭͷ঺հ ◦ αʔϏεϦϦʔεޙʹϙϦϞʔϑΟοΫؔ࿈ʹมߋ ▪ มߋ͕Ͱ͖ΔΑ͏ʹ࠷ॳ͸γϯϓϧͳσʔλߏ଄ʹ͢Δ ▪ ʮ͍͍ͶʯͷৼΔ෣͍͕ಉ͔ͩ͡ΒҠߦͰ͖ͨ • ϙϦϞʔϑΟοΫؔ࿈΁ͷϦϑΝΫλϦϯάͷ঺հ

    ◦ Controller ͷ Concern ΋ಋೖ • ৿ཏສ৅ʹʮ͍͍Ͷʯ͢ΔͨΊͷσʔλߏ଄͕׬੒👏 37 ·ͱΊ
  38. 38