architektura to nie bzdura

209
Architektura to nie bzdura DDD-WRO Paweł Szulc – [email protected]

Upload: pawel-szulc

Post on 04-Jul-2015

445 views

Category:

Technology


0 download

DESCRIPTION

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

TRANSCRIPT

Page 1: Architektura to nie bzdura

Architektura to nie bzdura

DDD-WRO

Paweł Szulc – [email protected]

Page 2: Architektura to nie bzdura

Architektura to nie bzdura

DDD-WRO

Paweł Szulc – [email protected]

https://twitter.com/paulszulc

Page 3: Architektura to nie bzdura

Architektura to nie bzdura

DDD-WRO

Paweł Szulc – [email protected]

https://twitter.com/paulszulc

http://rabbitonweb.com

Page 4: Architektura to nie bzdura

Architektura to nie bzdura

Page 5: Architektura to nie bzdura

Architektura to nie bzdura

Page 6: Architektura to nie bzdura

Efekt WOW

Page 7: Architektura to nie bzdura

Efekt WOW

Page 8: Architektura to nie bzdura

Efekt WOW

Page 9: Architektura to nie bzdura

Efekt WOW

Page 10: Architektura to nie bzdura

Cel prezentacji

Page 11: Architektura to nie bzdura

● Nie jest celem znalezienie złotego środka – bo taki nie istnieje

Cel prezentacji

Page 12: Architektura to nie bzdura

● Nie jest celem znalezienie złotego środka – bo taki nie istnieje● Nakłonić Was do dyskusji

Cel prezentacji

Page 13: Architektura to nie bzdura

- Wicket - Spring

- Hibernate/JPA

Stack technologiczny

Page 14: Architektura to nie bzdura

Przykłady

Page 15: Architektura to nie bzdura

● Aplikacja zarządzająca POI

Przykłady

Page 16: Architektura to nie bzdura

● Aplikacja zarządzająca POI● POI – ang. Point of Interest

Przykłady

Page 17: Architektura to nie bzdura

● Aplikacja zarządzająca POI● POI – ang. Point of Interest ● Grupa

Przykłady

Grupa

Page 18: Architektura to nie bzdura

● Aplikacja zarządzająca POI● POI – ang. Point of Interest ● Grupa ● Podgrupa

Przykłady

Grupa

Podgrupa

Page 19: Architektura to nie bzdura

● Aplikacja zarządzająca POI● POI – ang. Point of Interest ● Grupa ● Podgrupa● POI: nazwa, położenie (x,y)

Przykłady

Grupa

Podgrupa

POI

Page 20: Architektura to nie bzdura

● 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

Przykłady

Grupa

Podgrupa

POI

Page 21: Architektura to nie bzdura

Mainstreamowa architektura

Page 22: Architektura to nie bzdura

- nasz model to encje hibernetowe

Mainstreamowa architektura

Page 23: Architektura to nie bzdura

- nasz model to encje hibernetowe- logika biznesowa zamknięta w warstwie

serwisowej

Mainstreamowa architektura

Page 24: Architektura to nie bzdura

- nasz model to encje hibernetowe- logika biznesowa zamknięta w warstwie

serwisowej- kod zapytań do bazy danych przez obiekty typu

DAO

Mainstreamowa architektura

Page 25: Architektura to nie bzdura

- 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

Page 26: Architektura to nie bzdura

Jak ją nazwać?

Mainstreamowa architektura

Page 27: Architektura to nie bzdura

Jak ją nazwać?

"Model View Controler" ?

Mainstreamowa architektura

Page 28: Architektura to nie bzdura

"Architektura trójwarstwowa" ?

Mainstreamowa architektura

Page 29: Architektura to nie bzdura

"Entity-DAO-Service-View" ?

Mainstreamowa architektura

Page 30: Architektura to nie bzdura

"Encje na twarz i pchasz"

Mainstreamowa architektura

Page 31: Architektura to nie bzdura

"Encje na twarz i pchasz"

Mainstreamowa architektura

Page 32: Architektura to nie bzdura

