• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Architektura to nie bzdura
 

Architektura to nie bzdura

on

  • 313 views

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

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

Statistics

Views

Total Views
313
Views on SlideShare
310
Embed Views
3

Actions

Likes
0
Downloads
0
Comments
0

1 Embed 3

http://www.linkedin.com 3

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Architektura to nie bzdura Architektura to nie bzdura Presentation Transcript

    • Architektura to nie bzdura DDD-WRO Paweł Szulc – paul.szulc@gmail.com
    • Architektura to nie bzdura DDD-WRO Paweł Szulc – paul.szulc@gmail.com https://twitter.com/paulszulc
    • Architektura to nie bzdura DDD-WRO Paweł Szulc – paul.szulc@gmail.com https://twitter.com/paulszulc http://rabbitonweb.com
    • Architektura to nie bzdura
    • Architektura to nie bzdura
    • Efekt WOW
    • Efekt WOW
    • Efekt WOW
    • Efekt WOW
    • Cel prezentacji
    • Cel prezentacji Nie jest celem znalezienie złotego środka – bo taki nie istnieje ●
    • Cel prezentacji Nie jest celem znalezienie złotego środka – bo taki nie istnieje ● Nakłonić Was do dyskusji ●
    • Stack technologiczny - Wicket - Spring - Hibernate/JPA
    • Przykłady
    • Przykłady ● Aplikacja zarządzająca POI
    • Przykłady Aplikacja zarządzająca POI ● POI – ang. Point of Interest ●
    • Przykłady Grupa Aplikacja zarządzająca POI ● POI – ang. Point of Interest ● Grupa ●
    • Przykłady Grupa Aplikacja zarządzająca POI ● POI – ang. Point of Interest ● Grupa ● Podgrupa ● Podgrupa
    • Przykłady Aplikacja zarządzająca POI ● POI – ang. Point of Interest ● Grupa ● Podgrupa ● POI: nazwa, położenie (x,y) ● Grupa Podgrupa POI
    • 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
    • Mainstreamowa architektura
    • Mainstreamowa architektura - nasz model to encje hibernetowe
    • Mainstreamowa architektura - nasz model to encje hibernetowe - logika biznesowa zamknięta w warstwie serwisowej
    • Mainstreamowa architektura - nasz model to encje hibernetowe - logika biznesowa zamknięta w warstwie serwisowej - kod zapytań do bazy danych przez obiekty typu DAO
    • 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
    • Mainstreamowa architektura Jak ją nazwać?
    • Mainstreamowa architektura Jak ją nazwać? "Model View Controler" ?
    • Mainstreamowa architektura "Architektura trójwarstwowa" ?
    • Mainstreamowa architektura "Entity-DAO-Service-View" ?
    • Mainstreamowa architektura "Encje na twarz i pchasz"
    • Mainstreamowa architektura "Encje na twarz i pchasz"
    • Czemu nie używać, skoro działa?
    • ● Encja User.java
    • ● Encja User.java ● UserService.java
    • ● Encja User.java ● UserService.java (List<User> findAll())
    • ● Encja User.java ● UserService.java (List<User> findAll()) ● UserServiceImpl.java
    • ● Encja User.java ● UserService.java (List<User> findAll()) ● UserServiceImpl.java public List<User> findAll() { userDao.findAll(); }
    • ● Encja User.java ● UserService.java (List<User> findAll()) ● UserServiceImpl.java public List<User> findAll() { userDao.findAll(); } ● UserDao.java
    • ● Encja User.java ● UserService.java (List<User> findAll()) ● UserServiceImpl.java public List<User> findAll() { userDao.findAll(); } ● UserDao.java ● UserDaoImpl.java
    • Encja -> DAO -> Serwis ● Single responsibility principle
    • Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki
    • Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas
    • Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas ● DAO – data access object?
    • Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas DAO – data access object? user.getContest().getOwner() ●
    • 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); .... }
    • Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas ● DAO – data access object?
    • Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas ● DAO – data access object? ● Metody biznesowe?
    • 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); }
    • Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI.
    • PoiEntity poi = poiService.find(poiId);
    • PoiEntity poi = poiService.find(poiId); createForm(poi);
    • PoiEntity poi = poiService.find(poiId); createForm(poi); ... new Button("save") { public void onSubmit() { poiService.update(poi); } }
    • PoiEntity poi = poiService.find(poiId); createForm(poi); ... new Button("save") { public void onSubmit() { mailSender.send(body()) poiService.update(poi); } }
    • 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
    • Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI.
    • Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI.
    • Encja na widoku, i co z tego? ● Ważne pytanie dla encji...
    • Encja na widoku, i co z tego? ● Ważne pytanie dla encji – czy już zna Cię PersistenceContext?
    • 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
    • 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
    • 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
    • Dashboard A
    • Dashboard A B C D E
    • Dashboard A A A A B C D A E
    • Dashboard A A A A B C A D A1 A2 B1 E B2 B3 C1 C2 C3 C4 E1
    • 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
    • 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
    • PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
    • PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
    • PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
    • PoiEntity poi = poiService.find(poiId); poi.getConnectedPois(); LazyInitializationException
    • STOP – This is Hibernate Police!
    • STOP – This is Hibernate Police! A obywatel o Open Session In View nie słyszał?
    • Open Session In View Transaction.begin
    • Open Session In View Transaction.begin
    • Open Session In View Transaction.begin
    • Open Session In View Transaction.begin
    • Open Session In View Transaction.begin
    • Open Session In View Transaction.commit
    • Open Session In View REQUEST Transaction.begin Transaction.commit Transaction.begin Transaction.commit Transaction.begin Transaction.commit RESPONSE
    • PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
    • PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
    • PoiEntity poi = poiService.find(poiId); poi.getConnectedPois(); select * from t_pois where id = :poiId;
    • PoiEntity poi = poiService.find(poiId); poi.getConnectedPois(); select * from t_pois where id = :poiId; select * from t_pois where ....
    • List<PoiEntity> pois = poiService.findForUser(user); for(PoiEntity p : pois) { poi.getConnectedPois(); }
    • List<PoiEntity> pois = poiService.findForUser(user); for(PoiEntity p : pois) { poi.getConnectedPois(); } select * from t_pois where user_id = :uId;
    • 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 ...
    • 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 ...
    • 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 ...
    • 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 ...
    • 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 ...
    • 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
    • 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ść
    • 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ć"
    • Zamknięcie logiki biznesowej
    • Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa serwisowa Warstwa bazodanowa
    • Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa aplikacji Warstwa serwisowa Warstwa bazodanowa
    • Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa aplikacji Warstwa serwisowa Warstwa bazodanowa
    • Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa aplikacji Warstwa serwisowa Warstwa bazodanowa public interface UCListingPoisForGivenSubgroup { List<PoiDto> list(Long subgroupId) }
    • Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa aplikacji Warstwa serwisowa Warstwa bazodanowa public interface UserFromClientProvider { UserDto provide(); }
    • 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(); }
    • Warstwa aplikacji – organizacja
    • Warstwa aplikacji – organizacja ● Jest abstrakcją aplikacji
    • Warstwa aplikacji – organizacja ● Jest abstrakcją aplikacji ● Aplikacja to zbiór funkcjonalności
    • Warstwa aplikacji – organizacja ● Jest abstrakcją aplikacji ● Aplikacja to zbiór funkcjonalności ● Funkcjonalności zdefiniowane (w ten czy inny sposób)
    • 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'
    • Warstwa aplikacji – organizacja
    • Warstwa aplikacji – organizacja
    • Warstwa aplikacji – organizacja
    • 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'
    • 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
    • ● 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
    • ● 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); }
    • ● 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; }
    • ● 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; }
    • ● 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); }
    • ● 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); }
    • ● 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(); }
    • ● 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); } }
    • ● 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); } }
    • ● 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); } }
    • ● 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); } }
    • ● 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); } }
    • ● 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); } }
    • ● 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); }
    • ● 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());
    • ● 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());
    • ● 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());
    • ● 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());
    • ● 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());
    • ● 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());
    • ● 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());
    • ● 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)); }
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • Rozwiązania ● CQRS
    • Rozwiązania ● CQRS
    • Rozwiązania ● CQRS ● CQRS dla ubogich :)
    • Rozwiązania ● CQRS ● CQRS dla ubogich :) ● Rozróżnienie na Command i Query
    • 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ń
    • 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
    • public interface UCListingPoiDetails { List<PoiDto> list(Long subgroupId); ActionPossible canList(); }
    • @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) {..}
    • @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) {..} }
    • @Service public class DefaultUCListingPoiDetails implements UCListingPoiDetails { @Autowired private UserAuthorization userAuthorization; public ActionPossible canList() { .. } public List<PoiDto> list(Long subgroupId) {..} }
    • @Service public class DefaultUCListingPoiDetails implements UCListingPoiDetails { @Autowired private UserAuthorization userAuthorization; public ActionPossible canList() { .. } public List<PoiDto> list(Long subgroupId) { } }
    • @Service public class DefaultUCListingPoiDetails implements UCListingPoiDetails { @Autowired private UserAuthorization userAuthorization; public ActionPossible canList() { .. } public List<PoiDto> list(Long subgroupId) { checkThat(canList()); } }
    • @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); } }
    • public interface UCUpdatingPoiCoordinates { void update(Long poiId, Coordinates c); ActionPossible canUpdate(); ActionPossible canUpdateWithArgs( Long poiId, Coordinates c); }
    • @Service public class DefaultUCUpdatingPoiCoordinates implements UCUpdatingPoiCoordinates { public ActionPossible canUpdate() {..} ActionPossible canUpdateWithArgs(Long poiId, Coordinates c) {..} public void update(Long poiId, Coordinates c) {..} }
    • @Service public class DefaultUCUpdatingPoiCoordinates implements UCUpdatingPoiCoordinates { public ActionPossible canUpdate() {..} ActionPossible canUpdateWithArgs(Long poiId, Coordinates c) {..} public void update(Long poiId, Coordinates c) { } }
    • @Service public class DefaultUCUpdatingPoiCoordinates implements UCUpdatingPoiCoordinates { public ActionPossible canUpdate() {..} ActionPossible canUpdateWithArgs(Long poiId, Coordinates c) {..} public void update(Long poiId, Coordinates c) { checkThat(canUpdate()); } }
    • @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)); } }
    • @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); } }
    • @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()); }
    • Warstwa Application ● przejrzyste API zorientowane na przypadki użycia
    • Warstwa Application ● ● przejrzyste API zorientowane na przypadki użycia testowalność
    • Warstwa Application ● przejrzyste API zorientowane na przypadki użycia ● testowalność ● "głupi" widok, wiele warstw prezentacji
    • Warstwa Application ● przejrzyste API zorientowane na przypadki użycia ● testowalność ● "głupi" widok, wiele warstw prezentacji ● wejście w projekt
    • Warstwa Application ● przejrzyste API zorientowane na przypadki użycia ● testowalność ● "głupi" widok, wiele warstw prezentacji ● wejście w projekt ● polyglot programmer
    • 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
    • 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
    • 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
    • @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Audit { public String value() default ""; }
    • @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); }
    • Obiekty Modelu
    • Obiekty Modelu ● Encja jest obiektem reprezentującym model
    • Obiekty Modelu ● Encja jest obiektem reprezentującym model ● Gettery/settery defacto wymagane
    • Obiekty Modelu ● Encja jest obiektem reprezentującym model ● Gettery/settery defacto wymagane ● Metody typu add, remove
    • Obiekty Modelu ● Encja jest obiektem reprezentującym model ● Gettery/settery defacto wymagane ● Metody typu add, remove ● Metody "biznesowe" (run(), isRunning(), close())
    • 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
    • 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())
    • Pomysł... ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym
    • Pomysł... ● ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym Encje jedynie jako reprezentacje tabel
    • Pomysł... ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym ● Encje jedynie jako reprezentacje tabel ● Encja anemiczna
    • Pomysł... @Entity public class UserEntity { }
    • Pomysł... @Entity public class UserEntity { @Id private Long id; private String login; @OneToMany private Set<RoleEntity> roles; }
    • 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) {..} }
    • 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) {..} }
    • 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) {..} }
    • Pomysł - obiekt biznesowy ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym ● Encje jedynie jako reprezentacje tabel ● Encja anemiczna
    • 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
    • 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ę
    • 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)
    • 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"
    • @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() {..}
    • @Configurable public class User extends BusinessObject<UserEntity, Long> { public User(UserEntity entity) { super(entity, UserEntity.class); } }
    • @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()); } }
    • @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); } }
    • @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); } }
    • @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); } }
    • @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()); }
    • Obiekty biznesowe ● Tylko metody związane z operacjami na modelu ● Podobiekty (realizujące zakres funkcjonalności)
    • finish launch new running closed
    • public class Contest extends BusinessObject<ContestEntity, Long> { public boolean isLaunchable() {..} public void launch() {..} public boolean isFinishable() {..} public void finish() {..} ... }
    • 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() {..} }
    • 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> { }
    • Obiekty biznesowe ● Tylko metody związane z operacjami na modelu ● Podobiekty (realizujące zakres funkcjonalności)
    • Obiekty biznesowe ● Tylko metody związane z operacjami na modelu ● Podobiekty (realizujące zakres funkcjonalności) ● Testowalność
    • Q&(w miare możliwości)A