SlideShare une entreprise Scribd logo
1  sur  209
Télécharger pour lire hors ligne
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

Contenu connexe

Similaire à Architektura to nie bzdura

Integracja JSF + Facelets + Spring + JPA + Tomahawk
Integracja JSF + Facelets + Spring + JPA + TomahawkIntegracja JSF + Facelets + Spring + JPA + Tomahawk
Integracja JSF + Facelets + Spring + JPA + Tomahawk
Wiktor Gworek
 
Programowanie Komponentowe: #D Model komponentowy OSGi
Programowanie Komponentowe: #D Model komponentowy OSGiProgramowanie Komponentowe: #D Model komponentowy OSGi
Programowanie Komponentowe: #D Model komponentowy OSGi
Mikołaj Olszewski
 
PLNOG 5: Janusz Dziemidowicz - OpenSocial w nk.pl
PLNOG 5: Janusz Dziemidowicz - OpenSocial w nk.pl PLNOG 5: Janusz Dziemidowicz - OpenSocial w nk.pl
PLNOG 5: Janusz Dziemidowicz - OpenSocial w nk.pl
PROIDEA
 

Similaire à Architektura to nie bzdura (20)

MVP - Model View Presenter (polish)
MVP - Model View Presenter (polish)MVP - Model View Presenter (polish)
MVP - Model View Presenter (polish)
 
Integracja JSF + Facelets + Spring + JPA + Tomahawk
Integracja JSF + Facelets + Spring + JPA + TomahawkIntegracja JSF + Facelets + Spring + JPA + Tomahawk
Integracja JSF + Facelets + Spring + JPA + Tomahawk
 
User-centered design
User-centered designUser-centered design
User-centered design
 
Metaprogramowanie w JS
Metaprogramowanie w JSMetaprogramowanie w JS
Metaprogramowanie w JS
 
university day 1
university day 1university day 1
university day 1
 
tRPC - czy to koniec GraphQL?
tRPC - czy to koniec GraphQL?tRPC - czy to koniec GraphQL?
tRPC - czy to koniec GraphQL?
 
Confitura 2015 - Code Quality Keepers @ Allegro
Confitura 2015 - Code Quality Keepers @ AllegroConfitura 2015 - Code Quality Keepers @ Allegro
Confitura 2015 - Code Quality Keepers @ Allegro
 
CI oraz CD w złożonym projekcie o małym budżecie
CI oraz CD w złożonym projekcie o małym budżecieCI oraz CD w złożonym projekcie o małym budżecie
CI oraz CD w złożonym projekcie o małym budżecie
 
Programowanie Komponentowe: #D Model komponentowy OSGi
Programowanie Komponentowe: #D Model komponentowy OSGiProgramowanie Komponentowe: #D Model komponentowy OSGi
Programowanie Komponentowe: #D Model komponentowy OSGi
 
PLNOG 5: Janusz Dziemidowicz - OpenSocial w nk.pl
PLNOG 5: Janusz Dziemidowicz - OpenSocial w nk.pl PLNOG 5: Janusz Dziemidowicz - OpenSocial w nk.pl
PLNOG 5: Janusz Dziemidowicz - OpenSocial w nk.pl
 
Testy API: połączenie z bazą danych czy implementacja w pamięci
Testy API: połączenie z bazą danych czy implementacja w pamięciTesty API: połączenie z bazą danych czy implementacja w pamięci
Testy API: połączenie z bazą danych czy implementacja w pamięci
 
4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Cle...
4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Cle...4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Cle...
4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Cle...
 
Daj się wyręczyć - Joomla Day Polska 2014
Daj się wyręczyć - Joomla Day Polska 2014Daj się wyręczyć - Joomla Day Polska 2014
Daj się wyręczyć - Joomla Day Polska 2014
 
PHP meetup#4 Godek
PHP meetup#4 GodekPHP meetup#4 Godek
PHP meetup#4 Godek
 
Sentio
SentioSentio
Sentio
 
TGT#14 - @Before – Nie będę automatyzować @After – No dobra, to nie jest taki...
TGT#14 - @Before – Nie będę automatyzować @After – No dobra, to nie jest taki...TGT#14 - @Before – Nie będę automatyzować @After – No dobra, to nie jest taki...
TGT#14 - @Before – Nie będę automatyzować @After – No dobra, to nie jest taki...
 
