SlideShare una empresa de Scribd logo
1 de 21
Descargar para leer sin conexión
Simple Web Development in Java
Vincent Tencé
@testinfected
http://vtence.com
http://github.com/testinfected
Déjà vu?
You start a new project by assembling multiple libraries and frameworks
It’s a lot of initial complexity
One of the frameworks keeps getting in the way
The framework feels like a prison
It keeps surprising you with unintended behaviour
The Original Version
• Spring with Spring MVC
• Velocity and SiteMesh, UrlRewriteFilter
• Hibernate, JPA, MySQL
• Hibernate Validator
• Maven
• ... 53 jars!
http://thepresentationdesigner.co.uk/blog/portfolio-item/bruce-lee-slide-2/
The Challenge
• Use simple tools and libraries
• Framework (Web, ORM, DI)
• DIYS (Do It Yourself Simply)
• Ease of assembly, configuration and deployment
• Minimum startup and shutdown costs
• XML
• Annotations
The Simple Version
• Simple
• Mustache
• JDBC and MySQL
• CLI
• Buildr
• 4 jars
Build File
define 'petstore', [..] do
define 'domain' do
compile.with
test.with HAMCREST
package :jar
end
define 'persistence' do
compile.with project(:domain)
test.with HAMCREST, :flyway, :mysql, NO_LOG, [...]
package :jar
end
define 'webapp' domain
compile.with :simpleframework, :jmustache, [...]
test.with HAMCREST, :antlr_runtime, :cssselectors, :hamcrest_dom, [...]
test.with transitive(artifacts(:nekohtml, :htmlunit, :jmock_legacy))
package :jar
end
[...]
end
Dependency Injection

AttachmentStorage attachments = new FileSystemPhotoStore("/photos");
Connection connection = new ConnectionReference(request).get();
Transactor transactor = new JDBCTransactor(connection);
ProductCatalog products = new ProductsDatabase(connection);
ItemInventory items = new ItemsDatabase(connection);
OrderBook orders = new OrdersDatabase(connection);
ProcurementRequestHandler procurement =
new PurchasingAgent(products, items, transactor)
OrderNumberSequence orderNumbers = new OrderNumberDatabaseSequence(connection);
Cashier cashier = new Cashier(orderNumbers, orders, transactor);
Messages messages =
new BundledMessages(ResourceBundle.getBundle("ValidationMessages"))
Router router = Router.draw(new DynamicRoutes() {{
[...]
}});
Routing

[...]
Router router = Router.draw(new DynamicRoutes() {{
get("/products").to(new ListProducts(products, attachments, pages.products()));
post("/products").to(new CreateProduct(procurement));
get("/products/:product/items").to(new ListItems(items, pages.items()));
post("/products/:product/items").to(new CreateItem(procurement));
get("/cart").to(new ShowCart(cashier, pages.cart()));
post("/cart").to(new CreateCartItem(cashier));
get("/orders/new").to(new Checkout(cashier, pages.checkout()));
get("/orders/:number").to(new ShowOrder(orders, pages.order()));
post("/orders").to(new PlaceOrder(cashier));
delete("/logout").to(new Logout());
map("/").to(new StaticPage(pages.home()));
}});
MVC

public class ShowOrder implements Application {
private final OrderBook orderBook;
private final Page orderPage;
public ShowOrder(OrderBook orderBook, Page orderPage) {
this.orderBook = orderBook;
this.orderPage = orderPage;
}
public void handle(Request request, Response response) throws Exception {
String number = request.parameter("number");
Order order = orderBook.find(new OrderNumber(number));
orderPage.render(response, context().with("order", order));
}
}
Data Access
public class OrdersDatabase implements OrderBook {
[...]
public OrdersDatabase(Connection connection) {
this.connection = connection;
}
private List<LineItem> findLineItemsOf(Order order) {
return Select.from(lineItems).
where("order_id = ?", idOf(order).get()).
orderBy("order_line").
list(connection);
}
private Order findOrder(OrderNumber orderNumber) {
return Select.from(orders, "_order").
leftJoin(payments, "payment", "_order.payment_id = payment.id").
where("_order.number = ?", orderNumber).
first(connection);
}
[...]
}
Transactions

