Bareknuckle web development Odessa Johannes Brodwall Chief scientist

  • Slides: 51
Download presentation
Bare-knuckle web development Odessa Johannes Brodwall, Chief scientist Exilesoft Global

Bare-knuckle web development Odessa Johannes Brodwall, Chief scientist Exilesoft Global

 • Bare-knuckle philosophy • Demonstration of bareknuckle web in Java • Further directions

• Bare-knuckle philosophy • Demonstration of bareknuckle web in Java • Further directions

Part I:

Part I:

The bare-knuckle philosophy

The bare-knuckle philosophy

 • High impact/low ceremony • Framework light • Test-driven

• High impact/low ceremony • Framework light • Test-driven

High impact with low ceremony

High impact with low ceremony

Java web: Servlets, Web. Driver, Jetty, Mockito

Java web: Servlets, Web. Driver, Jetty, Mockito

Java SOAP: JOOX, Http. URLConnection

Java SOAP: JOOX, Http. URLConnection

. NET web prototype: Web. Driver + Http. Listener

. NET web prototype: Web. Driver + Http. Listener

. NET web work-inprogress: Web. Driver + Http. Self. Host. Server

. NET web work-inprogress: Web. Driver + Http. Self. Host. Server

Light on framework

Light on framework

Frameworks solve 80% of the job…

Frameworks solve 80% of the job…

… and makes the rest 10 times as hard

… and makes the rest 10 times as hard

“Why did Hibernate suddenly slow down? ”

“Why did Hibernate suddenly slow down? ”

“How do I implement a custom SOAP header with JAX-WS? ”

“How do I implement a custom SOAP header with JAX-WS? ”

“How to do X with Spring”

“How to do X with Spring”

@Auto. Wire + package scan with 100 s of beans

@Auto. Wire + package scan with 100 s of beans

Test-driven

Test-driven

No more architecture than what’s needed

No more architecture than what’s needed

Fast feedback cycle – also in the future

Fast feedback cycle – also in the future

Part II:

Part II:

Demo: Phonebook web app

Demo: Phonebook web app

Test driving

Test driving