Czemu nie używać, skoro działa?

Page 33: Architektura to nie bzdura

● Encja User.java

Page 34: Architektura to nie bzdura

● Encja User.java● UserService.java

Page 35: Architektura to nie bzdura

● Encja User.java● UserService.java (List<User> findAll())

Page 36: Architektura to nie bzdura

● Encja User.java● UserService.java (List<User> findAll())● UserServiceImpl.java

Page 37: Architektura to nie bzdura

● Encja User.java● UserService.java (List<User> findAll())● UserServiceImpl.javapublic List<User> findAll() { userDao.findAll(); }

Page 38: Architektura to nie bzdura

● Encja User.java● UserService.java (List<User> findAll())● UserServiceImpl.javapublic List<User> findAll() { userDao.findAll(); }

● UserDao.java

Page 39: Architektura to nie bzdura

● Encja User.java● UserService.java (List<User> findAll())● UserServiceImpl.javapublic List<User> findAll() { userDao.findAll(); }

● UserDao.java● UserDaoImpl.java

Page 40: Architektura to nie bzdura

Encja -> DAO -> Serwis

● Single responsibility principle

Page 41: Architektura to nie bzdura

Encja -> DAO -> Serwis

● Single responsibility principle● 8 tysięczniki

Page 42: Architektura to nie bzdura

Encja -> DAO -> Serwis

● Single responsibility principle● 8 tysięczniki● Eksplozja klas

Page 43: Architektura to nie bzdura

Encja -> DAO -> Serwis

● Single responsibility principle● 8 tysięczniki● Eksplozja klas● DAO – data access object?

Page 44: Architektura to nie bzdura

Encja -> DAO -> Serwis

● Single responsibility principle● 8 tysięczniki● Eksplozja klas● DAO – data access object?

user.getContest().getOwner()

Page 45: Architektura to nie bzdura

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);

....

}

Page 46: Architektura to nie bzdura

Encja -> DAO -> Serwis

● Single responsibility principle● 8 tysięczniki● Eksplozja klas● DAO – data access object?

Page 47: Architektura to nie bzdura

Encja -> DAO -> Serwis

● Single responsibility principle● 8 tysięczniki● Eksplozja klas● DAO – data access object?● Metody biznesowe?

Page 48: Architektura to nie bzdura

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);

}

Page 49: Architektura to nie bzdura

Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i

wyłącznie wartość położenia danego POI.

Page 50: Architektura to nie bzdura
Page 51: Architektura to nie bzdura

PoiEntity poi = poiService.find(poiId);

Page 52: Architektura to nie bzdura

PoiEntity poi = poiService.find(poiId);

createForm(poi);

Page 53: Architektura to nie bzdura

PoiEntity poi = poiService.find(poiId);

createForm(poi);

...

new Button("save") {

public void onSubmit() { poiService.update(poi);

}

}

Page 54: Architektura to nie bzdura

PoiEntity poi = poiService.find(poiId);

createForm(poi);

...

new Button("save") {

public void onSubmit() { mailSender.send(body());

poiService.update(poi);

}

}

Page 55: Architektura to nie bzdura

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

Page 56: Architektura to nie bzdura

Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i

wyłącznie wartość położenia danego POI.

Page 57: Architektura to nie bzdura

Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i

wyłącznie wartość położenia danego POI.

Page 58: Architektura to nie bzdura
Page 59: Architektura to nie bzdura

Encja na widoku, i co z tego?

● Ważne pytanie dla encji...

Page 60: Architektura to nie bzdura
Page 61: Architektura to nie bzdura

Encja na widoku, i co z tego?

● Ważne pytanie dla encji – czy już zna Cię PersistenceContext?

Page 62: Architektura to nie bzdura

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

Page 63: Architektura to nie bzdura

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

Page 64: Architektura to nie bzdura

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

Page 65: Architektura to nie bzdura

Dashboard

A

Page 66: Architektura to nie bzdura

Dashboard

A

B C

D E

Page 67: Architektura to nie bzdura

Dashboard

A

B C

D E

A

A

A

A