public class Cashier implements SalesAssistant {
[...]
public OrderNumber placeOrder(PaymentMethod paymentMethod) throws Exception {
[...]
QueryUnitOfWork<OrderNumber> order = new QueryUnitOfWork<OrderNumber>() {
public OrderNumber query() throws Exception {
OrderNumber nextNumber = orderNumberSequence.nextOrderNumber();
final Order order = new Order(nextNumber);
order.addItemsFrom(cart);
order.pay(paymentMethod);
orderBook.record(order);
cart.clear();
return nextNumber;
}
};
return transactor.performQuery(order);
}
[...]
}
Validation Constraints
public class CreditCardDetails extends PaymentMethod implements Serializable {
private final CreditCardType cardType;
private final Constraint<String> cardNumber;
private final NotNull<String> cardExpiryDate;
private final Valid<Address> billingAddress;
public CreditCardDetails(CreditCardType type,
String number,
String expiryDate,
Address billingAddress) {
this.cardType = type;
this.cardNumber = Validates.both(notEmpty(number),
correctnessOf(type, number));
this.cardExpiryDate = Validates.notNull(expiryDate);
this.billingAddress = Validates.validityOf(billingAddress);
}
public String getCardNumber() {
return cardNumber.get();
}
[...]
}
Validation

public class Validator {
public <T> Set<ConstraintViolation<?>> validate(T target) {
Valid<T> valid = Validates.validityOf(target);
valid.disableRootViolation();
ViolationsReport report = new ViolationsReport();
valid.check(Path.root(target), report);
return report.violations();
}
[...]
}
Forms
public class PaymentForm extends Form {
public static PaymentForm parse(Request request) {
return new PaymentForm(new CreditCardDetails(
valueOf(request.parameter("card-type")),
request.parameter("card-number"),
request.parameter("expiry-date"),
new Address(request.parameter("first-name"),
request.parameter("last-name"),
request.parameter("email"))));
}
private final Valid<CreditCardDetails> paymentDetails;
public PaymentForm(CreditCardDetails paymentDetails) {
this.paymentDetails = Validates.validityOf(paymentDetails);
}
public CreditCardType cardType() { return paymentDetails().getCardType(); }
public CreditCardDetails paymentDetails() { return paymentDetails.get(); }
}
Thoughts
• Not very “enterprisy”
• What are we missing?
• Use a proven solution or develop our own?
• Not a silver bullet
Takeaways
• Avoid the temptation of frameworks
• Use simple tools that do one thing and do it well
• Build your own tools
• Copy the best ideas; write only the simple code you need
• Keep your tools simple and specialized
Thanks!
• Simple version :
https://github.com/testinfected/simple-petstore
• Spring version :
https://github.com/testinfected/petstore
• Web :
https://github.com/testinfected/molecule
• Data Mapping :
https://github.com/testinfected/tape

Más contenido relacionado

La actualidad más candente

CodeFest 2013. Ерошенко А. — Фреймворк Html Elements или как удобно взаимодей...
CodeFest 2013. Ерошенко А. — Фреймворк Html Elements или как удобно взаимодей...CodeFest 2013. Ерошенко А. — Фреймворк Html Elements или как удобно взаимодей...
CodeFest 2013. Ерошенко А. — Фреймворк Html Elements или как удобно взаимодей...CodeFest
 
Intro to HTML5 Web Storage
Intro to HTML5 Web StorageIntro to HTML5 Web Storage
Intro to HTML5 Web Storagedylanks
 
Organizing Code with JavascriptMVC
Organizing Code with JavascriptMVCOrganizing Code with JavascriptMVC
Organizing Code with JavascriptMVCThomas Reynolds
 
When dynamic becomes static: the next step in web caching techniques
When dynamic becomes static: the next step in web caching techniquesWhen dynamic becomes static: the next step in web caching techniques
When dynamic becomes static: the next step in web caching techniquesWim Godden
 
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)Sirar Salih
 