Web. Driver browser = create. Web. Driver(); browser. get(url); browser. find. Element(By. link. Text("Add

Web. Driver browser = create. Web. Driver(); browser. get(url); browser. find. Element(By. link. Text("Add contact")). click(); browser. find. Eleme(By. name("full. Name")). send. Keys("Vader"); browser. find. Eleme(By. name("phone. Number")). send. Keys("27"); browser. find. Eleme(By. name("save. Contact")). click(); browser. find. Element(By. link. Text("Find contact")). click(); browser. find. Elem(By. name("name. Query")). send. Keys("vader"); browser. find. Element(By. name("name. Query")). submit(); assert. That(browser. find. Elem(By. id("contacts")). get. Text()). contains("555 -33274 -7827");

Server server = new Server(0); server. set. Handler( new Web. App. Context("src/main/webapp", "/contacts")); server.

Server server = new Server(0); server. set. Handler( new Web. App. Context("src/main/webapp", "/contacts")); server. start(); int port = server. get. Connectors()[0]. get. Local. Port(); String url = "http: //localhost: " + port + "/contacts";

<web-app version="2. 5“> <servlet-name>contact. Servlet</servlet-name> <servlet-class> com. exilesoft. bareknuckleweb. Contact. Servlet </servlet-class> </servlet> <servlet-mapping>

<web-app version="2. 5“> <servlet-name>contact. Servlet</servlet-name> <servlet-class> com. exilesoft. bareknuckleweb. Contact. Servlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>contact. Servlet</servlet-name> <url-pattern>contact/*</url-pattern> </servlet-mapping> </web-app>

public class Contact. Servlet extends Http. Servlet { }

public class Contact. Servlet extends Http. Servlet { }

@Test public void should. Show. Add. Form() throws Exception { Contact. Servlet servlet =

@Test public void should. Show. Add. Form() throws Exception { Contact. Servlet servlet = new Contact. Servlet(); Http. Servlet. Request req = mock(Http. Servlet. Request. class); Http. Servlet. Response resp = mock(Http. Servlet. Response. class); String. Writer html = new String. Writer(); when(resp. get. Writer()). then. Return(new Print. Writer(html)); when(req. get. Path. Info()). then. Return("/create. html"); servlet. do. Get(req, resp); verify(resp). set. Content. Type("text/html"); assert. That(html. to. String()). contains("<form method='post'"). contains("<input type='text' name='full. Name'"). contains("<input type='text' name='phone. Number'"). contains("<input type='submit' name='create. Contact'"); }

Refactoring

Refactoring

Part III:

Part III:

Further directorions

Further directorions

Norwegian agricultural authority

Norwegian agricultural authority

Java web application with an MVC architecture

Java web application with an MVC architecture

 • Controllers: • Create a view Retrieve model from repo • Set model

• Controllers: • Create a view Retrieve model from repo • Set model on view • Render view

View example:

View example:

@Override public void render(Http. Servlet. Response resp) throws IOException { Match document = $("html",

@Override public void render(Http. Servlet. Response resp) throws IOException { Match document = $("html", head(), $("img"). attr("src", "/sms-varsel/Sparebank 1. jpg"), $("h 1", "Internet bank simulator"), $("form"). attr("method", "post"). append( hidden. Field(this. bank. Num, "bank. Num"), hidden. Field(this. customer. Id, "customer. Id"), $("h 2", "Set Mobile Phone Number"), phone. Number. Field(this. phone. Number), $("h 2", "Account numbers"), account. Numbers. Field(this. account. Numbers), $("h 2", "Payment account"), payment. Account. Field(this. default. Account), $("h 2", "Save changes"), $("div", $("input"). attr("type", "submit"). attr("value", "Store")). attr("name", "update"))); resp. set. Content. Type("text/html"); resp. set. Character. Encoding("UTF-8"); resp. get. Writer(). write(document. to. String()); }

Match document = $("html", head(), $("img"). attr("src", "/logo. jpg"), $("h 1", “Page name"), $("form").

Match document = $("html", head(), $("img"). attr("src", "/logo. jpg"), $("h 1", “Page name"), $("form"). attr("method", "post"). append( hidden. Field(this. bank. Num, "bank. Num"), hidden. Field(this. customer. Id, "customer. Id"), $("h 2", "Save changes"), $("div", $("input"). attr("type", "submit"). attr("value", "Store")). attr("name", "update")));

Norwegian Power Transmission System Operator

Norwegian Power Transmission System Operator

Universal repository Universal service Commands and Queries One domain model

Universal repository Universal service Commands and Queries One domain model

No Spring – 100 KLOC

No Spring – 100 KLOC

Single-jar deployment • Includes scripts • Includes Jetty

Single-jar deployment • Includes scripts • Includes Jetty

public class Statnett. Web. Server { private final org. eclipse. jetty. server. Server server;

public class Statnett. Web. Server { private final org. eclipse. jetty. server. Server server; public Contact. Web. Server(int port) { server = new Server(port); server. set. Handler(new Web. App. Context(“…", "/statnett")); } void start() throws Exception { server. start(); } String get. Url() { int port = server. get. Connectors()[0]. get. Local. Port(); return "http: //localhost: " + port + "/contacts"; } public static void main(String[] args) throws Exception { Statnett. Web. Server server = new Statnett. Web. Server(10080); server. start(); System. out. println(server. get. Url()); } }

Spare. Bank 1

Spare. Bank 1

10 web service clients

10 web service clients

Http. URLConnection JOOX

Http. URLConnection JOOX

@Override public String get. Country. By. Ip(String ip. Address) throws Exception { Document soap.

@Override public String get. Country. By. Ip(String ip. Address) throws Exception { Document soap. Request = soap. Element("S: Envelope", $("S: Body", wsx. Element("wsx: Get. Geo. IP", $("wsx: IPAddress", ip. Address)))); Document soap. Response endpoint. post. Request(get. SOAPAction(), soap. Request); return $(soap. Response). xpath("/Envelope/Body/*"). xpath("Get. Geo. IPResult/Country. Name"). text(); }

public Document post. Request(String soap. Action, Document soap. Request) { Http. URLConnection conn =

public Document post. Request(String soap. Action, Document soap. Request) { Http. URLConnection conn = (Http. URLConnection) url. open. Connection(); connection. set. Do. Input(true); connection. set. Do. Output(true); connection. add. Request. Property("SOAPAction", soap. Action); connection. add. Request. Property("Content-Type", "text/xml"); $(soap. Request). write(connection. get. Output. Stream()); int response. Code = connection. get. Response. Code(); if (is. Error. Response(response. Code)) { String response = to. String(connection. get. Error. Stream()); String response. Content. Type = connection. get. Content. Type(); if (response. Content. Type. starts. With("text/xml")) { return response; } throw new Service. Communication. Exception( "On POST to " + url + ": " + response. Code + " " + connection. get. Response. Message() + ": " + response); } return $(connection. get. Input. Stream()). document(); d}

Conclusion:

Conclusion:

YAGNI

YAGNI

Test-driven development High investment in tests Low investment in frameworks

Test-driven development High investment in tests Low investment in frameworks

Thank you jbr@exilesoft. com http: //johannesbrodwall. com http: //exilesoft. com http: //twitter. com/jhannes

Thank you [email protected] com http: //johannesbrodwall. com http: //exilesoft. com http: //twitter. com/jhannes