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 t...
The Original Version
• Spring with Spring MVC
• Velocity and SiteMesh, UrlRewriteFilter
• Hibernate, JPA, MySQL
• Hibernat...
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 assembl...
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 'persiste...
Dependency Injection

AttachmentStorage attachments = new FileSystemPhotoStore("/photos");
Connection connection = new Con...
Routing

[...]
Router router = Router.draw(new DynamicRoutes() {{
get("/products").to(new ListProducts(products, attachmen...
MVC

public class ShowOrder implements Application {
private final OrderBook orderBook;
private final Page orderPage;
publ...
Data Access
public class OrdersDatabase implements OrderBook {
[...]
public OrdersDatabase(Connection connection) {
this.c...
Transactions

public class Cashier implements SalesAssistant {
[...]
public OrderNumber placeOrder(PaymentMethod paymentMe...
Validation Constraints
public class CreditCardDetails extends PaymentMethod implements Serializable {
private final Credit...
Validation

public class Validator {
public <T> Set<ConstraintViolation<?>> validate(T target) {
Valid<T> valid = Validate...
Forms
public class PaymentForm extends Form {
public static PaymentForm parse(Request request) {
return new PaymentForm(ne...
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
...
Thanks!
• Simple version :
https://github.com/testinfected/simple-petstore
• Spring version :
https://github.com/testinfec...
Simple Web Development in Java
Simple Web Development in Java
Simple Web Development in Java
Upcoming SlideShare
Loading in …5
×

Simple Web Development in Java

575 views

Published on

The slides of my talk at Confoo 2014 in Montréal, Qc.

Let's get back to simplicity when doing Java web development. Forget about DI frameworks, ORMs and complex build tools and see how we can develop well-tested, well-crafted web applications using only simple tools, libraries and techniques.

In this talk, I will share my experience rewriting a web application based on Spring MVC, Spring, Hibernate and Maven with only Simple and JDBC. We'll discuss the benefits and challenges of simplicity.

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
575
On SlideShare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
6
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Simple Web Development in Java

  1. 1. Simple Web Development in Java Vincent Tencé @testinfected http://vtence.com http://github.com/testinfected
  2. 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. 3. The Original Version • Spring with Spring MVC • Velocity and SiteMesh, UrlRewriteFilter • Hibernate, JPA, MySQL • Hibernate Validator • Maven • ... 53 jars!
  4. 4. http://thepresentationdesigner.co.uk/blog/portfolio-item/bruce-lee-slide-2/
  5. 5. 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
  6. 6. The Simple Version • Simple • Mustache • JDBC and MySQL • CLI • Buildr • 4 jars
  7. 7. 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
  8. 8. 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() {{ [...] }});
  9. 9. 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())); }});
  10. 10. 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)); } }
  11. 11. 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); } [...] }
  12. 12. 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); } [...] }
  13. 13. 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(); } [...] }
  14. 14. 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(); } [...] }
  15. 15. 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(); } }
  16. 16. Thoughts • Not very “enterprisy” • What are we missing? • Use a proven solution or develop our own? • Not a silver bullet
  17. 17. 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
  18. 18. 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

×