The love child of Android and .NET: App development with Xamarin
The love child of Android and .NET: App development with XamarinThe love child of Android and .NET: App development with Xamarin
The love child of Android and .NET: App development with XamarinLorenz Cuno Klopfenstein
 
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...tdc-globalcode
 
Intro to IndexedDB (Beta)
Intro to IndexedDB (Beta)Intro to IndexedDB (Beta)
Intro to IndexedDB (Beta)Mike West
 
Write Less Do More
Write Less Do MoreWrite Less Do More
Write Less Do MoreRemy Sharp
 
Persistent Offline Storage White
Persistent Offline Storage WhitePersistent Offline Storage White
Persistent Offline Storage WhiteAlexei White
 
Realm or: How I learned to stop worrying and love my app database
Realm or: How I learned to stop worrying and love my app databaseRealm or: How I learned to stop worrying and love my app database
Realm or: How I learned to stop worrying and love my app databaseSergi Martínez
 
Introduction to the new official C# Driver developed by 10gen
Introduction to the new official C# Driver developed by 10genIntroduction to the new official C# Driver developed by 10gen
Introduction to the new official C# Driver developed by 10genMongoDB
 
JavaScript!
JavaScript!JavaScript!
JavaScript!RTigger
 
Paris js extensions
Paris js extensionsParis js extensions
Paris js extensionserwanl
 
HtmlElements – естественное расширение PageObject
HtmlElements – естественное расширение PageObjectHtmlElements – естественное расширение PageObject
HtmlElements – естественное расширение PageObjectSQALab
 
History of jQuery
History of jQueryHistory of jQuery
History of jQueryjeresig
 

La actualidad más candente (20)

iOS5 NewStuff
iOS5 NewStuffiOS5 NewStuff
iOS5 NewStuff
 
CodeFest 2013. Ерошенко А. — Фреймворк Html Elements или как удобно взаимодей...
CodeFest 2013. Ерошенко А. — Фреймворк Html Elements или как удобно взаимодей...CodeFest 2013. Ерошенко А. — Фреймворк Html Elements или как удобно взаимодей...
CodeFest 2013. Ерошенко А. — Фреймворк Html Elements или как удобно взаимодей...
 
Intro to HTML5 Web Storage
Intro to HTML5 Web StorageIntro to HTML5 Web Storage
Intro to HTML5 Web Storage
 
Organizing Code with JavascriptMVC
Organizing Code with JavascriptMVCOrganizing Code with JavascriptMVC
Organizing Code with JavascriptMVC
 
When dynamic becomes static: the next step in web caching techniques
When dynamic becomes static: the next step in web caching techniquesWhen dynamic becomes static: the next step in web caching techniques
When dynamic becomes static: the next step in web caching techniques
 
Ecom2
Ecom2Ecom2
Ecom2
 
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)
 
The love child of Android and .NET: App development with Xamarin
The love child of Android and .NET: App development with XamarinThe love child of Android and .NET: App development with Xamarin
The love child of Android and .NET: App development with Xamarin
 
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
 
Sequelize
SequelizeSequelize
Sequelize
 
Intro to IndexedDB (Beta)
Intro to IndexedDB (Beta)Intro to IndexedDB (Beta)
Intro to IndexedDB (Beta)
 
Write Less Do More
Write Less Do MoreWrite Less Do More
Write Less Do More
 
Persistent Offline Storage White
Persistent Offline Storage WhitePersistent Offline Storage White
Persistent Offline Storage White
 
Realm or: How I learned to stop worrying and love my app database
Realm or: How I learned to stop worrying and love my app databaseRealm or: How I learned to stop worrying and love my app database
Realm or: How I learned to stop worrying and love my app database
 
Introduction to the new official C# Driver developed by 10gen
Introduction to the new official C# Driver developed by 10genIntroduction to the new official C# Driver developed by 10gen
Introduction to the new official C# Driver developed by 10gen
 
JavaScript!
JavaScript!JavaScript!
JavaScript!
 
