SlideShare a Scribd company logo
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

More Related Content

What's hot

iOS5 NewStuff
iOS5 NewStuffiOS5 NewStuff
iOS5 NewStuff
deenna_vargilz
 
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 Storage
dylanks
 
Organizing Code with JavascriptMVC
Organizing Code with JavascriptMVCOrganizing Code with JavascriptMVC
Organizing Code with JavascriptMVC
Thomas 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 techniques
Wim Godden
 
Ecom2
Ecom2Ecom2
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 Xamarin
Lorenz 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
 
Sequelize
SequelizeSequelize
Sequelize
Tarek Raihan
 
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 More
Remy Sharp
 
Persistent Offline Storage White
Persistent Offline Storage WhitePersistent Offline Storage White
Persistent Offline Storage White
Alexei 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
Sergi 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 10gen
MongoDB
 
JavaScript!
JavaScript!JavaScript!
JavaScript!
RTigger
 
Paris js extensions
Paris js extensionsParis js extensions
Paris js extensions
erwanl
 
HtmlElements – естественное расширение PageObject
HtmlElements – естественное расширение PageObjectHtmlElements – естественное расширение PageObject
HtmlElements – естественное расширение PageObject
SQALab
 
History of jQuery
History of jQueryHistory of jQuery
History of jQuery
jeresig
 
Mongo db for c# developers
Mongo db for c# developersMongo db for c# developers
Mongo db for c# developers
Simon Elliston Ball
 

What's hot (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 to 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 apps
Ivano Malavolta
 
Local Storage
Local StorageLocal Storage
Local Storage
Ivano Malavolta
 
Linq
LinqLinq
Local data storage for mobile apps
Local data storage for mobile appsLocal data storage for mobile apps
Local data storage for mobile apps
Ivano Malavolta
 
Real World MVC
Real World MVCReal World MVC
Real World MVC
James Johnson
 
10.Local Database & LINQ
10.Local Database & LINQ10.Local Database & LINQ
10.Local Database & LINQ
Nguyen 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 Belgique
Denis 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 apps
Ivano Malavolta
 
Painless Persistence in a Disconnected World
Painless Persistence in a Disconnected WorldPainless Persistence in a Disconnected World
Painless Persistence in a Disconnected World
Christian 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 Unicorns
Richie Rump
 
Web Technologies - forms and actions
Web Technologies -  forms and actionsWeb Technologies -  forms and actions
Web Technologies - forms and actions
Aren Zomorodian
 
Scaling php applications with redis
Scaling php applications with redisScaling php applications with redis
Scaling php applications with redis
jimbojsb
 
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
 
Php summary
Php summaryPhp summary
Php summary
Michelle Darling
 
Bare-knuckle web development
Bare-knuckle web developmentBare-knuckle web development
Bare-knuckle web development
Johannes 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.js
Richard Rodger
 

Similar to 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
 

Recently uploaded

Introduction of Cybersecurity with OSS at Code Europe 2024
Introduction of Cybersecurity with OSS  at Code Europe 2024Introduction of Cybersecurity with OSS  at Code Europe 2024
Introduction of Cybersecurity with OSS at Code Europe 2024
Hiroshi SHIBATA
 
What is an RPA CoE? Session 1 – CoE Vision
What is an RPA CoE?  Session 1 – CoE VisionWhat is an RPA CoE?  Session 1 – CoE Vision
What is an RPA CoE? Session 1 – CoE Vision
DianaGray10
 
"Choosing proper type of scaling", Olena Syrota
"Choosing proper type of scaling", Olena Syrota"Choosing proper type of scaling", Olena Syrota
"Choosing proper type of scaling", Olena Syrota
Fwdays
 
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
Edge AI and Vision Alliance
 
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
saastr
 
5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides
DanBrown980551
 
Leveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and StandardsLeveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and Standards
Neo4j
 
Apps Break Data
Apps Break DataApps Break Data
Apps Break Data
Ivo Velitchkov
 
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
saastr
 
Dandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity serverDandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity server
Antonios Katsarakis
 
Choosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptxChoosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptx
Brandon Minnick, MBA
 
Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024
Jason Packer
 
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge GraphGraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
Neo4j
 
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdfMonitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Tosin Akinosho
 
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
Alex Pruden
 
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success StoryDriving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Safe Software
 
“How Axelera AI Uses Digital Compute-in-memory to Deliver Fast and Energy-eff...
“How Axelera AI Uses Digital Compute-in-memory to Deliver Fast and Energy-eff...“How Axelera AI Uses Digital Compute-in-memory to Deliver Fast and Energy-eff...
“How Axelera AI Uses Digital Compute-in-memory to Deliver Fast and Energy-eff...
Edge AI and Vision Alliance
 
Essentials of Automations: Exploring Attributes & Automation Parameters
Essentials of Automations: Exploring Attributes & Automation ParametersEssentials of Automations: Exploring Attributes & Automation Parameters
Essentials of Automations: Exploring Attributes & Automation Parameters
Safe Software
 
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectorsConnector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
DianaGray10
 
Freshworks Rethinks NoSQL for Rapid Scaling & Cost-Efficiency
Freshworks Rethinks NoSQL for Rapid Scaling & Cost-EfficiencyFreshworks Rethinks NoSQL for Rapid Scaling & Cost-Efficiency
Freshworks Rethinks NoSQL for Rapid Scaling & Cost-Efficiency
ScyllaDB
 

Recently uploaded (20)

Introduction of Cybersecurity with OSS at Code Europe 2024
Introduction of Cybersecurity with OSS  at Code Europe 2024Introduction of Cybersecurity with OSS  at Code Europe 2024
Introduction of Cybersecurity with OSS at Code Europe 2024
 
What is an RPA CoE? Session 1 – CoE Vision
What is an RPA CoE?  Session 1 – CoE VisionWhat is an RPA CoE?  Session 1 – CoE Vision
What is an RPA CoE? Session 1 – CoE Vision
 
"Choosing proper type of scaling", Olena Syrota
"Choosing proper type of scaling", Olena Syrota"Choosing proper type of scaling", Olena Syrota
"Choosing proper type of scaling", Olena Syrota
 
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
 
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
 
5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides
 
Leveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and StandardsLeveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and Standards
 
Apps Break Data
Apps Break DataApps Break Data
Apps Break Data
 
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
 
Dandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity serverDandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity server
 
Choosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptxChoosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptx
 
Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024
 
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge GraphGraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
 
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdfMonitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdf
 
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
 
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success StoryDriving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success Story
 
“How Axelera AI Uses Digital Compute-in-memory to Deliver Fast and Energy-eff...
“How Axelera AI Uses Digital Compute-in-memory to Deliver Fast and Energy-eff...“How Axelera AI Uses Digital Compute-in-memory to Deliver Fast and Energy-eff...
“How Axelera AI Uses Digital Compute-in-memory to Deliver Fast and Energy-eff...
 
Essentials of Automations: Exploring Attributes & Automation Parameters
Essentials of Automations: Exploring Attributes & Automation ParametersEssentials of Automations: Exploring Attributes & Automation Parameters
Essentials of Automations: Exploring Attributes & Automation Parameters
 
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectorsConnector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
 
Freshworks Rethinks NoSQL for Rapid Scaling & Cost-Efficiency
Freshworks Rethinks NoSQL for Rapid Scaling & Cost-EfficiencyFreshworks Rethinks NoSQL for Rapid Scaling & Cost-Efficiency
Freshworks Rethinks NoSQL for Rapid Scaling & Cost-Efficiency
 

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