Architektura to nie bzdura

925 views
762 views

Published on

Prezentacja 'Architektura to nie bzdura' na DDD-Wro 15.01.2014

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
925
On SlideShare
0
From Embeds
0
Number of Embeds
13
Actions
Shares
0
Downloads
3
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Architektura to nie bzdura

  1. 1. Architektura to nie bzdura DDD-WRO Paweł Szulc – paul.szulc@gmail.com
  2. 2. Architektura to nie bzdura DDD-WRO Paweł Szulc – paul.szulc@gmail.com https://twitter.com/paulszulc
  3. 3. Architektura to nie bzdura DDD-WRO Paweł Szulc – paul.szulc@gmail.com https://twitter.com/paulszulc http://rabbitonweb.com
  4. 4. Architektura to nie bzdura
  5. 5. Architektura to nie bzdura
  6. 6. Efekt WOW
  7. 7. Efekt WOW
  8. 8. Efekt WOW
  9. 9. Efekt WOW
  10. 10. Cel prezentacji
  11. 11. Cel prezentacji Nie jest celem znalezienie złotego środka – bo taki nie istnieje ●
  12. 12. Cel prezentacji Nie jest celem znalezienie złotego środka – bo taki nie istnieje ● Nakłonić Was do dyskusji ●
  13. 13. Stack technologiczny - Wicket - Spring - Hibernate/JPA
  14. 14. Przykłady
  15. 15. Przykłady ● Aplikacja zarządzająca POI
  16. 16. Przykłady Aplikacja zarządzająca POI ● POI – ang. Point of Interest ●
  17. 17. Przykłady Grupa Aplikacja zarządzająca POI ● POI – ang. Point of Interest ● Grupa ●
  18. 18. Przykłady Grupa Aplikacja zarządzająca POI ● POI – ang. Point of Interest ● Grupa ● Podgrupa ● Podgrupa
  19. 19. Przykłady Aplikacja zarządzająca POI ● POI – ang. Point of Interest ● Grupa ● Podgrupa ● POI: nazwa, położenie (x,y) ● Grupa Podgrupa POI
  20. 20. Przykłady Aplikacja zarządzająca POI ● POI – ang. Point of Interest ● Grupa ● Podgrupa ● POI: nazwa, położenie (x,y) ● Użytkownik z prawami dostępu ● Grupa Podgrupa POI
  21. 21. Mainstreamowa architektura
  22. 22. Mainstreamowa architektura - nasz model to encje hibernetowe
  23. 23. Mainstreamowa architektura - nasz model to encje hibernetowe - logika biznesowa zamknięta w warstwie serwisowej
  24. 24. Mainstreamowa architektura - nasz model to encje hibernetowe - logika biznesowa zamknięta w warstwie serwisowej - kod zapytań do bazy danych przez obiekty typu DAO
  25. 25. Mainstreamowa architektura - nasz model to encje hibernetowe - logika biznesowa zamknięta w warstwie serwisowej - kod zapytań do bazy danych przez obiekty typu DAO - encje wykorzystywane w warstwie widoku
  26. 26. Mainstreamowa architektura Jak ją nazwać?
  27. 27. Mainstreamowa architektura Jak ją nazwać? "Model View Controler" ?
  28. 28. Mainstreamowa architektura "Architektura trójwarstwowa" ?
  29. 29. Mainstreamowa architektura "Entity-DAO-Service-View" ?
  30. 30. Mainstreamowa architektura "Encje na twarz i pchasz"
  31. 31. Mainstreamowa architektura "Encje na twarz i pchasz"
  32. 32. Czemu nie używać, skoro działa?
  33. 33. ● Encja User.java
  34. 34. ● Encja User.java ● UserService.java
  35. 35. ● Encja User.java ● UserService.java (List<User> findAll())
  36. 36. ● Encja User.java ● UserService.java (List<User> findAll()) ● UserServiceImpl.java
  37. 37. ● Encja User.java ● UserService.java (List<User> findAll()) ● UserServiceImpl.java public List<User> findAll() { userDao.findAll(); }
  38. 38. ● Encja User.java ● UserService.java (List<User> findAll()) ● UserServiceImpl.java public List<User> findAll() { userDao.findAll(); } ● UserDao.java
  39. 39. ● Encja User.java ● UserService.java (List<User> findAll()) ● UserServiceImpl.java public List<User> findAll() { userDao.findAll(); } ● UserDao.java ● UserDaoImpl.java
  40. 40. Encja -> DAO -> Serwis ● Single responsibility principle
  41. 41. Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki
  42. 42. Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas
  43. 43. Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas ● DAO – data access object?
  44. 44. Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas DAO – data access object? user.getContest().getOwner() ●
  45. 45. public interface PoiDAO extends DAO<PoiEntity, Long> { List<PoiEntity> findFiltered(PoiListingFilterWrapper wrapper); List<PoiEntity> findAllInSubgroup(SubgroupEntity subgroup); List<PoiEntity> findTextFiltered(SubgroupEntity subgroup, String textFilter); List<PoiEntity> findTextFilteredOnStreet(StreetEntity street, String textFilter); List<PoiEntity> filterPoisByTextPhrase(String searchPhrase, int start, int count); List<PoiEntity> filterPoisWithTypeByTextPhrase(String filter, int start, int maxAllowedResults); .... }
  46. 46. Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas ● DAO – data access object?
  47. 47. Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas ● DAO – data access object? ● Metody biznesowe?
  48. 48. public interface PoiDAO extends DAO<PoiEntity, Long> { List<PoiEntity> findFiltered(PoiListingFilterWrapper wrapper); List<PoiEntity> findAllInSubgroup(SubgroupEntity subgroup); List<PoiEntity> findTextFiltered(SubgroupEntity subgroup, String textFilter); List<PoiEntity> findTextFilteredOnStreet(StreetEntity street, String textFilter); List<PoiEntity> filterPoisByTextPhrase(String searchPhrase, int start, int count); List<PoiEntity> filterPoisWithTypeByTextPhrase(String filter, int start, int maxAllowedResults); void save(PoiEntity poi); void update(PoiEntity poi); }
  49. 49. Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI.
  50. 50. PoiEntity poi = poiService.find(poiId);
  51. 51. PoiEntity poi = poiService.find(poiId); createForm(poi);
  52. 52. PoiEntity poi = poiService.find(poiId); createForm(poi); ... new Button("save") { public void onSubmit() { poiService.update(poi); } }
  53. 53. PoiEntity poi = poiService.find(poiId); createForm(poi); ... new Button("save") { public void onSubmit() { mailSender.send(body()) poiService.update(poi); } }
  54. 54. PoiEntity poi = poiService.find(poiId); createForm(poi); ... new Button("save") { public void onSubmit() { mailSender.send(body()) poiService.update(poi); } } // x i y nie mogą być ujemne
  55. 55. Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI.
  56. 56. Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI.
  57. 57. Encja na widoku, i co z tego? ● Ważne pytanie dla encji...
  58. 58. Encja na widoku, i co z tego? ● Ważne pytanie dla encji – czy już zna Cię PersistenceContext?
  59. 59. Encja na widoku, i co z tego? ● ● Ważne pytanie dla encji – czy już zna Cię PersistenceContext? Algorytm tworzenia widoku jak i sama jego struktura oparta o encje
  60. 60. Encja na widoku, i co z tego? ● ● Ważne pytanie dla encji – czy już zna Cię PersistenceContext? Algorytm tworzenia widoku jak i sama jego struktura oparta o encje  Widok mocno związany ze strukturą bazy
  61. 61. Encja na widoku, i co z tego? ● ● Ważne pytanie dla encji – czy już zna Cię PersistenceContext? Algorytm tworzenia widoku jak i sama jego struktura oparta o encje  Widok mocno związany ze strukturą bazy  Skostniałość - dashboard
  62. 62. Dashboard A
  63. 63. Dashboard A B C D E
  64. 64. Dashboard A A A A B C D A E
  65. 65. Dashboard A A A A B C A D A1 A2 B1 E B2 B3 C1 C2 C3 C4 E1
  66. 66. Encja na widoku, i co z tego? ● ● Ważne pytanie dla encji – czy już zna Cię PersistenceContext? Algorytm tworzenia widoku jak i sama jego struktura oparta o encje  Widok mocno związany ze strukturą bazy  Skostniałość – dashboard
  67. 67. Encja na widoku, i co z tego? ● ● Ważne pytanie dla encji – czy już zna Cię PersistenceContext? Algorytm tworzenia widoku jak i sama jego struktura oparta o encje   ● Widok mocno związany ze strukturą bazy Skostniałość – dashboard LazyInitializationException
  68. 68. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
  69. 69. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
  70. 70. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
  71. 71. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois(); LazyInitializationException
  72. 72. STOP – This is Hibernate Police!
  73. 73. STOP – This is Hibernate Police! A obywatel o Open Session In View nie słyszał?
  74. 74. Open Session In View Transaction.begin
  75. 75. Open Session In View Transaction.begin
  76. 76. Open Session In View Transaction.begin
  77. 77. Open Session In View Transaction.begin
  78. 78. Open Session In View Transaction.begin
  79. 79. Open Session In View Transaction.commit
  80. 80. Open Session In View REQUEST Transaction.begin Transaction.commit Transaction.begin Transaction.commit Transaction.begin Transaction.commit RESPONSE
  81. 81. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
  82. 82. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
  83. 83. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois(); select * from t_pois where id = :poiId;
  84. 84. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois(); select * from t_pois where id = :poiId; select * from t_pois where ....
  85. 85. List<PoiEntity> pois = poiService.findForUser(user); for(PoiEntity p : pois) { poi.getConnectedPois(); }
  86. 86. List<PoiEntity> pois = poiService.findForUser(user); for(PoiEntity p : pois) { poi.getConnectedPois(); } select * from t_pois where user_id = :uId;
  87. 87. List<PoiEntity> pois = poiService.findForUser(user); for(PoiEntity p : pois) { poi.getConnectedPois(); } select * from t_pois where user_id = :uId; select * from t_pois where ...
  88. 88. List<PoiEntity> pois = poiService.findForUser(user); for(PoiEntity p : pois) { poi.getConnectedPois(); } select * from t_pois where user_id = :uId; select * from t_pois where ... select * from t_pois where ...
  89. 89. List<PoiEntity> pois = poiService.findForUser(user); for(PoiEntity p : pois) { poi.getConnectedPois(); } select * from t_pois where user_id = :uId; select * from t_pois where ... select * from t_pois where ... select * from t_pois where ...
  90. 90. List<PoiEntity> pois = poiService.findForUser(user); for(PoiEntity p : pois) { poi.getConnectedPois(); } select * from t_pois where user_id = :uId; select * from t_pois where ... select * from t_pois where ... select * from t_pois where ... select * from t_pois where ... select * from t_pois where ...
  91. 91. List<PoiEntity> pois = poiService.findForUser(user); for(PoiEntity p : pois) { poi.getConnectedPois(); } select * from t_pois where user_id = :uId; select * from t_pois where ... select * from t_pois where ... select * from t_pois where ... select * from t_pois where ... select * from t_pois where ...
  92. 92. Encja na widoku, i co z tego? ● ● Ważne pytanie dla encji – czy już zna Cię PersistenceContext? Algorytm tworzenia widoku jak i sama jego struktura oparta o encje   ● Widok mocno związany ze strukturą bazy Skostniałość – dashboard LazyInitializationException
  93. 93. Encja na widoku, i co z tego? ● ● Ważne pytanie dla encji – czy już zna Cię PersistenceContext? Algorytm tworzenia widoku jak i sama jego struktura oparta o encje  Widok mocno związany ze strukturą bazy  Skostniałość – dashboard ● LazyInitializationException ● Testowalność
  94. 94. Encja na widoku, i co z tego? ● ● Ważne pytanie dla encji – czy już zna Cię PersistenceContext? Algorytm tworzenia widoku jak i sama jego struktura oparta o encje  Widok mocno związany ze strukturą bazy  Skostniałość – dashboard ● LazyInitializationException ● Testowalność  "Testy już przechodzą, muszę jeszcze tylko przeklikać"
  95. 95. Zamknięcie logiki biznesowej
  96. 96. Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa serwisowa Warstwa bazodanowa
  97. 97. Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa aplikacji Warstwa serwisowa Warstwa bazodanowa
  98. 98. Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa aplikacji Warstwa serwisowa Warstwa bazodanowa
  99. 99. Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa aplikacji Warstwa serwisowa Warstwa bazodanowa public interface UCListingPoisForGivenSubgroup { List<PoiDto> list(Long subgroupId) }
  100. 100. Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa aplikacji Warstwa serwisowa Warstwa bazodanowa public interface UserFromClientProvider { UserDto provide(); }
  101. 101. Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa aplikacji Warstwa serwisowa Warstwa bazodanowa public class UserProvider implements UserFromClientProvider { public UserDto provide() { return userSession.getUser(); } } public interface UserFromClientProvider { UserDto provide(); }
  102. 102. Warstwa aplikacji – organizacja
  103. 103. Warstwa aplikacji – organizacja ● Jest abstrakcją aplikacji
  104. 104. Warstwa aplikacji – organizacja ● Jest abstrakcją aplikacji ● Aplikacja to zbiór funkcjonalności
  105. 105. Warstwa aplikacji – organizacja ● Jest abstrakcją aplikacji ● Aplikacja to zbiór funkcjonalności ● Funkcjonalności zdefiniowane (w ten czy inny sposób)
  106. 106. Warstwa aplikacji – organizacja ● Jest abstrakcją aplikacji ● Aplikacja to zbiór funkcjonalności ● ● Funkcjonalności zdefiniowane (w ten czy inny sposób) Z natury bardzo 'proceduralne'
  107. 107. Warstwa aplikacji – organizacja
  108. 108. Warstwa aplikacji – organizacja
  109. 109. Warstwa aplikacji – organizacja
  110. 110. Warstwa aplikacji – organizacja ● Jest abstrakcją aplikacji ● Aplikacja to zbiór funkcjonalności ● ● Funkcjonalności zdefiniowane (w ten czy inny sposób) Z natury bardzo 'proceduralne'
  111. 111. Warstwa aplikacji – organizacja ● Jest abstrakcją aplikacji ● Aplikacja to zbiór funkcjonalności ● ● ● Funkcjonalności zdefiniowane (w ten czy inny sposób) Z natury bardzo 'proceduralne' Przełożenie tych definicji na klasy, które definiują dany konkretny wycinek funkcjonalności
  112. 112. ● Jako użytkownik z prawem 'szczegóły poi' mogę wylistować wszystkie POI w danej podgrupie  widzę nazwę, położenie oraz listę innych POI, z którym dane POI jest powiązane
  113. 113. ● Jako użytkownik z prawem 'szczegóły poi' mogę wylistować wszystkie POI w danej podgrupie  widzę nazwę, położenie oraz listę innych POI, z którym dane POI jest powiązane public interface UCListingPoiDetails { List<PoiDto> list(Long subgroupId); boolean canList(Long subgroupId); }
  114. 114. ● Jako użytkownik z prawem 'szczegóły poi' mogę wylistować wszystkie POI w danej podgrupie  widzę nazwę, położenie oraz listę innych POI, z którym dane POI jest powiązane public interface UCListingPoiDetails { List<PoiDto> list(Long subgroupId); boolean canList(Long subgroupId); } public class PoiDto { private final String name; private final Coordinates coordinates; private final List<PoiDto> connectedPois; }
  115. 115. ● Jako użytkownik z prawem 'szczegóły poi' mogę wylistować wszystkie POI w danej podgrupie  widzę nazwę, położenie oraz listę innych POI, z którym dane POI jest powiązane public interface UCListingPoiDetails { List<PoiDto> list(Long subgroupId); boolean canList(Long subgroupId); } @Data public class PoiDto { private final String name; private final Coordinates coordinates; private final List<PoiDto> connectedPois; }
  116. 116. ● Jako użytkownik z prawem 'szczegóły poi' mogę wylistować wszystkie POI w danej podgrupie  widzę nazwę, położenie oraz listę innych POI, z którym dane POI jest powiązane public interface UCListingPoiDetails { List<PoiDto> list(Long subgroupId); boolean canList(Long subgroupId); }
  117. 117. ● Jako użytkownik z prawem 'szczegóły poi' mogę wylistować wszystkie POI w danej podgrupie  widzę nazwę, położenie oraz listę innych POI, z którym dane POI jest powiązane public interface UCListingPoiDetails { List<PoiDto> list(Long subgroupId); boolean canList(Long subgroupId); }
  118. 118. ● Jako użytkownik z prawem 'szczegóły poi' mogę wylistować wszystkie POI w danej podgrupie  widzę nazwę, położenie oraz listę innych POI, z którym dane POI jest powiązane public interface UCListingPoiDetails { List<PoiDto> list(Long subgroupId); ActionPossible canList(Long subgroupId); } public interface ActionPossible { boolean isPossible(); String explainImpossible(); }
  119. 119. ● Jako użytkownik z prawem 'szczegóły poi' mogę wylistować wszystkie POI w danej podgrupie  widzę nazwę, położenie oraz listę innych POI, z którym dane POI jest powiązane public class SubGroupPoisListPanel { @Autowired private UCListingPoiDetails uc; ... public SubGroupPoisListPanel(Long subgroupId) { ActionPossible canList = uc.canList(); if(canList.isPossible() { add(createList(uc.list(subgroupId)); } else { String reason = canList.explainImpossible(); add(new Label("info", reason); } }
  120. 120. ● Jako użytkownik z prawem 'szczegóły poi' mogę wylistować wszystkie POI w danej podgrupie  widzę nazwę, położenie oraz listę innych POI, z którym dane POI jest powiązane public class SubGroupPoisListPanel { @Autowired private UCListingPoiDetails uc; ... public SubGroupPoisListPanel(Long subgroupId) { ActionPossible canList = uc.canList(); if(canList.isPossible() { add(createList(uc.list(subgroupId)); } else { String reason = canList.explainImpossible(); add(new Label("info", reason); } }
  121. 121. ● Jako użytkownik z prawem 'szczegóły poi' mogę wylistować wszystkie POI w danej podgrupie  widzę nazwę, położenie oraz listę innych POI, z którym dane POI jest powiązane public class SubGroupPoisListPanel { @Autowired private UCListingPoiDetails uc; ... public SubGroupPoisListPanel(Long subgroupId) { ActionPossible canList = uc.canList(); if(canList.isPossible() { add(createList(uc.list(subgroupId)); } else { String reason = canList.explainImpossible(); add(new Label("info", reason); } }
  122. 122. ● Jako użytkownik z prawem 'szczegóły poi' mogę wylistować wszystkie POI w danej podgrupie  widzę nazwę, położenie oraz listę innych POI, z którym dane POI jest powiązane public class SubGroupPoisListPanel { @Autowired private UCListingPoiDetails uc; ... public SubGroupPoisListPanel(Long subgroupId) { ActionPossible canList = uc.canList(); if(canList.isPossible() { add(createList(uc.list(subgroupId)); } else { String reason = canList.explainImpossible(); add(new Label("info", reason); } }
  123. 123. ● Jako użytkownik z prawem 'szczegóły poi' mogę wylistować wszystkie POI w danej podgrupie  widzę nazwę, położenie oraz listę innych POI, z którym dane POI jest powiązane public class SubGroupPoisListPanel { @Autowired private UCListingPoiDetails uc; ... public SubGroupPoisListPanel(Long subgroupId) { ActionPossible canList = uc.canList(); if(canList.isPossible() { add(createList(uc.list(subgroupId)); } else { String reason = canList.explainImpossible(); add(new Label("info", reason); } }
  124. 124. ● Jako użytkownik z prawem 'szczegóły poi' mogę wylistować wszystkie POI w danej podgrupie  widzę nazwę, położenie oraz listę innych POI, z którym dane POI jest powiązane public class SubGroupPoisListPanel { @Autowired private UCListingPoiDetails uc; ... public SubGroupPoisListPanel(Long subgroupId) { ActionPossible canList = uc.canList(); if(canList.isPossible() { add(createList(uc.list(subgroupId)); } else { String reason = canList.explainImpossible(); add(new Label("info", reason); } }
  125. 125. ● Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI public interface UCUpdatingPoiCoordinates { void update(Long poiId, Coordinates c); ActionPossible canUpdate(); ActionPossible canUpdateWithArgs( Long poiId, Coordinates c); }
  126. 126. ● Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI @Autowired private UCUpdatingPoiCoordinates uc; Button update = new Button("update") { public void onSubmit() { ActionPossible withArgs = uc.canUpdateWithArgs(poiId, coords); if(withArgs.isPossible()) uc.update(poiId, coords) else userSession.warn(withArgs.explainImpossible()); } } update.setVisible(uc.canUpdate().isPossible());
  127. 127. ● Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI @Autowiredprivate UCUpdatingPoiCoordinates uc; Button update = new Button("update") { public void onSubmit() { ActionPossible withArgs = uc.canUpdateWithArgs(poiId, coords); if(withArgs.isPossible()) uc.update(poiId, coords) else userSession.warn(withArgs.explainImpossible()); } } update.setVisible(uc.canUpdate().isPossible());
  128. 128. ● Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI @Autowired private UCUpdatingPoiCoordinates uc; Button update = new Button("update") { public void onSubmit() { ActionPossible withArgs = uc.canUpdateWithArgs(poiId, coords); if(withArgs.isPossible()) uc.update(poiId, coords) else userSession.warn(withArgs.explainImpossible()); } } update.setVisible(uc.canUpdate().isPossible());
  129. 129. ● Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI @Autowired private UCUpdatingPoiCoordinates uc; Button update = new Button("update") { public void onSubmit() { ActionPossible withArgs = uc.canUpdateWithArgs(poiId, coords); if(withArgs.isPossible()) uc.update(poiId, coords) else userSession.warn(withArgs.explainImpossible()); } } update.setVisible(uc.canUpdate().isPossible());
  130. 130. ● Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI @Autowired private UCUpdatingPoiCoordinates uc; Button update = new Button("update") { public void onSubmit() { ActionPossible withArgs = uc.canUpdateWithArgs(poiId, coords); if(withArgs.isPossible()) uc.update(poiId, coords) else userSession.warn(withArgs.explainImpossible()); } } update.setVisible(uc.canUpdate().isPossible());
  131. 131. ● Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI @Autowired private UCUpdatingPoiCoordinates uc; Button update = new Button("update") { public void onSubmit() { ActionPossible withArgs = uc.canUpdateWithArgs(poiId, coords); if(withArgs.isPossible()) uc.update(poiId, coords) else userSession.warn(withArgs.explainImpossible()); } } update.setVisible(uc.canUpdate().isPossible());
  132. 132. ● Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI @Autowired private UCUpdatingPoiCoordinates uc; Button update = new Button("update") { public void onSubmit() { ... } } update.setVisible(uc.canUpdate().isPossible());
  133. 133. ● Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI @Autowired private UCUpdatingPoiCoordinates uc; Button update = new Button("update") { public void onSubmit() { ... } } ActionPossible canUpdate = uc.canUpdate(); update.setEnabled(canUpdate.isPossible()); if(!canUpdate.isPossible()) { String reason = canUpdate.explainImpossible(); update.add(new TooltTip(reason)); }
  134. 134. Problem jednego stack'a ID Nazwa Data utworzenia Stan 1 Konkurs 1 05.07.2013 Nowy 2 Konkurs 2 01.06.2013 Zamknięty 3 Konkurs 3 15.06.2013 Uruchomiony
  135. 135. Problem jednego stack'a @Entity public class Contest { @Id private Long id; private String name; private LocalDate creationDate; @Enumerated private State state; ID Nazwa Data utworzenia Stan 1 Konkurs 1 05.07.2013 Nowy 2 Konkurs 2 01.06.2013 Zamknięty 3 Konkurs 3 15.06.2013 Uruchomiony
  136. 136. Problem jednego stack'a @Entity public class Contest { @Id private Long id; private String name; private LocalDate creationDate; @Enumerated private State state; public Contest(String name) { this.name = name; this.creationDate = new LocalDate(); this.state = State.NOWY; } ID Nazwa Data utworzenia Stan 1 Konkurs 1 05.07.2013 Nowy 2 Konkurs 2 01.06.2013 Zamknięty 3 Konkurs 3 15.06.2013 Uruchomiony
  137. 137. Problem jednego stack'a @Entity public class Contest { ... public void start() { .. } public void close() { .. } public boolean isAnnual() { .. } } ID Nazwa Data utworzenia Stan 1 Konkurs 1 05.07.2013 Nowy 2 Konkurs 2 01.06.2013 Zamknięty 3 Konkurs 3 15.06.2013 Uruchomiony
  138. 138. Problem jednego stack'a @Entity public class Contest { ... public void start() { .. } public void close() { .. } public boolean isAnnual() { .. } } ID Nazwa Data utworzenia Stan 1 Konkurs 1 05.07.2013 Nowy 2 Konkurs 2 01.06.2013 Zamknięty 3 Konkurs 3 15.06.2013 Uruchomiony
  139. 139. Problem jednego stack'a @Entity public class Contest { ... public void start() { .. } public void close() { .. } public boolean isAnnual() { .. } } okej.. Chce taki panel ID Nazwa Data utworzenia Stan 1 Konkurs 1 05.07.2013 Nowy 2 Konkurs 2 01.06.2013 Zamknięty 3 Konkurs 3 15.06.2013 Uruchomiony
  140. 140. Problem jednego stack'a @Entity public class Contest { ... public void start() { .. } public void close() { .. } public boolean isAnnual() { .. } public String getName() {..} public LocalDate getCreationDate() {..} public State getState() {..} } ID Nazwa Data utworzenia Stan 1 Konkurs 1 05.07.2013 Nowy 2 Konkurs 2 01.06.2013 Zamknięty 3 Konkurs 3 15.06.2013 Uruchomiony
  141. 141. Rozwiązania ● CQRS
  142. 142. Rozwiązania ● CQRS
  143. 143. Rozwiązania ● CQRS ● CQRS dla ubogich :)
  144. 144. Rozwiązania ● CQRS ● CQRS dla ubogich :) ● Rozróżnienie na Command i Query
  145. 145. Rozwiązania ● CQRS ● CQRS dla ubogich :) ● ● ● Rozróżnienie na Command i Query Obiekty modelu (User, Poi, Subgroup) i serwisy (UserCreator) używane do obsługi poleceń Specjalne serwisy typu Query używane do obsługi zapytań
  146. 146. Rozwiązania ● CQRS ● CQRS dla ubogich :) ● ● ● ● Rozróżnienie na Command i Query Obiekty modelu (User, Poi, Subgroup) i serwisy (UserCreator) używane do obsługi poleceń Specjalne serwisy typu Query używane do obsługi zapytań Query niczym Wyrocznia
  147. 147. public interface UCListingPoiDetails { List<PoiDto> list(Long subgroupId); ActionPossible canList(); }
  148. 148. @Service public class DefaultUCListingPoiDetails implements UCListingPoiDetails { @Autowired private ClientFromUserProvider userProvider; public ActionPossible canList() { UserDto user = userProvider.provide(); if(user != null) { return user != null && user.hasRight(AR.POI_DETAILS); } return impossible("User not logged in"); } public List<PoiDto> list(Long subgroupId) {..}
  149. 149. @Service public class DefaultUCListingPoiDetails implements UCListingPoiDetails { @Autowired private UserAuthorization userAuthorization; public ActionPossible canList() { return userAuthorization.hasRight(AR.POI_DETAILS); } public List<PoiDto> list(Long subgroupId) {..} }
  150. 150. @Service public class DefaultUCListingPoiDetails implements UCListingPoiDetails { @Autowired private UserAuthorization userAuthorization; public ActionPossible canList() { .. } public List<PoiDto> list(Long subgroupId) {..} }
  151. 151. @Service public class DefaultUCListingPoiDetails implements UCListingPoiDetails { @Autowired private UserAuthorization userAuthorization; public ActionPossible canList() { .. } public List<PoiDto> list(Long subgroupId) { } }
  152. 152. @Service public class DefaultUCListingPoiDetails implements UCListingPoiDetails { @Autowired private UserAuthorization userAuthorization; public ActionPossible canList() { .. } public List<PoiDto> list(Long subgroupId) { checkThat(canList()); } }
  153. 153. @Service public class DefaultUCListingPoiDetails implements UCListingPoiDetails { @Autowired private UserAuthorization userAuthorization; @Autowired private ListingPoiDetailsQuery query; public ActionPossible canList() { .. } public List<PoiDto> list(Long subgroupId) { checkThat(canList()); return query.execute(subgroupId); } }
  154. 154. public interface UCUpdatingPoiCoordinates { void update(Long poiId, Coordinates c); ActionPossible canUpdate(); ActionPossible canUpdateWithArgs( Long poiId, Coordinates c); }
  155. 155. @Service public class DefaultUCUpdatingPoiCoordinates implements UCUpdatingPoiCoordinates { public ActionPossible canUpdate() {..} ActionPossible canUpdateWithArgs(Long poiId, Coordinates c) {..} public void update(Long poiId, Coordinates c) {..} }
  156. 156. @Service public class DefaultUCUpdatingPoiCoordinates implements UCUpdatingPoiCoordinates { public ActionPossible canUpdate() {..} ActionPossible canUpdateWithArgs(Long poiId, Coordinates c) {..} public void update(Long poiId, Coordinates c) { } }
  157. 157. @Service public class DefaultUCUpdatingPoiCoordinates implements UCUpdatingPoiCoordinates { public ActionPossible canUpdate() {..} ActionPossible canUpdateWithArgs(Long poiId, Coordinates c) {..} public void update(Long poiId, Coordinates c) { checkThat(canUpdate()); } }
  158. 158. @Service public class DefaultUCUpdatingPoiCoordinates implements UCUpdatingPoiCoordinates { public ActionPossible canUpdate() {..} ActionPossible canUpdateWithArgs(Long poiId, Coordinates c) {..} public void update(Long poiId, Coordinates c) { checkThat(canUpdate()); checkArguments(canUpdateWithArgs(poiId,c)); } }
  159. 159. @Service public class DefaultUCUpdatingPoiCoordinates implements UCUpdatingPoiCoordinates { @Autowired PoiFinder poiFinder; public ActionPossible canUpdate() {..} ActionPossible canUpdateWithArgs(Long poiId, Coordinates c) {..} public void update(Long poiId, Coordinates c) { checkThat(canUpdate()); checkArguments(canUpdateWithArgs(poiId,c)); poiFinder.find(poiId).updateCoordinates(c); } }
  160. 160. @Service public class DefaultUCUpdatingPoiCoordinates implements UCUpdatingPoiCoordinates { @Autowired PoiFinder poiFinder; @Autowired MailSender mailSender; public ActionPossible canUpdate() {..} ActionPossible canUpdateWithArgs(Long poiId, Coordinates c) {..} public void update(Long poiId, Coordinates c) { checkThat(canUpdate()); checkArguments(canUpdateWithArgs(poiId,c)); poiFinder.find(poiId).updateCoordinates(c); mailSender.send(createContent()); }
  161. 161. Warstwa Application ● przejrzyste API zorientowane na przypadki użycia
  162. 162. Warstwa Application ● ● przejrzyste API zorientowane na przypadki użycia testowalność
  163. 163. Warstwa Application ● przejrzyste API zorientowane na przypadki użycia ● testowalność ● "głupi" widok, wiele warstw prezentacji
  164. 164. Warstwa Application ● przejrzyste API zorientowane na przypadki użycia ● testowalność ● "głupi" widok, wiele warstw prezentacji ● wejście w projekt
  165. 165. Warstwa Application ● przejrzyste API zorientowane na przypadki użycia ● testowalność ● "głupi" widok, wiele warstw prezentacji ● wejście w projekt ● polyglot programmer
  166. 166. Warstwa Application ● przejrzyste API zorientowane na przypadki użycia ● testowalność ● "głupi" widok, wiele warstw prezentacji ● wejście w projekt ● polyglot programmer ● chodliwe funkcjonalności niemalże za darmo
  167. 167. Warstwa Application ● przejrzyste API zorientowane na przypadki użycia ● testowalność ● "głupi" widok, wiele warstw prezentacji ● wejście w projekt ● polyglot programmer ● chodliwe funkcjonalności niemalże za darmo ● Excel export
  168. 168. Warstwa Application ● przejrzyste API zorientowane na przypadki użycia ● testowalność ● "głupi" widok, wiele warstw prezentacji ● wejście w projekt ● polyglot programmer ● chodliwe funkcjonalności niemalże za darmo ● Excel export ● Aktywność użytkownika
  169. 169. @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Audit { public String value() default ""; }
  170. 170. @Aspect @Configurable public class AuditAspect { @Autowired private AuditLogger auditLogger; @Around("@annotation(audit)") public Object around(ProceedingJoinPoint joinPoint, Audit audit) throws Throwable { DateTime start = DateTime.now(); Object proceed = joinPoint.proceed(); long executionTime = DateTime.now().getMillis() start.getMillis(); auditLogger.log(getActionName(joinPoint), audit.value(),getParameters(joinPoint), start, executionTime); }
  171. 171. Obiekty Modelu
  172. 172. Obiekty Modelu ● Encja jest obiektem reprezentującym model
  173. 173. Obiekty Modelu ● Encja jest obiektem reprezentującym model ● Gettery/settery defacto wymagane
  174. 174. Obiekty Modelu ● Encja jest obiektem reprezentującym model ● Gettery/settery defacto wymagane ● Metody typu add, remove
  175. 175. Obiekty Modelu ● Encja jest obiektem reprezentującym model ● Gettery/settery defacto wymagane ● Metody typu add, remove ● Metody "biznesowe" (run(), isRunning(), close())
  176. 176. Obiekty Modelu ● Encja jest obiektem reprezentującym model ● Gettery/settery defacto wymagane ● Metody typu add, remove ● ● Metody "biznesowe" (run(), isRunning(), close()) Troche bardziej skomplikowana encja może mieć nawet i kilka tysięcy linii kodu
  177. 177. Obiekty Modelu ● Encja jest obiektem reprezentującym model ● Gettery/settery defacto wymagane ● Metody typu add, remove ● ● ● Metody "biznesowe" (run(), isRunning(), close()) Troche bardziej skomplikowana encja może mieć nawet i kilka tysięcy linii kodu Encja nie jest ani strukturą danych, ani obiektem (metoda canRun() obok getState())
  178. 178. Pomysł... ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym
  179. 179. Pomysł... ● ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym Encje jedynie jako reprezentacje tabel
  180. 180. Pomysł... ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym ● Encje jedynie jako reprezentacje tabel ● Encja anemiczna
  181. 181. Pomysł... @Entity public class UserEntity { }
  182. 182. Pomysł... @Entity public class UserEntity { @Id private Long id; private String login; @OneToMany private Set<RoleEntity> roles; }
  183. 183. Pomysł... @Entity public class UserEntity { @Id private Long id; private String login; @OneToMany private Set<RoleEntity> roles; Long getId() {..}, void setId(Long id) {..} Long getLogin() {..}, void setLogin(String lo) {..} Set<RoleEntity> getRoles() {..}, void setRoles(Set<RoleEntity> roles) {..} }
  184. 184. Pomysł... @Entity public class UserEntity { @Id private Long id; private String login; @OneToMany private Set<RoleEntity> roles; Long getId() {..}, void setId(Long id) {..} Long getLogin() {..}, void setLogin(String lo) {..} Set<RoleEntity> getRoles() {..}, void setRoles(Set<RoleEntity> roles) {..} void addRole(RoleEntity role) {..} void removeRole(RoleEntity role) {..} }
  185. 185. Pomysł... @Entity @Data public class UserEntity { @Id private Long id; private String login; @OneToMany private Set<RoleEntity> roles; void addRole(RoleEntity role) {..} void removeRole(RoleEntity role) {..} }
  186. 186. Pomysł - obiekt biznesowy ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym ● Encje jedynie jako reprezentacje tabel ● Encja anemiczna
  187. 187. Pomysł - obiekt biznesowy ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym ● Encje jedynie jako reprezentacje tabel ● Encja anemiczna ● Obiekt biznesowy – reprezentant modelu
  188. 188. Pomysł - obiekt biznesowy ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym ● Encje jedynie jako reprezentacje tabel ● Encja anemiczna ● Obiekt biznesowy – reprezentant modelu  na początku można o nim myśleć jako wrapper na encję
  189. 189. Pomysł - obiekt biznesowy ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym ● Encje jedynie jako reprezentacje tabel ● Encja anemiczna ● Obiekt biznesowy – reprezentant modelu   na początku można o nim myśleć jako wrapper na encję udostępnia zestaw metod biznesowych pozwalających operować na konkretnym modelu, który reprezentuje (i tylko na nim)
  190. 190. Pomysł - obiekt biznesowy ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym ● Encje jedynie jako reprezentacje tabel ● Encja anemiczna ● Obiekt biznesowy – reprezentant modelu    na początku można o nim myśleć jako wrapper na encję udostępnia zestaw metod biznesowych pozwalających operować na konkretnym modelu, który reprezentuje (i tylko na nim) nie istnieje "niezapisany"
  191. 191. @Configurable public abstract class BusinessObject<T extends Identifiable<K>, K> implements Serializable { protected T entity; private Class<T> clazz; @PersistenceContext private EntityManager entityManager; public BusinessObject(T entity, Class<T> clazz) { this.entity = checkNotNull(entity); this.clazz = clazz; } public T attached() { return entityManager().find(clazz, entity.getId()); } public K getId() { return attached().getId(); } public boolean equals(Object o) { .. } public int hashCode() {..}
  192. 192. @Configurable public class User extends BusinessObject<UserEntity, Long> { public User(UserEntity entity) { super(entity, UserEntity.class); } }
  193. 193. @Configurable public class User extends BusinessObject<UserEntity, Long> { public User(UserEntity entity) { super(entity, UserEntity.class); } public void addRole(Role role) { attached().addRole(role.attached()); attached().setLastModificationDate(new DateTime()); } }
  194. 194. @Service public class UserCreator { @PersistenceContext private EntityManager entityManager; @Transactional public User create(final String login) { UserEntity entity = new UserEntity(); entity.setLogin(login); entity.setCreationDate(new DateTime()); entityManager.persist(entity); return new User(entity); } }
  195. 195. @Configurable public class Group extends BusinessObject<GroupEntity, Long> { public Group(GroupEntity entity) {.. } public Subgroup addSubgroup(String name) { SubgroupEntity se = new SubgroupEntity(); se.setName(name); attached().addSubgroup(se); entityManager.persist(se); return new Subgroup(se); } }
  196. 196. @Service public class UserFinder { @PersistenceContext private EntityManager entityManager; @Transactional(readOnly = true) public User find(Long id) { UserEntity entity = entityManager.find(UserEntity.class, id); return entity == null ? null : new User(entity); } }
  197. 197. @Service public class DefaultUCUpdatingPoiCoordinates implements UCUpdatingPoiCoordinates { @Autowired PoiFinder poiFinder; @Autowired MailSender mailSender; public ActionPossible canUpdate() {..} ActionPossible canUpdateWithArgs(Long poiId, Coordinates c) {..} public void update(Long poiId, Coordinates c) { checkThat(canUpdate()); checkArguments(canUpdateWithArgs(poiId,c)); poiFinder.find(poiId).updateCoordinates(c); mailSender.send(createContent()); }
  198. 198. Obiekty biznesowe ● Tylko metody związane z operacjami na modelu ● Podobiekty (realizujące zakres funkcjonalności)
  199. 199. finish launch new running closed
  200. 200. public class Contest extends BusinessObject<ContestEntity, Long> { public boolean isLaunchable() {..} public void launch() {..} public boolean isFinishable() {..} public void finish() {..} ... }
  201. 201. public class Contest extends BusinessObject<ContestEntity, Long> { public ContestLifecycle lifecycle() { return new ContestLifecycle(attached()); } } public class ContestLifecycle extends BusinessObject<ContestEntity, Long> { public boolean isLaunchable() {..} public void launch() {..} public boolean isFinishable() {..} public void finish() {..} }
  202. 202. public class NewContest extends BusinessObject<ContestEntity, Long> { public RunningContest launch() {..} } public class RunningContest extends BusinessObject<ContestEntity, Long> { public ClosedContest finish() {..} } public class ClosedContest extends BusinessObject<ContestEntity, Long> { }
  203. 203. Obiekty biznesowe ● Tylko metody związane z operacjami na modelu ● Podobiekty (realizujące zakres funkcjonalności)
  204. 204. Obiekty biznesowe ● Tylko metody związane z operacjami na modelu ● Podobiekty (realizujące zakres funkcjonalności) ● Testowalność
  205. 205. Q&(w miare możliwości)A

×