Upgrade to Pro — share decks privately, control downloads, hide ads and more …

「ドメイン駆動設計入門」
を読んだ

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for sinsengumi sinsengumi
September 21, 2021

 「ドメイン駆動設計入門」
を読んだ

Avatar for sinsengumi

sinsengumi

September 21, 2021
Tweet

More Decks by sinsengumi

Other Decks in Programming

Transcript

  1. ΞδΣϯμ • υϝΠϯۦಈઃܭ:DDD ͱ͸ʁ • ͜ͷຊʢυϝΠϯۦಈઃܭೖ໳ʣͰͲ͏͍͏͜ͱ͕Θ͔Δͷ͔ʁ • ύλʔϯ • ஋ΦϒδΣΫτ

    • ΤϯςΟςΟ • υϝΠϯαʔϏε • ϦϙδτϦ • ΞϓϦέʔγϣϯαʔϏε • ϑΝΫτϦ • ू໿ • ࢓༷ ஌ࣝʢυϝΠϯʣΛදݱ͢Δύλʔϯ ΞϓϦέʔγϣϯΛ࣮ݱ͢ΔͨΊͷύλʔϯ ஌ࣝʢυϝΠϯʣΛදݱ͢ΔɺΑΓൃలతͳύλʔϯ
  2. ʢ࠶ܝʣΞδΣϯμ • υϝΠϯۦಈઃܭ:DDD ͱ͸ʁ • ͜ͷຊʢυϝΠϯۦಈઃܭೖ໳ʣͰͲ͏͍͏͜ͱ͕Θ͔Δͷ͔ʁ • ύλʔϯ • ஋ΦϒδΣΫτ

    • ΤϯςΟςΟ • υϝΠϯαʔϏε • ϦϙδτϦ • ΞϓϦέʔγϣϯαʔϏε • ϑΝΫτϦ • ू໿ • ࢓༷ ஌ࣝʢυϝΠϯʣΛදݱ͢Δύλʔϯ ΞϓϦέʔγϣϯΛ࣮ݱ͢ΔͨΊͷύλʔϯ ஌ࣝʢυϝΠϯʣΛදݱ͢ΔɺΑΓൃలతͳύλʔϯ
  3. ஋ΦϒδΣΫτ γεςϜݻ༗ͷ஋Λදݱ͢Δ • ࠷దͳ஋͕ϓϦϛςΟϒͳ஋Ͱ͋Δͱ͸ݶΒͳ͍ • ʮෆมʯʮಉ஋ੑʢ౳Ձੑʣʯʮަ׵Մೳʯͳੑ ࣭Λ࣋ͭ • Ͳ͜·Ͱ஋ΦϒδΣΫτʹ͢Δ͔ʁ •

    ϧʔϧ͕ଘࡏʁ୯ମͰऔΓѻ͍͍ͨʁ • ;Δ·͍Λ࣋ͯΔ • ϝϦοτ • දݱྗ͕૿͢ • ෆਖ਼ͳ஋Λଘࡏͤ͞ͳ͍ • ޡͬͨ୅ೖΛ๷͙ • ϩδοΫͷࢄࡏΛ๷͙ @Getter @RequiredArgsConstructor @EqualsAndHashCode public class FullName { private final String firstName; private final String lastName; // private final String middleName; } // ੏͚ͩΛදࣔ͢Δ String fullName = "Yoshida Tomoya"; String lastName = fullName.split(" ")[0]; System.out.println(lastName); // Yoshida // ੏͚ͩΛදࣔ͢Δʢ͏·͍͔͘ͳ͍ύλʔϯʣ String fullName = "John Smith"; String lastName = fullName.split(" ")[0]; System.out.println(lastName); // John
  4. ΤϯςΟςΟ ϥΠϑαΠΫϧͷ͋ΔΦϒδΣΫτ • ଐੑͰ͸ͳ͘ಉҰੑʢidentityʣʹΑͬͯࣝผ͞Ε Δ΋ͷ • ʮՄมʯʮಉҰੑʹΑΓ۠ผ͞ΕΔʯ • ஋ΦϒδΣΫτ or

    ΤϯςΟςΟ • ϥΠϑαΠΫϧ͕͋Δ͔ʁʢϢʔβ͸࡞੒͞ Εɺ໊લΛมߋ͠ɺ࡟আ͞ΕΔʣ • ஋ΦϒδΣΫτͱΤϯςΟςΟͷͲͪΒʹ΋
 ͳΓ͏ΔʢλΠϠͷྫʣ @Getter public class User { private final UserId id; private String name; public User(UserId id, String name) { this.id = id; changeUserName(name); } public void changeUserName(String name) { if (name.length() > 30) { throw new IllegalArgumentException("Ϣʔβ໊͸30จࣈҎ಺ʹ͍ͯͩ͘͠͞"); } this.name = name; } @Override public int hashCode() { return new HashCodeBuilder().append(id).hashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof User) { User other = (User) obj; return new EqualsBuilder().append(id, other.id).isEquals(); } else { return false; } } }
  5. υϝΠϯαʔϏε υϝΠϯͷ׆ಈΛදݱ͢Δ • ஋ΦϒδΣΫτ΍ΤϯςΟςΟʹهड़͢Δͱෆࣗ વʹݟ͑Δ΋ͷ • ঢ়ଶΛ࣋ͨͳ͍ • υϝΠϯϞσϧශ݂঱ʹ஫ҙ •

    ՄೳͳݶΓυϝΠϯαʔϏεΛආ͚Δ // ࣗ෼ࣗ਎ʹ໰͍߹Θ͍ͤͯΔ UserId userId = new UserId("id"); UserName userName = new UserName("yoshida"); User user = new User(userId, userName); boolean existsUser = user.exists(user); // ॏෳ֬ೝઐ༻Πϯελϯεʹ໰͍߹Θ͍ͤͯΔ UserId userId = new UserId("id"); UserName userName = new UserName("yoshida"); User user = new User(userId, userName); UserId checkId = new UserId("check"); UserName checkName = new UserName("check"); User checkObject = new User(checkId, checkName); boolean existsUser = checkObject.exists(user); public class UserService { public boolean exists(User user) { // SQL Λୟ͍ͯ DB ʹଘࡏ͢Δ͔֬ೝ͢Δॲཧɻ௕͍ɻ // SQL Λୟ͍ͯ DB ʹଘࡏ͢Δ͔֬ೝ͢Δॲཧɻ௕͍ɻ // SQL Λୟ͍ͯ DB ʹଘࡏ͢Δ͔֬ೝ͢Δॲཧɻ௕͍ɻ // SQL Λୟ͍ͯ DB ʹଘࡏ͢Δ͔֬ೝ͢Δॲཧɻ௕͍ɻ return false; } }
  6. ϦϙδτϦ σʔλʹ·ͭΘΔॲཧΛ෼཭͢Δ • ӬଓԽʢอଘʣͱ࠶ߏஙʢ෮ݩʣΛ୲౰͢Δ • updateName, updateEmail… Λආ͚Δɻ • ΤϯςΟςΟͷมߋ͸ΤϯςΟςΟࣗ਎ʹґ

    པ͢Δ • ಛఆͷٕज़ج൫ʹґଘ͠ͳ͍ͨΊʹΠϯλϑΣʔ εΛ੾Δ • ӬଓԽ૚͔Β௚઀ΤϯςΟςΟʹϚοϐϯά͢Δ ͷ͸ආ͚Δɻ • ෆཁͳ setter Λආ͚Δ @Service public class UserService { @Autowired private UserRepository userRepository; public boolean exists(User user) { User found = userRepository.find(user.getUserName()); return found != null; } public boolean exists2(User user) { // Ϣʔβ໊ʹΑΓॏෳ֬ೝΛߦ͏ɺͱ͍͏υϝΠϯ஌͕ࣦࣝΘΕ͍ͯΔ return userRepository.exists(user); } } public interface UserRepository { void save(User user); User find(UserName userName); boolean exists(User user); }
  7. ΞϓϦέʔγϣϯ αʔϏε ϢʔεέʔεΛ࣮ݱ͢Δ • υϝΠϯΦϒδΣΫτΛ௚઀ެ։͠ͳ͍ • DTO Λ࡞Δ • Ҿ਺͕ଟ͘ͳΔ৔߹

    • ίϚϯυΦϒδΣΫτΛ࡞Δ • υϝΠϯΦϒδΣΫτͷλεΫௐ੔ʹప͢Δ • υϝΠϯͷϧʔϧͷྲྀग़ʹؾΛ͚ͭΔ • ΞϓϦέʔγϣϯαʔϏεͷ੾Γํ • ڽू౓ͰݟͯΈΔ • ͜͜΋ΠϯλϑΣʔεʹ͓ͯ͘͠ͱςετ΍෼ۀ͕ ͠΍͍͢ • ঢ়ଶ͸࣋ͨͳ͍ @Service public class UserApplicationService { @Autowired private UserRepository userRepository; @Autowired private UserService userService; public void update(UserUpdateCommand command) { UserId targetId = new UserId(command.getId()); User user = userRepository.find(targetId); if (command.getName() != null) { user.changeName(new UserName(command.getName())); if (userService.exists(user)) { throw new RuntimeException("طʹଘࡏ͍ͯ͠·͢"); } } if (command.getEmail() != null) { user.changeEmail(new Email(command.getEmail())); } userRepository.save(user); } }
  8. ϑΝΫτϦ ෳࡶͳੜ੒ॲཧΛߦ͏ • جຊ͸ίϯετϥΫλͰੜ੒ॲཧΛߦ͏΂͖ • ίϯετϥΫλ಺ͰଞͷΦϒδΣΫτΛੜ੒ ͢Δ͔Ͳ͏͔ • ͜͜΋ΠϯλϑΣʔεʹ͓ͯ͘͠ͱςετ΍෼ۀ͕ ͠΍͍͢

    • ϑΝΫτϦʹ͸2छྨ͋Δ • ΫϥεͦΕࣗମ͕ϑΝΫτϦʹͳΔ • ϝιου͕ϑΝΫτϦͱͯ͠ػೳ͢Δ @Component public class UserFactory { public User create(UserName userName) { // SQL Ͱ࣍ͷ ID ΛҾͬுͬͯ͘Δॲཧɻ௕͍ // SQL Ͱ࣍ͷ ID ΛҾͬுͬͯ͘Δॲཧɻ௕͍ // SQL Ͱ࣍ͷ ID ΛҾͬுͬͯ͘Δॲཧɻ௕͍ // SQL Ͱ࣍ͷ ID ΛҾͬுͬͯ͘Δॲཧɻ௕͍ // SQL Ͱ࣍ͷ ID ΛҾͬுͬͯ͘Δॲཧɻ௕͍ UserId userId = new UserId("hoge"); return new User(userId, userName); } }
  9. ײ૝ • Ϋϥε࡞Γա͗͌͌ɾɾɾʢDTO, ΠϯλϑΣʔε, ….ʣ • Ͳ͜ʹԿΛॻ͔͘໎͍ͦ͏ʢ૬౰܇࿅͞Εͯͳ͍ͱ೉͍͠ʣ • ·ͣɺίʔυΛॻ͖࢝ΊΔͱ͖Ϣʔεέʔε͔Βߟ͑Δ͜ͱ͕ଟ͍ͱࢥ͏ɻ
 Ϣʔβ৘ใΛมߋ͍ͨ͠

    => ΞϓϦέʔγϣϯαʔϏε
 DDD Ͱ͸υϝΠϯΦϒδΣΫτʢΤϯςΟςΟɺ஋ΦϒδΣΫτɺυϝΠϯαʔϏεʣ ͔Β࡞ΔͱݴΘΕ͍ͯΔ • ֓೦΍஌ࣝʢυϝΠϯʣΛͲ͏ίʔυͰදݱ͢Δͷ͔ʁ͸͘͢͝Θ͔Γ΍͔ͬͨ͢ • ύοέʔδߏ੒ͱ͔ͷαϯϓϧ΋͋ͬͯΑ͔ͬͨ