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

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

sinsengumi
September 21, 2021

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

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