SlideShare a Scribd company logo
1 of 113
Download to read offline
#WISSENTEILEN
No-Tier Applications
Lars Röwekamp | CIO New Technologies
#WISSENTEILEN
@mobileLarson
@_openknowledge
#WISSENTEILEN
ÜBER OPEN KNOWLEDGE
Branchenneutrale Softwareentwicklung & IT-Beratung
#WISSENTEILEN
ÜBER MICH
Wer bin ich - und wenn ja, wie viele?
• CIO New Technologies
• Enterprise & Mobile
• Autor, Speaker, Coach & Mentor
• Snowboard & MTB Enthusiast
Lars Röwekamp (a.k.a. @mobileLarson)
LR
#WISSENTEILEN
„May I submit my billing info to your
merchant account via your payment
gateway?“
#WISSENTEILEN
Die gute „alte“ Schichtenarchitektur
Fachliche Injection
Fachliche Transaktionen
Fachliche Scopes
Fachliche Methoden
No-Tier Applications
#WISSENTEILEN
Die gute „alte“
Schichtenarchitektur
(Quelle: https://www.bettycrocker.com/recipes/rainbow-layer-cake/)
#WISSENTEILEN
Die Use Cases
Call Center Anwendung
• Kunde neu erfassen und speichern
• Kunde löschen mit Bestätigung
#WISSENTEILEN
„Create“
#WISSENTEILEN
Der Use Case
UC-001: „create Customer“
• Kunde neu erfassen und speichern
• Call Center Agent als Audit-Info speichern
• Begrüßungs-Mail an Neukunden versenden
#WISSENTEILEN
Der Use Case
UC-001: „create Customer“
• Kunde neu erfassen und speichern
• Call Center Agent als Audit-Info speichern
• btw: wenn CC Agent Trainee, dann Tracing
• Begrüßungs-Mail an Neukunden versenden
• btw: nur wenn Kunde eMail hinterlegt hat
#WISSENTEILEN
Der Use Case
UC-001: „create Customer“
• (JSF) View ruft UI Controller via U-EL
• UI Controller ruft CustomerService EJB/CDI
• UI Controller ruft MailService EJB/CDI
#WISSENTEILEN
„Create v2“
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject
private CustomerService customerService;
@Inject
private MailService mailService;
private Customer customer;
public Outcome createCustomer() {
customerService.createCustomer(customer);
mailService.sendMail("Welcome", "Welcome to jeeCRM", customer.getEmail());
return Outcome.SUCCESS;
}
…
}
Und was ist mit dem
Call Center Agent?
#WISSENTEILEN
Der Use Case
UC-001: „create Customer“
• (JSF) View ruft UI Controller via U-EL
• UI Controller ruft CustomerService EJB/CDI
• UI Controller ruft MailService EJB/CDI
• UI Controller ruft AuthenticationController
#WISSENTEILEN
„Create v3“
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject
private AuthenticationController authController;
...
public Outcome createCustomer() {
CallCenterAgent callCenterAgent = authController.getAuthenticatedUser();
customer.updateAuditInformation(callCenterAgent);
customerService.createCustomer(customer);
mailService.sendMail("Welcome", "Welcome to jeeCRM", customer.getEmail());
return Outcome.SUCCESS;
}
...
}
Ist der Call Center
Agent ein Trainee?
Hat der Kunde
eine eMail?
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerBean {
@Inject
private CustomerService customerService;
@Inject
private MailService mailService;
@Inject
private TrackService trackService;
@Inject
private AuthenticationController authenController;
private Customer customer;
public Outcome createCustomer() {
// get logged in call center agent for auditing
CrmUser callCenterAgent = authController.getAuthenticatedUser();
// set audit information
currentCustomer.updateAuditInformation(callCenterAgent);
// track call center activity, if trainee
if (callCenterAgent.isTrainee()) {
TrackAction trackAction = TrackAction.ADD_CUSTOMER;
List<TrackParameter> trackParameters = new ArrayList<TrackParameter>();
TrackParameter trackParameter = new TrackParameter(TrackParameterKey.CALL_CENTER_AGENT, callCenterAgent);
trackParameters.add(trackParameter);
trackService.track(trackAction, trackParameters);
}
// add customer to db via customer service
customerService.createCustomer(customer);
// send welcome mail, if customer has an email address
if (customer.getEmail() != null
&& customer.getEmail().length() > 0) {
mailService.sendMail("Welcome", "Welcome to jeeCRM“, customer.getEmail());
}
return Outcome.SUCCESS;
}
}
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject
private AuthenticationController authController;
...
public Outcome createCustomer() {
CallCenterAgent callCenterAgent = authController.getAuthenticatedUser();
customer.updateAuditInformation(callCenterAgent);
customerService.createCustomer(customer);
mailService.sendMail("Welcome", "Welcome to jeeCRM", customer.getEmail());
return Outcome.SUCCESS;
}
...
}
Wie steht‘s eigentlich
mit Transaktionen?
#WISSENTEILEN
Der Use Case
UC-001: „create Customer“
• (JSF) View ruft UI Controller via U-EL
• UI Controller ruft AuthenticationController
• UI Controller ruft CustomerFacade EJB
• Delegate EJB ruft CustomerService EJB/CDI
• Delegate EJB ruft MailService EJB/CDI
#WISSENTEILEN
„Create v4“
#WISSENTEILEN
„Create v4“
TX
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@EJB
private CustomerFacade customerFacade;
@Inject
private AuthenticationController authController;
...
public Outcome createCustomer() {
CallCenterAgent callCenterAgent = authController.getAuthenticatedUser();
customerFacade.createCustomer(customer, callCenterAgent);
return Outcome.SUCCESS;
}
...
}
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@EJB
private CustomerFacade customerFacade;
@Inject
private AuthenticationController authController;
...
public Outcome createCustomer() {
CallCenterAgent callCenterAgent = authController.getAuthenticatedUser();
customerFacade.createCustomer(customer, callCenterAgent);
return Outcome.SUCCESS;
}
...
}
#WISSENTEILEN
@Stateless
public class CustomerFacade {
@Inject
private CustomerService customerService;
@Inject
private MailService mailService;
private Customer customer;
public void createCustomer(Customer customer,
CallCenterAgentz callCenterAgent) {
customer.updateAuditInformation(callCenterAgent);
customerService.createCustomer(customer);
mailService.sendMail("Welcome", "Welcome to jeeCRM", customer.getEmail());
}
…
}
Fühlt sich „fachlich“
nicht wirklich gut an!
Alternativen?
#WISSENTEILEN
„Create v5“
TX
#WISSENTEILEN
„Delete“
#WISSENTEILEN
Der Use Case
UC-002: „delete Customer“
• (JSF) View ruft UI Controller via U-EL
• UI Controller „merkt“ sich Kunde in Session
• UI Controller navigiert zu Bestätigungsseite
• UI Controller bekommt Bestätigung
• …
#WISSENTEILEN
„Delete“
#WISSENTEILEN
@Named("deleteCustomerController")
@SessionScoped
public class DeleteCustomerController implements Serializable {
@Inject
private CustomerService customerService;
private Customer customer;
public Outcome askForDeletion(Customer aCustomer) {
customer = aCustomer;
return Outcome.SUCCESS;
}
public Outcome deleteCustomer() {
customerService.deleteCustomer(customer);
return Outcome.SUCCESS;
}
}
Wie kommt der Kunde
aus der Session raus?
#WISSENTEILEN
Tech
drives
Business
#WISSENTEILEN
#WISSENTEILEN
TX
#WISSENTEILEN
Problemkind Schichtenmodell
• UI Controller via CDI Managed Beans
• Service Facade und Services via EJB/CDI
• Persistenz via EntityManager und Entities
• Alles nur Infrastruktur!
• Wo steckt eigentlich die fachliche Domain?
#WISSENTEILEN
TX
#WISSENTEILEN
TX
#WISSENTEILEN
Refactoring
#WISSENTEILEN
Die bessere „neue“
Domänenarchitektur
(Quelle: https://www.bettycrocker.com/recipes/rainbow-surprise-inside-cake/)
#WISSENTEILEN
Fachliche Injection
#WISSENTEILEN
Fachliche Injection
CDI Producer Methods & Fields
• Factory Method Pattern für fachliche Objekte
• @Produces als Mittel zum Zweck
• @Qualifier als Mittel zur fachlichen Qualifizierung
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject
private AuthenticationController authController;
...
public Outcome createCustomer() {
CallCenterAgent callCenterAgent = authController.getAuthenticatedUser();
customer.updateAuditInformation(callCenterAgent);
customerService.createCustomer(customer);
mailService.sendMail("Welcome", "Welcome to jeeCRM", customer.getEmail());
return Outcome.SUCCESS;
}
...
}
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject
private AuthenticationController authController;
...
public Outcome createCustomer() {
CallCenterAgent callCenterAgent = authController.getAuthenticatedUser();
customer.updateAuditInformation(callCenterAgent);
customerService.createCustomer(customer);
mailService.sendMail("Welcome", "Welcome to jeeCRM", customer.getEmail());
return Outcome.SUCCESS;
}
...
}
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject ...
private CallCenterAgent callCenterAgent;
...
public Outcome createCustomer() {
customer.updateAuditInformation(callCenterAgent);
customerService.createCustomer(customer);
mailService.sendMail("Welcome", "Welcome to jeeCRM", customer.getEmail());
return Outcome.SUCCESS;
}
...
}
#WISSENTEILEN
@Named("authenticationController")
@SessionScoped
public class AuthenticationController implements Serializable {
@Inject
private UserService UserService;
private CallCenterAgent authenticatedCallCenterAgent;
@Produces ...
public CallCenterAgent getAuthenticatedCallCenterAgent() {
return authenticatedCrmUser;
}
// call center authentication
public String authenticate(...) {
...
}
}
@Inject CallCenterAgent
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject @Current
private CallCenterAgent currentCallCenterAgent;
...
public Outcome createCustomer() {
customer.updateAuditInformation(currentCallCenterAgent);
customerService.createCustomer(customer);
mailService.sendMail("Welcome", "Welcome to jeeCRM", customer.getEmail());
return Outcome.SUCCESS;
}
...
}
Der aktuell angemeldete …
#WISSENTEILEN
@Named("authenticationController")
@SessionScoped
public class AuthenticationController implements Serializable {
@Inject
private UserService UserService;
private CallCenterAgent authenticatedCallCenterAgent;
@Produces @Current @RequestScoped
public CallCenterAgent getAuthenticatedCallCenterAgent() {
return authenticatedCrmUser;
}
// call center authentication
public String authenticate(...) {
...
}
}
@Inject @Current CallCenterAgent
#WISSENTEILEN
package de.openknowledge.fullstack.jeecrm.annotation;
import …
@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
public @interface Current {
// no implementation by default
}
#WISSENTEILEN
Fachliche Injection V2
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject @Current
private CallCenterAgent currentCallCenterAgent;
...
public Outcome createCustomer() {
customer.updateAuditInformation(currentCallCenterAgent);
customerService.createCustomer(customer);
mailService.sendMail("Welcome", "Welcome to jeeCRM", customer.getEmail());
return Outcome.SUCCESS;
}
...
}
Cool, oder?
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject @Current
private CallCenterAgent currentCallCenterAgent;
...
public Outcome createCustomer() {
customer.updateAuditInformation(currentCallCenterAgent);
customerService.createCustomer(customer);
mailService.sendMail("Welcome", "Welcome to jeeCRM", customer.getEmail());
return Outcome.SUCCESS;
}
...
}
Cool, oder?
#WISSENTEILEN
@Stateless
public class CustomerService {
@Inject @Current
private CallCenterAgent currentCallCenterAgent;
...
@PersistenceContext
private EntityManager em;
// transactional by default
public void createCustomer(Customer customer) {
customer.updateAuditInformation(currentCallCenterAgent);
em.persist(customer);
}
...
}
Das ist cool!
#WISSENTEILEN
@Stateless
public class CustomerService {
@Inject @Current
private CallCenterAgent currentCallCenterAgent;
...
@PersistenceContext
private EntityManager em;
// transactional by default
public void createCustomer(Customer customer) {
customer.updateAuditInformation(currentCallCenterAgent);
em.persist(customer);
}
...
}
Das ist cool!
#WISSENTEILEN
Fachliche Transaktionen
#WISSENTEILEN
// Customer Service EJB
@Stateless
public class CustomerService {
@Inject @Current
private CallCenterAgent currentCallCenterAgent;
...
@PersistenceContext
private EntityManager em;
// transactional by default
public void createCustomer(Customer customer) {
customer.updateAuditInformation(currentCallCenterAgent);
em.persist(customer);
}
...
}
Warum EJB?
#WISSENTEILEN
// Customer Service CDI ManagedBean
@ApplicationScoped
public class CustomerService {
@Inject @Current
private CallCenterAgent currentCallCenterAgent;
...
@PersistenceContext
private EntityManager em;
// transactional by default
public void createCustomer(Customer customer) {
customer.updateAuditInformation(currentCallCenterAgent);
em.persist(customer);
}
...
} Ok, aber wo bekommen wir
jetzt die Transaktion her?
#WISSENTEILEN
// Customer Service CDI ManagedBean
@ApplicationScoped
public class CustomerService {
@Inject @Current
private CallCenterAgent currentCallCenterAgent;
...
@PersistenceContext
private EntityManager em;
@javax.transaction.Transactional // JTA 1.2 – TxType.REQUIRED by default
public void createCustomer(Customer customer) {
customer.updateAuditInformation(currentCallCenterAgent);
em.persist(customer);
}
...
}
#WISSENTEILEN
TX
#WISSENTEILEN
TX
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject
private CustomerService customerService;
...
@Transactional
public Outcome createCustomer() {
customerService.createCustomer(customer);
... // some additional „tx“ related work at use case level
return Outcome.SUCCESS;
}
...
}
#WISSENTEILEN
Fachlicher Scope
#WISSENTEILEN
Fachlicher Scope
UC-002: „delete Customer“
• Kunde-Löschen-Wizard:
• Kunde zum Löschen aus Tabelle auswählen
• Löschwunsch bestätigen*
• erfolgreiche Löschung anzeigen*
*auf Folgeseite
#WISSENTEILEN
Fachlicher Scope
Anti-Pattern „pumped up Session“
• RequestScoped ist zu kurz
• ViewScoped passt irgendwie auch nicht
• SessionScoped aus Mangel an Alternativen
#WISSENTEILEN
Fachlicher Scope
Anti-Pattern „pumped up Session“
• RequestScoped ist zu kurz
• ViewScoped passt irgendwie auch nicht
• SessionScoped aus Mangel an Alternativen
• FlowScoped (ab Java EE 7) als Lösung?
#WISSENTEILEN
@Named("deleteCustomerController")
@SessionScoped
public class DeleteCustomerController implements Serializable {
@Inject
private CustomerService customerService;
private Customer customer;
public Outcome askForDeletion(Customer aCustomer) {
customer = aCustomer;
return Outcome.SUCCESS;
}
public Outcome deleteCustomer() {
customerService.deleteCustomer(customer);
return Outcome.SUCCESS;
}
}
#WISSENTEILEN
Session
Scope
#WISSENTEILEN
@RequestScoped
class MyBeanA
@ConversationSoped
class MyWizard
@Inject Conversation conv;
// inside „start“ Methode
conv.begin();
// inside „end“ Methode
conv.end();
@RequestScoped
class MyBeanB
@Inject
@Inject
Conversation
Scope
#WISSENTEILEN
@Named("deleteCustomerController")
@ConversationScoped
public class DeleteCustomerController implements Serializable {
@Inject
private Conversation customerDeleteConversation;
...
public Outcome askForDeletion(Customer aCustomer) {
customerDeleteConversation.begin();
customerToDelete = aCustomer;
return Outcome.SUCCESS;
}
@Transactional
public Outcome deleteCustomer() {
... // call backend services
customerDeleteConversation.end();
return Outcome.SUCCESS;
}
}
#WISSENTEILEN
@Named("deleteCustomerController")
@ConversationScoped
public class DeleteCustomerController implements Serializable {
@Inject
private Conversation customerDeleteConversation;
...
public Outcome askForDeletion(Customer aCustomer) {
customerDeleteConversation.begin();
customerToDelete = aCustomer;
return Outcome.SUCCESS;
}
@Transactional
public Outcome deleteCustomer() {
... // call backend services
customerDeleteConversation.end();
return Outcome.SUCCESS;
}
}
Was ist, wenn
Conversation schon
aktiv?
Was ist, wenn
Conversation noch
aktiv?
#WISSENTEILEN
@Named("deleteCustomerController")
@ConversationScoped
public class DeleteCustomerController implements Serializable {
@Inject
private Conversation customerDeleteConversation;
...
public Outcome askForDeletion(Customer aCustomer) {
if (customerDeleteConversation.isTransient()) {
customerDeleteConversation.begin();
}
customerToDelete = aCustomer;
return Outcome.SUCCESS;
}
...
}
#WISSENTEILEN
@Named("deleteCustomerController")
@ConversationScoped
public class DeleteCustomerController implements Serializable {
@Inject
private Conversation customerDeleteConversation;
...
public Outcome cancelDeletion() {
// make sure to end a long-running transaction
if (!conversation.isTransient()) {
conversation.end();
}
return Outcome.SUCCESS;
}
}
#WISSENTEILEN
Fachlicher Scope
Conversation eXtended via DeltaSpike
• Normal Conversations
• Grouped Conversations
• Sub Conversations
#WISSENTEILEN
Fachliche Methoden
#WISSENTEILEN
Fachliche Methoden
a.k.a. „no more doAll(…)-Methods“
• Primärer Use Case: create Customer
• Sekundärer Use Case: send Welcome Mail
• Sekundärer Use Case: trace Trainee Audit Info
• Sekundärer Use Case: if tenant X …
#WISSENTEILEN
Fachliche Methoden
Idee der Domänen-Events
• Primärer Use Case löst Event aus
• Sekundäre Use Cases reagieren auf Event
#WISSENTEILEN
#WISSENTEILEN
#WISSENTEILEN
Fachliche Methoden
CDI Events zur losen Kopplung
• Event Object & Event Producer
• Observer Methoden
#WISSENTEILEN
Fachliche Methoden
CDI Events zur losen Kopplung
• schichtenneutral für POJOs
• ggf. transaktionsgebunden
• (a)synchrone Interaktion
#WISSENTEILEN
Fachliche Methoden
CDI Events? Klingt super, aber ….
• Wie sieht ein solches Event aus?
• Wie fange ich es ab?
• Und vor allem: wie löse ich es aus?
#WISSENTEILEN
// event to indicate that a new customer was created
public class CustomerCreatedEvent {
private Customer customer;
public CustomerCreatedEvent(Customer customer) {
this.customer = customer;
}
public Customer getCustomer() {
return this.customer;
}
}
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject
private Event<CustomerCreatedEvent> customerCreatedEventSource;
@Inject
private CustomerService customerService;
private Customer currentCustomer;
@Transactional
public Outcome addCustomer() {
// add customer to db via customer service
customerService.createCustomer(currentCustomer);
customerCreatedEventSource.fire(new CustomerCreatedEvent(currentCustomer));
return Outcome.SUCCESS;
} …
}
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject
private Event<CustomerCreatedEvent> customerCreatedEventSource;
@Inject
private CustomerService customerService;
private Customer currentCustomer;
@Transactional
public Outcome addCustomer() {
// add customer to db via customer service
customerService.createCustomer(currentCustomer);
customerCreatedEventSource.fire(new CustomerCreatedEvent(currentCustomer));
return Outcome.SUCCESS;
} …
}
#WISSENTEILEN
@ApplicationScoped
public class Mailer implements Serializable {
@Inject
private MailService mailService;
public void sendWelcomeMail(@Observes CustomerCreatedEvent event) {
// send welcome mail, if customer has an email address
Customer customer = event.getCustomer();
if (customer.getEmail() != null) {
mailService.sendMail(...);
}
}
public void sendGoodbyeMail(@Observes CustomerDeletedEvent event) {
...
}
}
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject
private Event<CustomerCreatedEvent> eventSource;
@Inject
private CustomerService customerService;
private Customer currentCustomer;
@Transactional
public Outcome addCustomer() {
// add customer to db via customer service
customerService.createCustomer(currentCustomer);
eventSource.fire(new CustomerCreatedEvent(currentCustomer));
return Outcome.SUCCESS;
} …
}
Infrastruktur vs
Fachlichkeit?
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject @Created
private Event<Customer> eventSource;
@Inject
private CustomerService customerService;
private Customer currentCustomer;
@Transactional
public Outcome addCustomer() {
// add customer to db via customer service
customerService.createCustomer(currentCustomer);
eventSource.fire(currentCustomer));
return Outcome.SUCCESS;
} …
}
#WISSENTEILEN
@ApplicationScoped
public class Mailer implements Serializable {
@Inject
MailService mailService;
public void sendWelcomeMail(@Observes @Created Customer customer) {
// send welcome mail, if customer has an email address
if (customer.getEmail() != null) {
mailService.sendMail(...);
}
}
public void sendGoodbyeMail(@Observes @Deleted Customer customer) {
...
}
}
#WISSENTEILEN
@ApplicationScoped
public class TrackingService implements Serializable {
@Inject @Current
private CallCenterAgent currentCallCenterAgent;
// conditional observer method that takes into account:
// - Transaction status, e.g. AFTER_SUCCESS, AFTER_FAILURE
public void trackCustomerCreated(@Observes(during=AFTER_SUCCESS)
@Created Customer newCustomer) {
// track only if agent is in role TRAINEE
if (Role.TRAINEE.equals(currentCallCenterAgent.getRole()){
this.trackAction(TrackAction.CUSTOMER_CREATED, newCustomer)
}
}
...
}
#WISSENTEILEN
@ApplicationScoped
public class GlobalCache implements Serializable {
// conditional observer method that takes into account:
// - Bean instance status: ALLWAYS or IF_EXISTS
// - Transaction status, e.g. AFTER_SUCCESS, AFTER_FAILURE
public void insertIntoCache(@Observes(receive=IF_EXISTS,
during=AFTER=SUCCESS)
@Created Customer newCustomer) { ... }
// conditional observer method that takes into account:
// - Bean instance status: ALLWAYS or IF_EXISTS
// - Transaction status, e.g. AFTER_SUCCESS, AFTER_FAILURE
public void insertIntoCache(@Observes(receive=IF_EXISTS,
during=AFTER=SUCCESS)
@Deleted Customer deletedCustomer) { ... }
...
}
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject @Created
private Event<Customer> eventSource;
...
@Transactional
public Outcome addCustomer() {
// add customer to db via customer service
customerService.createCustomer(currentCustomer);
eventSource.fire(currentCustomer));
return Outcome.SUCCESS;
} …
}
synchronous vs.
asynchronous?
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject @Created
private Event<Customer> eventSource;
...
@Transactional
public Outcome addCustomer() {
// add customer to db via customer service
customerService.createCustomer(currentCustomer);
eventSource.fireAsync(currentCustomer));
return Outcome.SUCCESS;
} …
}
btw: returns a
CompletableStage
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject @Created
private Event<Customer> eventSource;
...
@Transactional
public Outcome addCustomer() {
// add customer to db via customer service
customerService.createCustomer(currentCustomer);
eventSource.fireAsync(currentCustomer)
.whenComplete((event, throwable) -> {
if (throwable != null) { ... } else { ... }
});
return Outcome.SUCCESS;
} …
}
allows beeing
reactive ;-)
#WISSENTEILEN
@ApplicationScoped
public class Mailer implements Serializable {
@Inject
private MailService mailService;
public void sendWelcomeMail(@ObservesAsync
@Customer Customer customer) {
...
}
public void sendGoodbyeMail(@ObservesAsync
@Customer Customer customer) {
...
}
}
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject @Created
private Event<Customer> eventSource;
...
@Transactional
public Outcome addCustomer() {
// add customer to db via customer service
customerService.createCustomer(currentCustomer);
eventSource.fire(currentCustomer));
return Outcome.SUCCESS;
} …
}
statische vs. dynamische Qualifier?
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject @Created
private Event<Customer> eventSource;
@Inject @TenantId // e.g. @TenantId(“4711“) for tenant „4711“
private String tenantId;
...
// fire event: @Created @Tenant(“4711“) currentCustomer
@Transactional
public Outcome addCustomer() {
// add customer to db via customer service
customerService.createCustomer(currentCustomer);
eventSource.select(new TenantQualifier(tenantId)).fire(currentCustomer));
return Outcome.SUCCESS;
} …
}
#WISSENTEILEN
@ApplicationScoped
public class SpecialMailerFor4711 implements Serializable {
@Inject
private MailService mailService;
public void sendWelcomeMail(@Observes @TenantId(“4711“)
@Customer Customer customer) {
...
}
public void sendGoodbyeMail(@Observes @TenantId(“4711“)
@Customer Customer customer) {
...
}
}
#WISSENTEILEN
Résumé
#WISSENTEILEN
X-Tier Application
a.k.a. Infrastructure-driven Architecture
• technische Injection
• technische Transaktionen
• technische Scopes
• technische Methoden
#WISSENTEILEN
TX
#WISSENTEILEN
No-Tier Application
a.k.a. Business-driven Architecture
• fachliche Injection
• fachliche Transaktionen
• fachliche Scopes
• fachliche Methoden
#WISSENTEILEN
TX
#WISSENTEILEN
TX
#WISSENTEILEN
Bonus
Material
#WISSENTEILEN
TX
#WISSENTEILEN
TX
#WISSENTEILEN
Fachliche UI Injection
#WISSENTEILEN
Fachliche Injection in Views
Views sind nach wie vor ein Problem
• Injection via U-EL
• fachliche von UI Controllern
#WISSENTEILEN
<html ...>
<h:body>
<h:form>
Vorname: <h:inputText
value=“#{createCustomerController.customer.firstname}"/>
Name: <h:inputText
value=“#{createCustomerController.customer.lastname}"/>
</h:form>
</h:body>
</html>
#WISSENTEILEN
<html ...>
<h:body>
<h:form>
Vorname: <h:inputText
value=“#{customerToCreate.firstname}"/>
Name: <h:inputText
value=“#{customerToCreate.lastname}"/>
</h:form>
</h:body>
</html>
#WISSENTEILEN
@Named("createCustomerController")
@RequestScoped
public class CreateCustomerController {
@Inject
private CustomerService customerService;
private Customer customerToCreate;
@Produces
@Named(“customerToCreate“)
public Customer getCustomer () {
return customerToCreate;
}
...
}
#WISSENTEILEN
@Named(“customerController")
@RequestScoped
public class CustomerController {
@Inject
private CustomerService customerService;
@Produces
@Named(“customers“)
public Collection<Customer> getAllCustomers() {
return customerService.findAll();
}
@Produces
@Named(“prospects“)
public Collection<Customer> getAllProspects () {
return customerService.findAllOf(CustomerType.PROSPECT);
}
...
}
Infrastructure vs.
Fachlichkeit
#WISSENTEILEN
public class CustomerRepository {
@PersistenceContext
private EntityManager em;
@Produces
@Named(“customers“)
public Collection<Customer> findAll() {
return em.createNamedQuery(“customer.findAll“, Customer.class)
.getResultList();
}
@Produces
@Named(“prospects“)
public Collection<Customer> findAllProspects () {
return em.createNamedQuery(“customer.findProspects“, Customer.class)
.getResultList();
}
...
}
#WISSENTEILEN
? ? ?
#WISSENTEILEN
Kontakt
LARS RÖWEKAMP
CIO NEW TECHNOLOGIES
lars.roewekamp@openknowledge.de
+49 (0)441 4082 – 0
@mobileLarson
@_openknowledge
OFFENKUNDIGGUT
#WISSENTEILEN
Bildnachweise
#04 © syda Productions – shutterstock.com
#30 © Dim Tik – shutterstock.com
#36 © Leonova Iuliia – shutterstock.com
#38 © print10 – istockphoto.com
#96 © Liliya Kandrashevich – shutterstock.com
All other pictures inside this presentation orginate
from pixabay.com or were created by my own.

More Related Content

Similar to No-Tier Enterprise Architecture

Using Azure Managed Identities for your App Services by Jan de Vries from 4Do...
Using Azure Managed Identities for your App Services by Jan de Vries from 4Do...Using Azure Managed Identities for your App Services by Jan de Vries from 4Do...
Using Azure Managed Identities for your App Services by Jan de Vries from 4Do...DevClub_lv
 
Global Azure - Use Azure Active Directory Managed Identities for your services!
Global Azure - Use Azure Active Directory Managed Identities for your services!Global Azure - Use Azure Active Directory Managed Identities for your services!
Global Azure - Use Azure Active Directory Managed Identities for your services!Jan de Vries
 
Next.Net event - Use Azure Active Directory Managed Identities for your servi...
Next.Net event - Use Azure Active Directory Managed Identities for your servi...Next.Net event - Use Azure Active Directory Managed Identities for your servi...
Next.Net event - Use Azure Active Directory Managed Identities for your servi...Jan de Vries
 
Multi-Tenancy with Spring Boot
Multi-Tenancy with Spring Boot Multi-Tenancy with Spring Boot
Multi-Tenancy with Spring Boot Stormpath
 
cloud telephony service
cloud telephony servicecloud telephony service
cloud telephony servicevinayrana40
 
Apex Enterprise Patterns: Building Strong Foundations
Apex Enterprise Patterns: Building Strong FoundationsApex Enterprise Patterns: Building Strong Foundations
Apex Enterprise Patterns: Building Strong FoundationsSalesforce Developers
 
Bdd with Cucumber and Mocha
Bdd with Cucumber and MochaBdd with Cucumber and Mocha
Bdd with Cucumber and MochaAtish Narlawar
 
Building and deploying microservices with event sourcing, CQRS and Docker (Be...
Building and deploying microservices with event sourcing, CQRS and Docker (Be...Building and deploying microservices with event sourcing, CQRS and Docker (Be...
Building and deploying microservices with event sourcing, CQRS and Docker (Be...Chris Richardson
 
Mobile services on windows azure (part3)
Mobile services on windows azure (part3)Mobile services on windows azure (part3)
Mobile services on windows azure (part3)Radu Vunvulea
 
마이크로소프트 Azure 에서 안드로이드 Push 구현과 Data 처리
마이크로소프트 Azure 에서 안드로이드  Push 구현과 Data 처리마이크로소프트 Azure 에서 안드로이드  Push 구현과 Data 처리
마이크로소프트 Azure 에서 안드로이드 Push 구현과 Data 처리Young D
 
Udi Dahan Intentions And Interfaces
Udi Dahan Intentions And InterfacesUdi Dahan Intentions And Interfaces
Udi Dahan Intentions And Interfacesdeimos
 
14147503 Intentions Interfaces Making Patterns Concrete
14147503 Intentions Interfaces Making Patterns Concrete14147503 Intentions Interfaces Making Patterns Concrete
14147503 Intentions Interfaces Making Patterns ConcreteQConLondon2008
 
MongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB.local Atlanta: Introduction to Serverless MongoDBMongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB.local Atlanta: Introduction to Serverless MongoDBMongoDB
 
The courage to business logic – Business Driven Architecture
The courage to business logic – Business Driven Architecture The courage to business logic – Business Driven Architecture
The courage to business logic – Business Driven Architecture OPEN KNOWLEDGE GmbH
 
API SOAP e Cron: integrare Magento con servizi esterni
API SOAP e Cron: integrare Magento con servizi esterniAPI SOAP e Cron: integrare Magento con servizi esterni
API SOAP e Cron: integrare Magento con servizi esterniAndrea De Pirro
 
Automate Business Processes with Point-and-Click Solutions
Automate Business Processes with Point-and-Click SolutionsAutomate Business Processes with Point-and-Click Solutions
Automate Business Processes with Point-and-Click SolutionsApttus
 
Developing enterprise ecommerce solutions using hybris by Drazen Nikolic - Be...
Developing enterprise ecommerce solutions using hybris by Drazen Nikolic - Be...Developing enterprise ecommerce solutions using hybris by Drazen Nikolic - Be...
Developing enterprise ecommerce solutions using hybris by Drazen Nikolic - Be...youngculture
 
Ignite 2019 - Telecommunications Industry
Ignite 2019 - Telecommunications IndustryIgnite 2019 - Telecommunications Industry
Ignite 2019 - Telecommunications IndustryRick Lievano
 
The Elastix Call Center Protocol Revealed
The Elastix Call Center Protocol RevealedThe Elastix Call Center Protocol Revealed
The Elastix Call Center Protocol RevealedPaloSanto Solutions
 

Similar to No-Tier Enterprise Architecture (20)

Using Azure Managed Identities for your App Services by Jan de Vries from 4Do...
Using Azure Managed Identities for your App Services by Jan de Vries from 4Do...Using Azure Managed Identities for your App Services by Jan de Vries from 4Do...
Using Azure Managed Identities for your App Services by Jan de Vries from 4Do...
 
Global Azure - Use Azure Active Directory Managed Identities for your services!
Global Azure - Use Azure Active Directory Managed Identities for your services!Global Azure - Use Azure Active Directory Managed Identities for your services!
Global Azure - Use Azure Active Directory Managed Identities for your services!
 
Next.Net event - Use Azure Active Directory Managed Identities for your servi...
Next.Net event - Use Azure Active Directory Managed Identities for your servi...Next.Net event - Use Azure Active Directory Managed Identities for your servi...
Next.Net event - Use Azure Active Directory Managed Identities for your servi...
 
Multi-Tenancy with Spring Boot
Multi-Tenancy with Spring Boot Multi-Tenancy with Spring Boot
Multi-Tenancy with Spring Boot
 
cloud telephony service
cloud telephony servicecloud telephony service
cloud telephony service
 
Apex Enterprise Patterns: Building Strong Foundations
Apex Enterprise Patterns: Building Strong FoundationsApex Enterprise Patterns: Building Strong Foundations
Apex Enterprise Patterns: Building Strong Foundations
 
Bdd with Cucumber and Mocha
Bdd with Cucumber and MochaBdd with Cucumber and Mocha
Bdd with Cucumber and Mocha
 
Building and deploying microservices with event sourcing, CQRS and Docker (Be...
Building and deploying microservices with event sourcing, CQRS and Docker (Be...Building and deploying microservices with event sourcing, CQRS and Docker (Be...
Building and deploying microservices with event sourcing, CQRS and Docker (Be...
 
Mobile services on windows azure (part3)
Mobile services on windows azure (part3)Mobile services on windows azure (part3)
Mobile services on windows azure (part3)
 
마이크로소프트 Azure 에서 안드로이드 Push 구현과 Data 처리
마이크로소프트 Azure 에서 안드로이드  Push 구현과 Data 처리마이크로소프트 Azure 에서 안드로이드  Push 구현과 Data 처리
마이크로소프트 Azure 에서 안드로이드 Push 구현과 Data 처리
 
Evolve your coding with some BDD
Evolve your coding with some BDDEvolve your coding with some BDD
Evolve your coding with some BDD
 
Udi Dahan Intentions And Interfaces
Udi Dahan Intentions And InterfacesUdi Dahan Intentions And Interfaces
Udi Dahan Intentions And Interfaces
 
14147503 Intentions Interfaces Making Patterns Concrete
14147503 Intentions Interfaces Making Patterns Concrete14147503 Intentions Interfaces Making Patterns Concrete
14147503 Intentions Interfaces Making Patterns Concrete
 
MongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB.local Atlanta: Introduction to Serverless MongoDBMongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB.local Atlanta: Introduction to Serverless MongoDB
 
The courage to business logic – Business Driven Architecture
The courage to business logic – Business Driven Architecture The courage to business logic – Business Driven Architecture
The courage to business logic – Business Driven Architecture
 
API SOAP e Cron: integrare Magento con servizi esterni
API SOAP e Cron: integrare Magento con servizi esterniAPI SOAP e Cron: integrare Magento con servizi esterni
API SOAP e Cron: integrare Magento con servizi esterni
 
Automate Business Processes with Point-and-Click Solutions
Automate Business Processes with Point-and-Click SolutionsAutomate Business Processes with Point-and-Click Solutions
Automate Business Processes with Point-and-Click Solutions
 
Developing enterprise ecommerce solutions using hybris by Drazen Nikolic - Be...
Developing enterprise ecommerce solutions using hybris by Drazen Nikolic - Be...Developing enterprise ecommerce solutions using hybris by Drazen Nikolic - Be...
Developing enterprise ecommerce solutions using hybris by Drazen Nikolic - Be...
 
Ignite 2019 - Telecommunications Industry
Ignite 2019 - Telecommunications IndustryIgnite 2019 - Telecommunications Industry
Ignite 2019 - Telecommunications Industry
 
The Elastix Call Center Protocol Revealed
The Elastix Call Center Protocol RevealedThe Elastix Call Center Protocol Revealed
The Elastix Call Center Protocol Revealed
 

More from OPEN KNOWLEDGE GmbH

Warum der Computer "Nein" sagt - Mehr Nachvollziehbarkeit dank Explainable AI
Warum der Computer "Nein" sagt - Mehr Nachvollziehbarkeit dank Explainable AIWarum der Computer "Nein" sagt - Mehr Nachvollziehbarkeit dank Explainable AI
Warum der Computer "Nein" sagt - Mehr Nachvollziehbarkeit dank Explainable AIOPEN KNOWLEDGE GmbH
 
Machine Learning? Ja gerne! Aber was und wie? Eine Kurzanleitung für den erfo...
Machine Learning? Ja gerne! Aber was und wie? Eine Kurzanleitung für den erfo...Machine Learning? Ja gerne! Aber was und wie? Eine Kurzanleitung für den erfo...
Machine Learning? Ja gerne! Aber was und wie? Eine Kurzanleitung für den erfo...OPEN KNOWLEDGE GmbH
 
From Zero to still Zero: Die schönsten Fehler auf dem Weg in die Cloud
From Zero to still Zero: Die schönsten Fehler auf dem Weg in die CloudFrom Zero to still Zero: Die schönsten Fehler auf dem Weg in die Cloud
From Zero to still Zero: Die schönsten Fehler auf dem Weg in die CloudOPEN KNOWLEDGE GmbH
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
FEHLENDE DATEN? (K)EIN PROBLEM!: Die Kunst der Data Imputation
FEHLENDE DATEN? (K)EIN PROBLEM!: Die Kunst der Data ImputationFEHLENDE DATEN? (K)EIN PROBLEM!: Die Kunst der Data Imputation
FEHLENDE DATEN? (K)EIN PROBLEM!: Die Kunst der Data ImputationOPEN KNOWLEDGE GmbH
 
Cloud-native and Enterprise Java? Hold my beer!
Cloud-native and Enterprise Java? Hold my beer!Cloud-native and Enterprise Java? Hold my beer!
Cloud-native and Enterprise Java? Hold my beer!OPEN KNOWLEDGE GmbH
 
From Zero to still Zero: The most beautiful mistakes going into the cloud.
From Zero to still Zero: The most beautiful mistakes going into the cloud. From Zero to still Zero: The most beautiful mistakes going into the cloud.
From Zero to still Zero: The most beautiful mistakes going into the cloud. OPEN KNOWLEDGE GmbH
 
Ready for the Future: Jakarta EE in Zeiten von Cloud Native & Co
Ready for the Future: Jakarta EE in Zeiten von Cloud Native & CoReady for the Future: Jakarta EE in Zeiten von Cloud Native & Co
Ready for the Future: Jakarta EE in Zeiten von Cloud Native & CoOPEN KNOWLEDGE GmbH
 
Shared Data in verteilten Architekturen
Shared Data in verteilten ArchitekturenShared Data in verteilten Architekturen
Shared Data in verteilten ArchitekturenOPEN KNOWLEDGE GmbH
 
Machine Learning mit TensorFlow.js
Machine Learning mit TensorFlow.jsMachine Learning mit TensorFlow.js
Machine Learning mit TensorFlow.jsOPEN KNOWLEDGE GmbH
 
It's not Rocket Science: Neuronale Netze
It's not Rocket Science: Neuronale NetzeIt's not Rocket Science: Neuronale Netze
It's not Rocket Science: Neuronale NetzeOPEN KNOWLEDGE GmbH
 
Shared Data in verteilten Systemen
Shared Data in verteilten SystemenShared Data in verteilten Systemen
Shared Data in verteilten SystemenOPEN KNOWLEDGE GmbH
 
Mehr Sicherheit durch Automatisierung
Mehr Sicherheit durch AutomatisierungMehr Sicherheit durch Automatisierung
Mehr Sicherheit durch AutomatisierungOPEN KNOWLEDGE GmbH
 
API-Design, Microarchitecture und Testing
API-Design, Microarchitecture und TestingAPI-Design, Microarchitecture und Testing
API-Design, Microarchitecture und TestingOPEN KNOWLEDGE GmbH
 
Supersonic Java für die Cloud: Quarkus
Supersonic Java für die Cloud: QuarkusSupersonic Java für die Cloud: Quarkus
Supersonic Java für die Cloud: QuarkusOPEN KNOWLEDGE GmbH
 
Hilfe, ich will meinen Monolithen zurück!
Hilfe, ich will meinen Monolithen zurück!Hilfe, ich will meinen Monolithen zurück!
Hilfe, ich will meinen Monolithen zurück!OPEN KNOWLEDGE GmbH
 

More from OPEN KNOWLEDGE GmbH (20)

Warum der Computer "Nein" sagt - Mehr Nachvollziehbarkeit dank Explainable AI
Warum der Computer "Nein" sagt - Mehr Nachvollziehbarkeit dank Explainable AIWarum der Computer "Nein" sagt - Mehr Nachvollziehbarkeit dank Explainable AI
Warum der Computer "Nein" sagt - Mehr Nachvollziehbarkeit dank Explainable AI
 
Machine Learning? Ja gerne! Aber was und wie? Eine Kurzanleitung für den erfo...
Machine Learning? Ja gerne! Aber was und wie? Eine Kurzanleitung für den erfo...Machine Learning? Ja gerne! Aber was und wie? Eine Kurzanleitung für den erfo...
Machine Learning? Ja gerne! Aber was und wie? Eine Kurzanleitung für den erfo...
 
From Zero to still Zero: Die schönsten Fehler auf dem Weg in die Cloud
From Zero to still Zero: Die schönsten Fehler auf dem Weg in die CloudFrom Zero to still Zero: Die schönsten Fehler auf dem Weg in die Cloud
From Zero to still Zero: Die schönsten Fehler auf dem Weg in die Cloud
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
FEHLENDE DATEN? (K)EIN PROBLEM!: Die Kunst der Data Imputation
FEHLENDE DATEN? (K)EIN PROBLEM!: Die Kunst der Data ImputationFEHLENDE DATEN? (K)EIN PROBLEM!: Die Kunst der Data Imputation
FEHLENDE DATEN? (K)EIN PROBLEM!: Die Kunst der Data Imputation
 
Nie wieder Log-Files!
Nie wieder Log-Files!Nie wieder Log-Files!
Nie wieder Log-Files!
 
Cloud-native and Enterprise Java? Hold my beer!
Cloud-native and Enterprise Java? Hold my beer!Cloud-native and Enterprise Java? Hold my beer!
Cloud-native and Enterprise Java? Hold my beer!
 
From Zero to still Zero: The most beautiful mistakes going into the cloud.
From Zero to still Zero: The most beautiful mistakes going into the cloud. From Zero to still Zero: The most beautiful mistakes going into the cloud.
From Zero to still Zero: The most beautiful mistakes going into the cloud.
 
API Expand Contract
API Expand ContractAPI Expand Contract
API Expand Contract
 
Ready for the Future: Jakarta EE in Zeiten von Cloud Native & Co
Ready for the Future: Jakarta EE in Zeiten von Cloud Native & CoReady for the Future: Jakarta EE in Zeiten von Cloud Native & Co
Ready for the Future: Jakarta EE in Zeiten von Cloud Native & Co
 
Shared Data in verteilten Architekturen
Shared Data in verteilten ArchitekturenShared Data in verteilten Architekturen
Shared Data in verteilten Architekturen
 
Machine Learning mit TensorFlow.js
Machine Learning mit TensorFlow.jsMachine Learning mit TensorFlow.js
Machine Learning mit TensorFlow.js
 
KI und Architektur
KI und ArchitekturKI und Architektur
KI und Architektur
 
It's not Rocket Science: Neuronale Netze
It's not Rocket Science: Neuronale NetzeIt's not Rocket Science: Neuronale Netze
It's not Rocket Science: Neuronale Netze
 
Shared Data in verteilten Systemen
Shared Data in verteilten SystemenShared Data in verteilten Systemen
Shared Data in verteilten Systemen
 
Business-Mehrwert durch KI
Business-Mehrwert durch KIBusiness-Mehrwert durch KI
Business-Mehrwert durch KI
 
Mehr Sicherheit durch Automatisierung
Mehr Sicherheit durch AutomatisierungMehr Sicherheit durch Automatisierung
Mehr Sicherheit durch Automatisierung
 
API-Design, Microarchitecture und Testing
API-Design, Microarchitecture und TestingAPI-Design, Microarchitecture und Testing
API-Design, Microarchitecture und Testing
 
Supersonic Java für die Cloud: Quarkus
Supersonic Java für die Cloud: QuarkusSupersonic Java für die Cloud: Quarkus
Supersonic Java für die Cloud: Quarkus
 
Hilfe, ich will meinen Monolithen zurück!
Hilfe, ich will meinen Monolithen zurück!Hilfe, ich will meinen Monolithen zurück!
Hilfe, ich will meinen Monolithen zurück!
 

Recently uploaded

Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...Abortion Clinic
 
Your Ultimate Web Studio for Streaming Anywhere | Evmux
Your Ultimate Web Studio for Streaming Anywhere | EvmuxYour Ultimate Web Studio for Streaming Anywhere | Evmux
Your Ultimate Web Studio for Streaming Anywhere | Evmuxevmux96
 
Effective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeConEffective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeConNatan Silnitsky
 
Weeding your micro service landscape.pdf
Weeding your micro service landscape.pdfWeeding your micro service landscape.pdf
Weeding your micro service landscape.pdftimtebeek1
 
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024SimonedeGijt
 
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024Andreas Granig
 
Workshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit Milan
Workshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit MilanWorkshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit Milan
Workshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit MilanNeo4j
 
OpenChain Webinar: AboutCode and Beyond - End-to-End SCA
OpenChain Webinar: AboutCode and Beyond - End-to-End SCAOpenChain Webinar: AboutCode and Beyond - End-to-End SCA
OpenChain Webinar: AboutCode and Beyond - End-to-End SCAShane Coughlan
 
Lessons Learned from Building a Serverless Notifications System.pdf
Lessons Learned from Building a Serverless Notifications System.pdfLessons Learned from Building a Serverless Notifications System.pdf
Lessons Learned from Building a Serverless Notifications System.pdfSrushith Repakula
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxAnnaArtyushina1
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationJuha-Pekka Tolvanen
 
Encryption Recap: A Refresher on Key Concepts
Encryption Recap: A Refresher on Key ConceptsEncryption Recap: A Refresher on Key Concepts
Encryption Recap: A Refresher on Key Conceptsthomashtkim
 
[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypse
[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypse[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypse
[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypseTomasz Kowalczewski
 

Recently uploaded (20)

Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
 
Your Ultimate Web Studio for Streaming Anywhere | Evmux
Your Ultimate Web Studio for Streaming Anywhere | EvmuxYour Ultimate Web Studio for Streaming Anywhere | Evmux
Your Ultimate Web Studio for Streaming Anywhere | Evmux
 
Effective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeConEffective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeCon
 
Weeding your micro service landscape.pdf
Weeding your micro service landscape.pdfWeeding your micro service landscape.pdf
Weeding your micro service landscape.pdf
 
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
 
Abortion Pill Prices Polokwane ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
Abortion Pill Prices Polokwane ](+27832195400*)[ 🏥 Women's Abortion Clinic in...Abortion Pill Prices Polokwane ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
Abortion Pill Prices Polokwane ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
 
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
 
Workshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit Milan
Workshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit MilanWorkshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit Milan
Workshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit Milan
 
Abortion Pill Prices Jane Furse ](+27832195400*)[🏥Women's Abortion Clinic in ...
Abortion Pill Prices Jane Furse ](+27832195400*)[🏥Women's Abortion Clinic in ...Abortion Pill Prices Jane Furse ](+27832195400*)[🏥Women's Abortion Clinic in ...
Abortion Pill Prices Jane Furse ](+27832195400*)[🏥Women's Abortion Clinic in ...
 
OpenChain Webinar: AboutCode and Beyond - End-to-End SCA
OpenChain Webinar: AboutCode and Beyond - End-to-End SCAOpenChain Webinar: AboutCode and Beyond - End-to-End SCA
OpenChain Webinar: AboutCode and Beyond - End-to-End SCA
 
Lessons Learned from Building a Serverless Notifications System.pdf
Lessons Learned from Building a Serverless Notifications System.pdfLessons Learned from Building a Serverless Notifications System.pdf
Lessons Learned from Building a Serverless Notifications System.pdf
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
微信号购买
微信号购买微信号购买
微信号购买
 
Abortion Clinic In Pongola ](+27832195400*)[ 🏥 Safe Abortion Pills In Pongola...
Abortion Clinic In Pongola ](+27832195400*)[ 🏥 Safe Abortion Pills In Pongola...Abortion Clinic In Pongola ](+27832195400*)[ 🏥 Safe Abortion Pills In Pongola...
Abortion Clinic In Pongola ](+27832195400*)[ 🏥 Safe Abortion Pills In Pongola...
 
Encryption Recap: A Refresher on Key Concepts
Encryption Recap: A Refresher on Key ConceptsEncryption Recap: A Refresher on Key Concepts
Encryption Recap: A Refresher on Key Concepts
 
Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
 
[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypse
[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypse[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypse
[GeeCON2024] How I learned to stop worrying and love the dark silicon apocalypse
 
Abortion Clinic in Bloemfontein [(+27832195400*)]🏥Safe Abortion Pills In Bloe...
Abortion Clinic in Bloemfontein [(+27832195400*)]🏥Safe Abortion Pills In Bloe...Abortion Clinic in Bloemfontein [(+27832195400*)]🏥Safe Abortion Pills In Bloe...
Abortion Clinic in Bloemfontein [(+27832195400*)]🏥Safe Abortion Pills In Bloe...
 
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
 

No-Tier Enterprise Architecture