REST API - teoria i praktyka - WordUp Warszawa
REST API - teoria i praktyka - WordUp WarszawaREST API - teoria i praktyka - WordUp Warszawa
REST API - teoria i praktyka - WordUp Warszawa
 
Angular 4 pragmatycznie
Angular 4 pragmatycznieAngular 4 pragmatycznie
Angular 4 pragmatycznie
 
TWIG - niezłe widoki dla PHP
TWIG - niezłe widoki dla PHPTWIG - niezłe widoki dla PHP
TWIG - niezłe widoki dla PHP
 
Wprowadzenie do PHPUnit
Wprowadzenie do PHPUnitWprowadzenie do PHPUnit
Wprowadzenie do PHPUnit
 

Plus de Pawel Szulc

Plus de Pawel Szulc (20)

Getting acquainted with Lens
Getting acquainted with LensGetting acquainted with Lens
Getting acquainted with Lens
 
Impossibility
ImpossibilityImpossibility
Impossibility
 
Maintainable Software Architecture in Haskell (with Polysemy)
Maintainable Software Architecture in Haskell (with Polysemy)Maintainable Software Architecture in Haskell (with Polysemy)
Maintainable Software Architecture in Haskell (with Polysemy)
 
Painless Haskell
Painless HaskellPainless Haskell
Painless Haskell
 
Trip with monads
Trip with monadsTrip with monads
Trip with monads
 
Trip with monads
Trip with monadsTrip with monads
Trip with monads
 
Illogical engineers
Illogical engineersIllogical engineers
Illogical engineers
 
RChain - Understanding Distributed Calculi
RChain - Understanding Distributed CalculiRChain - Understanding Distributed Calculi
RChain - Understanding Distributed Calculi
 
Illogical engineers
Illogical engineersIllogical engineers
Illogical engineers
 
Understanding distributed calculi in Haskell
Understanding distributed calculi in HaskellUnderstanding distributed calculi in Haskell
Understanding distributed calculi in Haskell
 
Software engineering the genesis
Software engineering  the genesisSoftware engineering  the genesis
Software engineering the genesis
 
Make your programs Free
Make your programs FreeMake your programs Free
Make your programs Free
 
Going bananas with recursion schemes for fixed point data types
Going bananas with recursion schemes for fixed point data typesGoing bananas with recursion schemes for fixed point data types
Going bananas with recursion schemes for fixed point data types
 
“Going bananas with recursion schemes for fixed point data types”
“Going bananas with recursion schemes for fixed point data types”“Going bananas with recursion schemes for fixed point data types”
“Going bananas with recursion schemes for fixed point data types”
 
Writing your own RDD for fun and profit
Writing your own RDD for fun and profitWriting your own RDD for fun and profit
Writing your own RDD for fun and profit
 
The cats toolbox a quick tour of some basic typeclasses
The cats toolbox  a quick tour of some basic typeclassesThe cats toolbox  a quick tour of some basic typeclasses
The cats toolbox a quick tour of some basic typeclasses
 
Introduction to type classes
Introduction to type classesIntroduction to type classes
Introduction to type classes
 
Functional Programming & Event Sourcing - a pair made in heaven
Functional Programming & Event Sourcing - a pair made in heavenFunctional Programming & Event Sourcing - a pair made in heaven
Functional Programming & Event Sourcing - a pair made in heaven
 
Apache spark workshop
Apache spark workshopApache spark workshop
Apache spark workshop
 
Introduction to type classes in 30 min
Introduction to type classes in 30 minIntroduction to type classes in 30 min
Introduction to type classes in 30 min
 