Paris js extensions
Paris js extensionsParis js extensions
Paris js extensions
 
HtmlElements – естественное расширение PageObject
HtmlElements – естественное расширение PageObjectHtmlElements – естественное расширение PageObject
HtmlElements – естественное расширение PageObject
 
History of jQuery
History of jQueryHistory of jQuery
History of jQuery
 
Mongo db for c# developers
Mongo db for c# developersMongo db for c# developers
Mongo db for c# developers
 

Similar a Simple Web Development in Java

Retour à la simplicité
Retour à la simplicitéRetour à la simplicité
Retour à la simplicitéVincent Tencé
 
Local storage in Web apps
Local storage in Web appsLocal storage in Web apps
Local storage in Web appsIvano Malavolta
 
Local data storage for mobile apps
Local data storage for mobile appsLocal data storage for mobile apps
Local data storage for mobile appsIvano Malavolta
 
10.Local Database & LINQ
10.Local Database & LINQ10.Local Database & LINQ
10.Local Database & LINQNguyen Tuan
 
Présentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC BelgiquePrésentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC BelgiqueDenis Voituron
 
Rich Internet Applications con JavaFX e NetBeans
Rich Internet Applications  con JavaFX e NetBeans Rich Internet Applications  con JavaFX e NetBeans
Rich Internet Applications con JavaFX e NetBeans Fabrizio Giudici
 
Bye bye $GLOBALS['TYPO3_DB']
Bye bye $GLOBALS['TYPO3_DB']Bye bye $GLOBALS['TYPO3_DB']
Bye bye $GLOBALS['TYPO3_DB']Jan Helke
 
[2015/2016] Local data storage for web-based mobile apps
[2015/2016] Local data storage for web-based mobile apps[2015/2016] Local data storage for web-based mobile apps
[2015/2016] Local data storage for web-based mobile appsIvano Malavolta
 
Painless Persistence in a Disconnected World
Painless Persistence in a Disconnected WorldPainless Persistence in a Disconnected World
Painless Persistence in a Disconnected WorldChristian Melchior
 
dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...
dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...
dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...dotNet Miami
 
Entity Framework: Code First and Magic Unicorns
Entity Framework: Code First and Magic UnicornsEntity Framework: Code First and Magic Unicorns
Entity Framework: Code First and Magic UnicornsRichie Rump
 
Web Technologies - forms and actions
Web Technologies -  forms and actionsWeb Technologies -  forms and actions
Web Technologies - forms and actionsAren Zomorodian
 
Scaling php applications with redis
Scaling php applications with redisScaling php applications with redis
Scaling php applications with redisjimbojsb
 
Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Sven Efftinge
 
Bare-knuckle web development
Bare-knuckle web developmentBare-knuckle web development
Bare-knuckle web developmentJohannes Brodwall
 
Introducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.jsIntroducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.jsRichard Rodger
 

Similar a Simple Web Development in Java (20)

Retour à la simplicité
Retour à la simplicitéRetour à la simplicité
Retour à la simplicité
 
Local storage in Web apps
Local storage in Web appsLocal storage in Web apps
Local storage in Web apps
 
Local Storage
Local StorageLocal Storage
Local Storage
 
Linq
LinqLinq
Linq
 
Local data storage for mobile apps
Local data storage for mobile appsLocal data storage for mobile apps
Local data storage for mobile apps
 
Real World MVC
Real World MVCReal World MVC
Real World MVC
 
10.Local Database & LINQ
10.Local Database & LINQ10.Local Database & LINQ
10.Local Database & LINQ
 
Présentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC BelgiquePrésentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC Belgique
 
Rich Internet Applications con JavaFX e NetBeans
Rich Internet Applications  con JavaFX e NetBeans Rich Internet Applications  con JavaFX e NetBeans
Rich Internet Applications con JavaFX e NetBeans
 
Bye bye $GLOBALS['TYPO3_DB']
Bye bye $GLOBALS['TYPO3_DB']Bye bye $GLOBALS['TYPO3_DB']
Bye bye $GLOBALS['TYPO3_DB']
 