Page 68: Architektura to nie bzdura

Dashboard

A

B C

D E

A1 A2 B1 B2 B3 C1 C2 C3 C4 E1

A

A

A

A

Page 69: Architektura to nie bzdura

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

Page 70: Architektura to nie bzdura

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

Page 71: Architektura to nie bzdura

PoiEntity poi = poiService.find(poiId);

poi.getConnectedPois();

Page 72: Architektura to nie bzdura

PoiEntity poi = poiService.find(poiId);

poi.getConnectedPois();

Page 73: Architektura to nie bzdura

PoiEntity poi = poiService.find(poiId);

poi.getConnectedPois();

Page 74: Architektura to nie bzdura

PoiEntity poi = poiService.find(poiId);

poi.getConnectedPois();

LazyInitializationException

Page 75: Architektura to nie bzdura
Page 76: Architektura to nie bzdura

STOP – This is Hibernate Police!

Page 77: Architektura to nie bzdura

STOP – This is Hibernate Police!

A obywatel o Open Session In Viewnie słyszał?

Page 78: Architektura to nie bzdura

Open Session In View

Transaction.begin

Page 79: Architektura to nie bzdura

Open Session In View

Transaction.begin

Page 80: Architektura to nie bzdura

Open Session In View

Transaction.begin

Page 81: Architektura to nie bzdura

Open Session In View

Transaction.begin

Page 82: Architektura to nie bzdura

Open Session In View

Transaction.begin

Page 83: Architektura to nie bzdura

Open Session In View

Transaction.commit

Page 84: Architektura to nie bzdura

Open Session In View

Transaction.beginTransaction.commitTransaction.beginTransaction.commitTransaction.beginTransaction.commit

REQUEST

RESPONSE

Page 85: Architektura to nie bzdura

PoiEntity poi = poiService.find(poiId);

poi.getConnectedPois();

Page 86: Architektura to nie bzdura

PoiEntity poi = poiService.find(poiId);

poi.getConnectedPois();

Page 87: Architektura to nie bzdura

PoiEntity poi = poiService.find(poiId);

poi.getConnectedPois();

select * from t_pois where id = :poiId;

Page 88: Architektura to nie bzdura

PoiEntity poi = poiService.find(poiId);

poi.getConnectedPois();

select * from t_pois where id = :poiId;

select * from t_pois where ....

Page 89: Architektura to nie bzdura

List<PoiEntity> pois = poiService.findForUser(user);

for(PoiEntity p : pois) {

poi.getConnectedPois();

}

Page 90: Architektura to nie bzdura

List<PoiEntity> pois = poiService.findForUser(user);

for(PoiEntity p : pois) {

poi.getConnectedPois();

}

select * from t_pois where user_id = :uId;

Page 91: Architektura to nie bzdura

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 ...

Page 92: Architektura to nie bzdura

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 ...

Page 93: Architektura to nie bzdura

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 ...

Page 94: Architektura to nie bzdura

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 ...

Page 95: Architektura to nie bzdura

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 ...

Page 96: Architektura to nie bzdura

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

Page 97: Architektura to nie bzdura

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ść

Page 98: Architektura to nie bzdura

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ć"

Page 99: Architektura to nie bzdura

Zamknięcie logiki biznesowej

Page 100: Architektura to nie bzdura

Zamknięcie logiki biznesowej

Warstwa prezentacji

Warstwa serwisowa

Warstwa bazodanowa

Page 101: Architektura to nie bzdura

Zamknięcie logiki biznesowej

Warstwa prezentacji

Warstwa aplikacji

Warstwa serwisowa

Warstwa bazodanowa

Page 102: Architektura to nie bzdura

Zamknięcie logiki biznesowej

Warstwa prezentacji

Warstwa aplikacji

Warstwa serwisowa

Warstwa bazodanowa

Page 103: Architektura to nie bzdura

Zamknięcie logiki biznesowej

Warstwa prezentacji

Warstwa aplikacji

Warstwa serwisowa

Warstwa bazodanowa

public interface UCListingPoisForGivenSubgroup { List<PoiDto> list(Long subgroupId)}