Architektura to nie bzdura

  • 1. Architektura to nie bzdura DDD-WRO Paweł Szulc – paul.szulc@gmail.com
  • 2. Architektura to nie bzdura DDD-WRO Paweł Szulc – paul.szulc@gmail.com https://twitter.com/paulszulc
  • 3. Architektura to nie bzdura DDD-WRO Paweł Szulc – paul.szulc@gmail.com https://twitter.com/paulszulc http://rabbitonweb.com
  • 11. Cel prezentacji Nie jest celem znalezienie złotego środka – bo taki nie istnieje ●
  • 12. Cel prezentacji Nie jest celem znalezienie złotego środka – bo taki nie istnieje ● Nakłonić Was do dyskusji ●
  • 13. Stack technologiczny - Wicket - Spring - Hibernate/JPA
  • 16. Przykłady Aplikacja zarządzająca POI ● POI – ang. Point of Interest ●
  • 17. Przykłady Grupa Aplikacja zarządzająca POI ● POI – ang. Point of Interest ● Grupa ●
  • 18. Przykłady Grupa Aplikacja zarządzająca POI ● POI – ang. Point of Interest ● Grupa ● Podgrupa ● Podgrupa
  • 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. 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
  • 22. Mainstreamowa architektura - nasz model to encje hibernetowe
  • 23. Mainstreamowa architektura - nasz model to encje hibernetowe - logika biznesowa zamknięta w warstwie serwisowej
  • 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. 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
  • 27. Mainstreamowa architektura Jak ją nazwać? "Model View Controler" ?
  • 32. Czemu nie używać, skoro działa?
  • 36. ● Encja User.java ● UserService.java (List<User> findAll()) ● UserServiceImpl.java
  • 37. ● Encja User.java ● UserService.java (List<User> findAll()) ● UserServiceImpl.java public List<User> findAll() { userDao.findAll(); }
  • 38. ● Encja User.java ● UserService.java (List<User> findAll()) ● UserServiceImpl.java public List<User> findAll() { userDao.findAll(); } ● UserDao.java
  • 39. ● Encja User.java ● UserService.java (List<User> findAll()) ● UserServiceImpl.java public List<User> findAll() { userDao.findAll(); } ● UserDao.java ● UserDaoImpl.java
  • 40. Encja -> DAO -> Serwis ● Single responsibility principle
  • 41. Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki
  • 42. Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas
  • 43. Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas ● DAO – data access object?
  • 44. Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas DAO – data access object? user.getContest().getOwner() ●
  • 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. Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas ● DAO – data access object?
  • 47. Encja -> DAO -> Serwis ● Single responsibility principle ● 8 tysięczniki ● Eksplozja klas ● DAO – data access object? ● Metody biznesowe?
  • 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. Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI.
  • 50.
  • 53. PoiEntity poi = poiService.find(poiId); createForm(poi); ... new Button("save") { public void onSubmit() { poiService.update(poi); } }
  • 54. PoiEntity poi = poiService.find(poiId); createForm(poi); ... new Button("save") { public void onSubmit() { mailSender.send(body()) poiService.update(poi); } }
  • 55. 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
  • 56. Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI.
  • 57. Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę zmieniać tylko i wyłącznie wartość położenia danego POI.
  • 58.
  • 59. Encja na widoku, i co z tego? ● Ważne pytanie dla encji...
  • 60.
  • 61. Encja na widoku, i co z tego? ● Ważne pytanie dla encji – czy już zna Cię PersistenceContext?
  • 62. 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
  • 63. 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
  • 64. 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
  • 69. 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
  • 70. 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
  • 71. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
  • 72. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
  • 73. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
  • 74. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois(); LazyInitializationException
  • 75.
  • 76. STOP – This is Hibernate Police!
  • 77. STOP – This is Hibernate Police! A obywatel o Open Session In View nie słyszał?
  • 78. Open Session In View Transaction.begin
  • 79. Open Session In View Transaction.begin
  • 80. Open Session In View Transaction.begin
  • 81. Open Session In View Transaction.begin
  • 82. Open Session In View Transaction.begin
  • 83. Open Session In View Transaction.commit
  • 84. Open Session In View REQUEST Transaction.begin Transaction.commit Transaction.begin Transaction.commit Transaction.begin Transaction.commit RESPONSE
  • 85. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
  • 86. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois();
  • 87. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois(); select * from t_pois where id = :poiId;
  • 88. PoiEntity poi = poiService.find(poiId); poi.getConnectedPois(); select * from t_pois where id = :poiId; select * from t_pois where ....
  • 90. List<PoiEntity> pois = poiService.findForUser(user); for(PoiEntity p : pois) { poi.getConnectedPois(); } select * from t_pois where user_id = :uId;
  • 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 ...
  • 92. 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 ...
  • 93. 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 ...
  • 94. 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 ...
  • 95. 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 ...
  • 96. 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
  • 97. 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ść
  • 98. 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ć"
  • 100. Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa serwisowa Warstwa bazodanowa
  • 101. Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa aplikacji Warstwa serwisowa Warstwa bazodanowa
  • 102. Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa aplikacji Warstwa serwisowa Warstwa bazodanowa
  • 103. Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa aplikacji Warstwa serwisowa Warstwa bazodanowa public interface UCListingPoisForGivenSubgroup { List<PoiDto> list(Long subgroupId) }
  • 104. Zamknięcie logiki biznesowej Warstwa prezentacji Warstwa aplikacji Warstwa serwisowa Warstwa bazodanowa public interface UserFromClientProvider { UserDto provide(); }
  • 105. 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(); }
  • 106. Warstwa aplikacji – organizacja
  • 107. Warstwa aplikacji – organizacja ● Jest abstrakcją aplikacji
  • 108. Warstwa aplikacji – organizacja ● Jest abstrakcją aplikacji ● Aplikacja to zbiór funkcjonalności
  • 109. Warstwa aplikacji – organizacja ● Jest abstrakcją aplikacji ● Aplikacja to zbiór funkcjonalności ● Funkcjonalności zdefiniowane (w ten czy inny sposób)
  • 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. Warstwa aplikacji – organizacja
  • 112. Warstwa aplikacji – organizacja
  • 113. Warstwa aplikacji – organizacja
  • 114. 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'
  • 115. 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
  • 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
  • 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. ● 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; }
  • 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 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; }
  • 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 interface UCListingPoiDetails { List<PoiDto> list(Long subgroupId); boolean canList(Long subgroupId); }
  • 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 interface UCListingPoiDetails { List<PoiDto> list(Long subgroupId); boolean canList(Long subgroupId); }
  • 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 interface UCListingPoiDetails { List<PoiDto> list(Long subgroupId); ActionPossible canList(Long subgroupId); } public interface ActionPossible { boolean isPossible(); String explainImpossible(); }
  • 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. ● 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. ● 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); } }
  • 126. ● 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); } }
  • 127. ● 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); } }
  • 128. ● 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); } }
  • 129. ● 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); }
  • 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. ● 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());
  • 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() { ActionPossible withArgs = uc.canUpdateWithArgs(poiId, coords); if(withArgs.isPossible()) uc.update(poiId, coords) else userSession.warn(withArgs.explainImpossible()); } } update.setVisible(uc.canUpdate().isPossible());
  • 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 withArgs = uc.canUpdateWithArgs(poiId, coords); if(withArgs.isPossible()) uc.update(poiId, coords) else userSession.warn(withArgs.explainImpossible()); } } update.setVisible(uc.canUpdate().isPossible());
  • 134. ● 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());
  • 135. ● 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());
  • 136. ● 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());
  • 137. ● 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)); }
  • 138. 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
  • 139. 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
  • 140. 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
  • 141. 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
  • 142. 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
  • 143. 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
  • 144. 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
  • 148. Rozwiązania ● CQRS ● CQRS dla ubogich :) ● Rozróżnienie na Command i Query
  • 149. 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ń
  • 150. 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
  • 151. public interface UCListingPoiDetails { List<PoiDto> list(Long subgroupId); ActionPossible canList(); }
  • 152. @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) {..}
  • 153. @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) {..} }
  • 154. @Service public class DefaultUCListingPoiDetails implements UCListingPoiDetails { @Autowired private UserAuthorization userAuthorization; public ActionPossible canList() { .. } public List<PoiDto> list(Long subgroupId) {..} }
  • 155. @Service public class DefaultUCListingPoiDetails implements UCListingPoiDetails { @Autowired private UserAuthorization userAuthorization; public ActionPossible canList() { .. } public List<PoiDto> list(Long subgroupId) { } }
  • 156. @Service public class DefaultUCListingPoiDetails implements UCListingPoiDetails { @Autowired private UserAuthorization userAuthorization; public ActionPossible canList() { .. } public List<PoiDto> list(Long subgroupId) { checkThat(canList()); } }
  • 157. @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); } }
  • 158. public interface UCUpdatingPoiCoordinates { void update(Long poiId, Coordinates c); ActionPossible canUpdate(); ActionPossible canUpdateWithArgs( Long poiId, Coordinates c); }
  • 159. @Service public class DefaultUCUpdatingPoiCoordinates implements UCUpdatingPoiCoordinates { public ActionPossible canUpdate() {..} ActionPossible canUpdateWithArgs(Long poiId, Coordinates c) {..} public void update(Long poiId, Coordinates c) {..} }
  • 160. @Service public class DefaultUCUpdatingPoiCoordinates implements UCUpdatingPoiCoordinates { public ActionPossible canUpdate() {..} ActionPossible canUpdateWithArgs(Long poiId, Coordinates c) {..} public void update(Long poiId, Coordinates c) { } }
  • 161. @Service public class DefaultUCUpdatingPoiCoordinates implements UCUpdatingPoiCoordinates { public ActionPossible canUpdate() {..} ActionPossible canUpdateWithArgs(Long poiId, Coordinates c) {..} public void update(Long poiId, Coordinates c) { checkThat(canUpdate()); } }
  • 162. @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)); } }
  • 163. @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); } }
  • 164. @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()); }
  • 165. Warstwa Application ● przejrzyste API zorientowane na przypadki użycia
  • 166. Warstwa Application ● ● przejrzyste API zorientowane na przypadki użycia testowalność
  • 167. Warstwa Application ● przejrzyste API zorientowane na przypadki użycia ● testowalność ● "głupi" widok, wiele warstw prezentacji
  • 168. Warstwa Application ● przejrzyste API zorientowane na przypadki użycia ● testowalność ● "głupi" widok, wiele warstw prezentacji ● wejście w projekt
  • 169. Warstwa Application ● przejrzyste API zorientowane na przypadki użycia ● testowalność ● "głupi" widok, wiele warstw prezentacji ● wejście w projekt ● polyglot programmer
  • 170. 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
  • 171. 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
  • 172. 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
  • 174. @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); }
  • 176. Obiekty Modelu ● Encja jest obiektem reprezentującym model
  • 177. Obiekty Modelu ● Encja jest obiektem reprezentującym model ● Gettery/settery defacto wymagane
  • 178. Obiekty Modelu ● Encja jest obiektem reprezentującym model ● Gettery/settery defacto wymagane ● Metody typu add, remove
  • 179. Obiekty Modelu ● Encja jest obiektem reprezentującym model ● Gettery/settery defacto wymagane ● Metody typu add, remove ● Metody "biznesowe" (run(), isRunning(), close())
  • 180. 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
  • 181. 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())
  • 182. Pomysł... ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym
  • 183. Pomysł... ● ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym Encje jedynie jako reprezentacje tabel
  • 184. Pomysł... ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym ● Encje jedynie jako reprezentacje tabel ● Encja anemiczna
  • 186. Pomysł... @Entity public class UserEntity { @Id private Long id; private String login; @OneToMany private Set<RoleEntity> roles; }
  • 187. 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) {..} }
  • 188. 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) {..} }
  • 189. 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) {..} }
  • 190. Pomysł - obiekt biznesowy ● Niech encja reprezentuje tylko i wyłącznie schemat relacyjny w świecie obiektowym ● Encje jedynie jako reprezentacje tabel ● Encja anemiczna
  • 191. 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
  • 192. 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ę
  • 193. 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)
  • 194. 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"
  • 195. @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() {..}
  • 196. @Configurable public class User extends BusinessObject<UserEntity, Long> { public User(UserEntity entity) { super(entity, UserEntity.class); } }
  • 197. @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()); } }
  • 198. @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); } }
  • 199. @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); } }
  • 200. @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); } }
  • 201. @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()); }
  • 202. Obiekty biznesowe ● Tylko metody związane z operacjami na modelu ● Podobiekty (realizujące zakres funkcjonalności)
  • 204. public class Contest extends BusinessObject<ContestEntity, Long> { public boolean isLaunchable() {..} public void launch() {..} public boolean isFinishable() {..} public void finish() {..} ... }
  • 205. 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() {..} }
  • 206. 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> { }
  • 207. Obiekty biznesowe ● Tylko metody związane z operacjami na modelu ● Podobiekty (realizujące zakres funkcjonalności)
  • 208. Obiekty biznesowe ● Tylko metody związane z operacjami na modelu ● Podobiekty (realizujące zakres funkcjonalności) ● Testowalność