[2015/2016] Local data storage for web-based mobile apps
[2015/2016] Local data storage for web-based mobile apps[2015/2016] Local data storage for web-based mobile apps
[2015/2016] Local data storage for web-based mobile apps
 
Painless Persistence in a Disconnected World
Painless Persistence in a Disconnected WorldPainless Persistence in a Disconnected World
Painless Persistence in a Disconnected World
 
dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...
dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...
dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...
 
Entity Framework: Code First and Magic Unicorns
Entity Framework: Code First and Magic UnicornsEntity Framework: Code First and Magic Unicorns
Entity Framework: Code First and Magic Unicorns
 
Web Technologies - forms and actions
Web Technologies -  forms and actionsWeb Technologies -  forms and actions
Web Technologies - forms and actions
 
Scaling php applications with redis
Scaling php applications with redisScaling php applications with redis
Scaling php applications with redis
 
Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]
 
Php summary
Php summaryPhp summary
Php summary
 
Bare-knuckle web development
Bare-knuckle web developmentBare-knuckle web development
Bare-knuckle web development
 
Introducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.jsIntroducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.js
 

Último

FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024The Digital Insurer
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfOverkill Security
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...apidays
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Jeffrey Haguewood
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Zilliz
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 

Último (20)

FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 

Simple Web Development in Java

  • 1. Simple Web Development in Java Vincent Tencé @testinfected http://vtence.com http://github.com/testinfected
  • 2. Déjà vu? You start a new project by assembling multiple libraries and frameworks It’s a lot of initial complexity One of the frameworks keeps getting in the way The framework feels like a prison It keeps surprising you with unintended behaviour
  • 3.
  • 4. The Original Version • Spring with Spring MVC • Velocity and SiteMesh, UrlRewriteFilter • Hibernate, JPA, MySQL • Hibernate Validator • Maven • ... 53 jars!
  • 5.
  • 7. The Challenge • Use simple tools and libraries • Framework (Web, ORM, DI) • DIYS (Do It Yourself Simply) • Ease of assembly, configuration and deployment • Minimum startup and shutdown costs • XML • Annotations
  • 8. The Simple Version • Simple • Mustache • JDBC and MySQL • CLI • Buildr • 4 jars
  • 9.
  • 10. Build File define 'petstore', [..] do define 'domain' do compile.with test.with HAMCREST package :jar end define 'persistence' do compile.with project(:domain) test.with HAMCREST, :flyway, :mysql, NO_LOG, [...] package :jar end define 'webapp' domain compile.with :simpleframework, :jmustache, [...] test.with HAMCREST, :antlr_runtime, :cssselectors, :hamcrest_dom, [...] test.with transitive(artifacts(:nekohtml, :htmlunit, :jmock_legacy)) package :jar end [...] end
  • 11. Dependency Injection AttachmentStorage attachments = new FileSystemPhotoStore("/photos"); Connection connection = new ConnectionReference(request).get(); Transactor transactor = new JDBCTransactor(connection); ProductCatalog products = new ProductsDatabase(connection); ItemInventory items = new ItemsDatabase(connection); OrderBook orders = new OrdersDatabase(connection); ProcurementRequestHandler procurement = new PurchasingAgent(products, items, transactor) OrderNumberSequence orderNumbers = new OrderNumberDatabaseSequence(connection); Cashier cashier = new Cashier(orderNumbers, orders, transactor); Messages messages = new BundledMessages(ResourceBundle.getBundle("ValidationMessages")) Router router = Router.draw(new DynamicRoutes() {{ [...] }});
  • 12. Routing [...] Router router = Router.draw(new DynamicRoutes() {{ get("/products").to(new ListProducts(products, attachments, pages.products())); post("/products").to(new CreateProduct(procurement)); get("/products/:product/items").to(new ListItems(items, pages.items())); post("/products/:product/items").to(new CreateItem(procurement)); get("/cart").to(new ShowCart(cashier, pages.cart())); post("/cart").to(new CreateCartItem(cashier)); get("/orders/new").to(new Checkout(cashier, pages.checkout())); get("/orders/:number").to(new ShowOrder(orders, pages.order())); post("/orders").to(new PlaceOrder(cashier)); delete("/logout").to(new Logout()); map("/").to(new StaticPage(pages.home())); }});
  • 13. MVC public class ShowOrder implements Application { private final OrderBook orderBook; private final Page orderPage; public ShowOrder(OrderBook orderBook, Page orderPage) { this.orderBook = orderBook; this.orderPage = orderPage; } public void handle(Request request, Response response) throws Exception { String number = request.parameter("number"); Order order = orderBook.find(new OrderNumber(number)); orderPage.render(response, context().with("order", order)); } }
  • 14. Data Access public class OrdersDatabase implements OrderBook { [...] public OrdersDatabase(Connection connection) { this.connection = connection; } private List<LineItem> findLineItemsOf(Order order) { return Select.from(lineItems). where("order_id = ?", idOf(order).get()). orderBy("order_line"). list(connection); } private Order findOrder(OrderNumber orderNumber) { return Select.from(orders, "_order"). leftJoin(payments, "payment", "_order.payment_id = payment.id"). where("_order.number = ?", orderNumber). first(connection); } [...] }
  • 15. Transactions public class Cashier implements SalesAssistant { [...] public OrderNumber placeOrder(PaymentMethod paymentMethod) throws Exception { [...] QueryUnitOfWork<OrderNumber> order = new QueryUnitOfWork<OrderNumber>() { public OrderNumber query() throws Exception { OrderNumber nextNumber = orderNumberSequence.nextOrderNumber(); final Order order = new Order(nextNumber); order.addItemsFrom(cart); order.pay(paymentMethod); orderBook.record(order); cart.clear(); return nextNumber; } }; return transactor.performQuery(order); } [...] }
  • 16. Validation Constraints public class CreditCardDetails extends PaymentMethod implements Serializable { private final CreditCardType cardType; private final Constraint<String> cardNumber; private final NotNull<String> cardExpiryDate; private final Valid<Address> billingAddress; public CreditCardDetails(CreditCardType type, String number, String expiryDate, Address billingAddress) { this.cardType = type; this.cardNumber = Validates.both(notEmpty(number), correctnessOf(type, number)); this.cardExpiryDate = Validates.notNull(expiryDate); this.billingAddress = Validates.validityOf(billingAddress); } public String getCardNumber() { return cardNumber.get(); } [...] }
  • 17. Validation public class Validator { public <T> Set<ConstraintViolation<?>> validate(T target) { Valid<T> valid = Validates.validityOf(target); valid.disableRootViolation(); ViolationsReport report = new ViolationsReport(); valid.check(Path.root(target), report); return report.violations(); } [...] }
  • 18. Forms public class PaymentForm extends Form { public static PaymentForm parse(Request request) { return new PaymentForm(new CreditCardDetails( valueOf(request.parameter("card-type")), request.parameter("card-number"), request.parameter("expiry-date"), new Address(request.parameter("first-name"), request.parameter("last-name"), request.parameter("email")))); } private final Valid<CreditCardDetails> paymentDetails; public PaymentForm(CreditCardDetails paymentDetails) { this.paymentDetails = Validates.validityOf(paymentDetails); } public CreditCardType cardType() { return paymentDetails().getCardType(); } public CreditCardDetails paymentDetails() { return paymentDetails.get(); } }
  • 19. Thoughts • Not very “enterprisy” • What are we missing? • Use a proven solution or develop our own? • Not a silver bullet
  • 20. Takeaways • Avoid the temptation of frameworks • Use simple tools that do one thing and do it well • Build your own tools • Copy the best ideas; write only the simple code you need • Keep your tools simple and specialized
  • 21. Thanks! • Simple version : https://github.com/testinfected/simple-petstore • Spring version : https://github.com/testinfected/petstore • Web : https://github.com/testinfected/molecule • Data Mapping : https://github.com/testinfected/tape