Page 104: Architektura to nie bzdura

Zamknięcie logiki biznesowej

Warstwa prezentacji

Warstwa aplikacji

Warstwa serwisowa

Warstwa bazodanowa

public interface UserFromClientProvider { UserDto provide(); }

Page 105: Architektura to nie bzdura

Zamknięcie logiki biznesowej

Warstwa prezentacji

Warstwa aplikacji

Warstwa serwisowa

Warstwa bazodanowa

public interface UserFromClientProvider { UserDto provide(); }

public class UserProvider implements UserFromClientProvider { public UserDto provide() { return userSession.getUser(); }}

Page 106: Architektura to nie bzdura

Warstwa aplikacji – organizacja

Page 107: Architektura to nie bzdura

Warstwa aplikacji – organizacja

● Jest abstrakcją aplikacji

Page 108: Architektura to nie bzdura

Warstwa aplikacji – organizacja

● Jest abstrakcją aplikacji● Aplikacja to zbiór funkcjonalności

Page 109: Architektura to nie bzdura

Warstwa aplikacji – organizacja

● Jest abstrakcją aplikacji● Aplikacja to zbiór funkcjonalności● Funkcjonalności zdefiniowane (w ten czy inny

sposób)

Page 110: Architektura to nie bzdura

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'

Page 111: Architektura to nie bzdura

Warstwa aplikacji – organizacja

Page 112: Architektura to nie bzdura

Warstwa aplikacji – organizacja

Page 113: Architektura to nie bzdura

Warstwa aplikacji – organizacja

Page 114: Architektura to nie bzdura

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'

Page 115: Architektura to nie bzdura

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

Page 116: Architektura to nie bzdura

● 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

Page 117: Architektura to nie bzdura

● 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);

}

Page 118: Architektura to nie bzdura

● 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;

}

Page 119: Architektura to nie bzdura

● 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;

}

Page 120: Architektura to nie bzdura

● 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);

}

Page 121: Architektura to nie bzdura

● 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);

}

Page 122: Architektura to nie bzdura

● 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();

}

Page 123: Architektura to nie bzdura

● 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);

}

}

Page 124: Architektura to nie bzdura

● 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);

}

}

Page 125: Architektura to nie bzdura

● 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);

}

}

Page 126: Architektura to nie bzdura

● 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);

}

}

Page 127: Architektura to nie bzdura

● 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);

}

}

Page 128: Architektura to nie bzdura

● 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);

}

}

Page 129: Architektura to nie bzdura

● 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);

}

Page 130: Architektura to nie bzdura

● 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());

Page 131: Architektura to nie bzdura

● 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());

Page 132: Architektura to nie bzdura

● 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());

Page 133: Architektura to nie bzdura

● 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());

Page 134: Architektura to nie bzdura

● 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());

Page 135: Architektura to nie bzdura

● 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());

Page 136: Architektura to nie bzdura

● 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());

Page 137: Architektura to nie bzdura

● 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));

}

Page 138: Architektura to nie bzdura

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

Page 139: Architektura to nie bzdura

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

@Entity public class Contest {

@Id private Long id;

private String name;

private LocalDate creationDate;

@Enumerated private State state;

Page 140: Architektura to nie bzdura

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

@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;

}

Page 141: Architektura to nie bzdura

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

@Entity public class Contest {

...

public void start() { .. }

public void close() { .. }

public boolean isAnnual() { .. }

}

Page 142: Architektura to nie bzdura

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

@Entity public class Contest {

...

public void start() { .. }

public void close() { .. }

public boolean isAnnual() { .. }

}

Page 143: Architektura to nie bzdura

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

@Entity public class Contest {

...

public void start() { .. }

public void close() { .. }

public boolean isAnnual() { .. }

}

Chce taki panel

okej..

Page 144: Architektura to nie bzdura

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

@Entity public class Contest {

...

public void start() { .. }

public void close() { .. }

public boolean isAnnual() { .. }

public String getName() {..}

public LocalDate getCreationDate() {..}

public State getState() {..}

}

