Simple Web Development in Java

21
Simple Web Development in Java Vincent Tencé @testinfected http://vtence.com http://github.com/testinfected

description

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.

Transcript of Simple Web Development in Java

Page 1: Simple Web Development in Java

Simple Web Development in Java

Vincent Tencé@testinfected

http://vtence.comhttp://github.com/testinfected

Page 2: Simple Web Development in Java

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

Page 3: Simple Web Development in Java
Page 4: Simple Web Development in Java

The Original Version

• Spring with Spring MVC

• Velocity and SiteMesh, UrlRewriteFilter

• Hibernate, JPA, MySQL

• Hibernate Validator

• Maven

• ... 53 jars!

Page 5: Simple Web Development in Java
Page 7: Simple Web Development in Java

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

Page 8: Simple Web Development in Java

The Simple Version

• Simple

• Mustache

• JDBC and MySQL

• CLI

• Buildr

• 4 jars

Page 9: Simple Web Development in Java
Page 10: Simple Web Development in Java

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

Page 11: Simple Web Development in Java

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() {{[...]

}});

Page 12: Simple Web Development in Java

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()));}});

Page 13: Simple Web Development in Java

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)); }}

Page 14: Simple Web Development in Java

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); } [...]}

Page 15: Simple Web Development in Java

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); } [...]}

Page 16: Simple Web Development in Java

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(); } [...]}

Page 17: Simple Web Development in Java

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(); }

[...]}

Page 18: Simple Web Development in Java

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(); }}

Page 19: Simple Web Development in Java

Thoughts

• Not very “enterprisy”

• What are we missing?

• Use a proven solution or develop our own?

• Not a silver bullet

Page 20: Simple Web Development in Java

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

Page 21: Simple Web Development in Java

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