Page 145: Architektura to nie bzdura

Rozwiązania

● CQRS

Page 146: Architektura to nie bzdura

Rozwiązania

● CQRS

Page 147: Architektura to nie bzdura

Rozwiązania

● CQRS● CQRS dla ubogich :)

Page 148: Architektura to nie bzdura

Rozwiązania

● CQRS● CQRS dla ubogich :)

● Rozróżnienie na Command i Query

Page 149: Architektura to nie bzdura

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ń

Page 150: Architektura to nie bzdura

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

Page 151: Architektura to nie bzdura

public interface UCListingPoiDetails {

List<PoiDto> list(Long subgroupId);

ActionPossible canList();

}

Page 152: Architektura to nie bzdura

@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) {..}

}

Page 153: Architektura to nie bzdura

@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) {..}

}

Page 154: Architektura to nie bzdura

@Service

public class DefaultUCListingPoiDetails

implements UCListingPoiDetails {

@Autowired

private UserAuthorization userAuthorization;

public ActionPossible canList() { .. }

public List<PoiDto> list(Long subgroupId) {..}

}

Page 155: Architektura to nie bzdura

@Service

public class DefaultUCListingPoiDetails

implements UCListingPoiDetails {

@Autowired

private UserAuthorization userAuthorization;

public ActionPossible canList() { .. }

public List<PoiDto> list(Long subgroupId) {

}

}

Page 156: Architektura to nie bzdura

@Service

public class DefaultUCListingPoiDetails

implements UCListingPoiDetails {

@Autowired

private UserAuthorization userAuthorization;

public ActionPossible canList() { .. }

public List<PoiDto> list(Long subgroupId) {

checkThat(canList());

}

}

Page 157: Architektura to nie bzdura

@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);

}

}

Page 158: Architektura to nie bzdura

public interface UCUpdatingPoiCoordinates {

void update(Long poiId, Coordinates c);

ActionPossible canUpdate();

ActionPossible canUpdateWithArgs(

Long poiId,

Coordinates c);

}

Page 159: Architektura to nie bzdura

@Service

public class DefaultUCUpdatingPoiCoordinates

implements UCUpdatingPoiCoordinates {

public ActionPossible canUpdate() {..}

ActionPossible canUpdateWithArgs(Long poiId,

Coordinates c) {..}

public void update(Long poiId, Coordinates c) {..}

}

Page 160: Architektura to nie bzdura

@Service

public class DefaultUCUpdatingPoiCoordinates

implements UCUpdatingPoiCoordinates {

public ActionPossible canUpdate() {..}

ActionPossible canUpdateWithArgs(Long poiId,

Coordinates c) {..}

public void update(Long poiId, Coordinates c) {

}

}

Page 161: Architektura to nie bzdura

@Service

public class DefaultUCUpdatingPoiCoordinates

implements UCUpdatingPoiCoordinates {

public ActionPossible canUpdate() {..}

ActionPossible canUpdateWithArgs(Long poiId,

Coordinates c) {..}

public void update(Long poiId, Coordinates c) {

checkThat(canUpdate());

}

}

Page 162: Architektura to nie bzdura

@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));

}

}

Page 163: Architektura to nie bzdura

@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);

}

}

Page 164: Architektura to nie bzdura

@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());

}

}

Page 165: Architektura to nie bzdura

Warstwa Application

● przejrzyste API zorientowane na przypadki użycia

Page 166: Architektura to nie bzdura

Warstwa Application

● przejrzyste API zorientowane na przypadki użycia

● testowalność

Page 167: Architektura to nie bzdura

Warstwa Application

● przejrzyste API zorientowane na przypadki użycia

● testowalność● "głupi" widok, wiele warstw prezentacji

Page 168: Architektura to nie bzdura

Warstwa Application

● przejrzyste API zorientowane na przypadki użycia

● testowalność● "głupi" widok, wiele warstw prezentacji● wejście w projekt

Page 169: Architektura to nie bzdura

Warstwa Application

● przejrzyste API zorientowane na przypadki użycia

● testowalność● "głupi" widok, wiele warstw prezentacji● wejście w projekt● polyglot programmer

Page 170: Architektura to nie bzdura

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

Page 171: Architektura to nie bzdura

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

Page 172: Architektura to nie bzdura

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

Page 173: Architektura to nie bzdura

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface Audit {

public String value() default "";

}

Page 174: Architektura to nie bzdura

@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);

}

Page 175: Architektura to nie bzdura

Obiekty Modelu

Page 176: Architektura to nie bzdura

Obiekty Modelu

● Encja jest obiektem reprezentującym model

Page 177: Architektura to nie bzdura

Obiekty Modelu

● Encja jest obiektem reprezentującym model● Gettery/settery defacto wymagane

Page 178: Architektura to nie bzdura

Obiekty Modelu

● Encja jest obiektem reprezentującym model● Gettery/settery defacto wymagane● Metody typu add, remove

Page 179: Architektura to nie bzdura

Obiekty Modelu

● Encja jest obiektem reprezentującym model● Gettery/settery defacto wymagane● Metody typu add, remove● Metody "biznesowe" (run(), isRunning(),

close())

Page 180: Architektura to nie bzdura

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

Page 181: Architektura to nie bzdura

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())

Page 182: Architektura to nie bzdura

Pomysł...

● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym

Page 183: Architektura to nie bzdura

Pomysł...

● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym

● Encje jedynie jako reprezentacje tabel

Page 184: Architektura to nie bzdura

Pomysł...

● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym

● Encje jedynie jako reprezentacje tabel ● Encja anemiczna

Page 185: Architektura to nie bzdura

@Entity

public class UserEntity {

}

Pomysł...

Page 186: Architektura to nie bzdura

@Entity

public class UserEntity {

@Id private Long id;

private String login;

@OneToMany private Set<RoleEntity> roles;

}

Pomysł...

Page 187: Architektura to nie bzdura

@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ł...

Page 188: Architektura to nie bzdura

@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ł...

Page 189: Architektura to nie bzdura

@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ł...

Page 190: Architektura to nie bzdura

Pomysł - obiekt biznesowy

● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym

● Encje jedynie jako reprezentacje tabel ● Encja anemiczna

Page 191: Architektura to nie bzdura

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

Page 192: Architektura to nie bzdura

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ę

Page 193: Architektura to nie bzdura

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)

Page 194: Architektura to nie bzdura

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"

Page 195: Architektura to nie bzdura

@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() {..}

}

Page 196: Architektura to nie bzdura

@Configurable

public class User

extends BusinessObject<UserEntity, Long> {

public User(UserEntity entity) {

super(entity, UserEntity.class);

}

}

Page 197: Architektura to nie bzdura

@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());

}

}

Page 198: Architektura to nie bzdura

@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);

}

}

Page 199: Architektura to nie bzdura

@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);

}

}

Page 200: Architektura to nie bzdura

@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);

}

}

Page 201: Architektura to nie bzdura

@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());

}

}

Page 202: Architektura to nie bzdura

Obiekty biznesowe

● Tylko metody związane z operacjami na modelu● Podobiekty (realizujące zakres funkcjonalności)

Page 203: Architektura to nie bzdura

new running closedlaunch finish

Page 204: Architektura to nie bzdura

public class Contest

extends BusinessObject<ContestEntity, Long> {

public boolean isLaunchable() {..}

public void launch() {..}

public boolean isFinishable() {..}

public void finish() {..}

...

}

Page 205: Architektura to nie bzdura

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() {..}

}

Page 206: Architektura to nie bzdura

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> {

}

Page 207: Architektura to nie bzdura

Obiekty biznesowe

● Tylko metody związane z operacjami na modelu● Podobiekty (realizujące zakres funkcjonalności)

Page 208: Architektura to nie bzdura

Obiekty biznesowe

● Tylko metody związane z operacjami na modelu● Podobiekty (realizujące zakres funkcjonalności)● Testowalność

Page 209: Architektura to nie bzdura

Q&(w miare możliwości)A