SlideShare uma empresa Scribd logo
1 de 53
Bare-knuckle web
    development
                   XP Days Ukraine
     Johannes Brodwall, Chief scientist
                     Exilesoft Global
• Bare-knuckle
             philosophy
• Demonstration of bare-
     knuckle web in Java
    • Further directions
Part I:
The bare-knuckle
     philosophy
High impact with
   low ceremony
•    Framework light
      • Test-driven
    • No calculators
Light on framework
Frameworks solve 80%
         of the job…
… and makes the rest 10
         times as hard
“Why did Hibernate
suddenly slow down?”
“How do I implement a
 custom SOAP header
      with JAX-WS?”
“How to do X with Spring”
@AutoWire + package scan
      with 100s of beans
Test-driven
No more architecture than
           what’s needed
Fast feedback cycle – also
             in the future
Don’t use a
calculator…
Part II:
Demo: Phonebook
        web app
Test driving
WebDriver browser = createWebDriver();

browser.get(url);
browser.findElement(By.linkText("Add contact")).click();

browser.findEleme(By.name("fullName")).sendKeys("Vader");
browser.findEleme(By.name("phoneNumber")).sendKeys("27");
browser.findEleme(By.name("saveContact")).click();

browser.findElement(By.linkText("Find contact")).click();
browser.findElem(By.name("nameQuery")).sendKeys("vader");
browser.findElement(By.name("nameQuery")).submit();

assertThat(browser.findElem(By.id("contacts")).getText())
    .contains("555-33274-7827");
Server server = new Server(0);
server.setHandler(
     new WebAppContext("src/main/webapp", "/contacts"));
server.start();

int port = server.getConnectors()[0].getLocalPort();
String url = "http://localhost:" + port + "/contacts";
<web-app version="2.5“>

<servlet>
  <servlet-name>contactServlet</servlet-name>
  <servlet-class>
     com.exilesoft.bareknuckleweb.ContactServlet
  </servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>contactServlet</servlet-name>
  <url-pattern>contact/*</url-pattern>
</servlet-mapping>


</web-app>
public class ContactServlet extends HttpServlet {
}
@Test
public void shouldShowAddForm() throws Exception {
    ContactServlet servlet = new ContactServlet();
    HttpServletRequest req = mock(HttpServletRequest.class);
    HttpServletResponse resp = mock(HttpServletResponse.class);
    StringWriter html = new StringWriter();

    when(resp.getWriter()).thenReturn(new PrintWriter(html));
    when(req.getPathInfo()).thenReturn("/create.html");

    servlet.doGet(req, resp);

    verify(resp).setContentType("text/html");
    assertThat(html.toString())
        .contains("<form method='post'")
        .contains("<input type='text' name='fullName'")
        .contains("<input type='text' name='phoneNumber'")
        .contains("<input type='submit' name='createContact'");
}
Refactoring
void showFindPage(String q, PrintWriter writer) {
    Document doc = Xml.read("contact/index.html");
    doc.selectFirst("[name=nameQuery]").val(nameQuery);
    Element contactsEl = doc.select("#contacts");
    Element template = contactsEl.select(".contact");
    contactsEl.clear();
    for (Contact contact : contactRepository.find(q)) {
        contactsEl.add(
            template.copy().text(contact.print()));
    }
    doc.write(writer);
}
.NET
[TestMethod]
public void ShouldFindSavedContacts()
{
    var server = new WebServer();
    server.Start("http://localhost:12380/");

    var url = "http://localhost:12380";
    var browser = new SimpleBrowser.WebDriver.SimpleBrowserDriver();

    browser.Url = url + "/contacts";

    browser.FindElement(By.LinkText("Add contact")).Click();

    browser.FindElement(By.Name("fullName")).SendKeys("Darth Vader");
    browser.FindElement(By.Name("phoneNumber")).SendKeys("555-33274-7827");
    browser.FindElement(By.Name("saveContact")).Click();

    browser.FindElement(By.LinkText("Find contact")).Click();
    browser.FindElement(By.Name("nameQuery")).SendKeys("vader");
    browser.FindElement(By.Name("nameQuery")).Submit();

    browser.FindElement(By.Id("contacts")).Text.Should()
       .Contain("555-33274-7827");
}
public class WebServer
{
    public void Start(string baseAddress)
    {
        var config =
           new HttpSelfHostConfiguration(baseAddress);
        config.Routes.MapHttpRoute(
               "web Default",
                "{controller}/{id}",
                new { id = RouteParameter.Optional });

        using (var server = new HttpSelfHostServer(config))
        {
            server.OpenAsync().Wait();
            Console.WriteLine("Press Enter to quit.");
            Console.ReadLine();
        }
    }
}
Part III:
Further directions
Norwegian
agricultural
  authority
Java web application with
     an MVC architecture
Controllers:
             • Create a view
•   Retrieve model from repo
        • Set model on view
              • Render view
View example:
@Override
public void render(HttpServletResponse resp) throws IOException {
    Match document = $("html",
            head(),
            $("img").attr("src", "/sms-varsel/Sparebank1.jpg"),
            $("h1", "Internet bank simulator"),
            $("form").attr("method", "post").append(
                    hiddenField(this.bankNum, "bankNum"),
                    hiddenField(this.customerId, "customerId"),
                    $("h2", "Set Mobile Phone Number"),
                    phoneNumberField(this.phoneNumber),
                    $("h2", "Account numbers"),
                    accountNumbersField(this.accountNumbers),
                    $("h2", "Payment account"),
                    paymentAccountField(this.defaultAccount),
                    $("h2", "Save changes"),
                    $("div",

$("input").attr("type", "submit").attr("value", "Store")).attr("nam
e", "update")));
    resp.setContentType("text/html");
    resp.setCharacterEncoding("UTF-8");
    resp.getWriter().write(document.toString());
}
Match document = $("html",
      head(),
      $("img").attr("src", "/logo.jpg"),
      $("h1", “Page name"),
      $("form").attr("method", "post").append(
          hiddenField(this.bankNum, "bankNum"),
          hiddenField(this.customerId, "customerId"),
          $("h2", "Save changes"),
          $("div",
              $("input").attr("type", "submit")
                        .attr("value", "Store"))
                        .attr("name", "update")));
Norwegian Power
   Transmission
System Operator
Universal repository
     Universal service
Commands and Queries
    One domain model
No Spring – 100 KLOC
Single-jar deployment
   • Includes scripts
     • Includes Jetty
public class StatnettWebServer {
    private final org.eclipse.jetty.server.Server server;
    public ContactWebServer(int port) {
        server = new Server(port);
        server.setHandler(new WebAppContext(“…", "/statnett"));
    }

    void start() throws Exception {
        server.start();
    }

    String getUrl() {
        int port = server.getConnectors()[0].getLocalPort();
        return "http://localhost:" + port + "/contacts";
    }

    public static void main(String[] args) throws Exception {
        StatnettWebServer server = new StatnettWebServer(10080);
        server.start();
        System.out.println(server.getUrl());
    }
}
SpareBank1
10 web service
        clients
HttpURLConnection
           JOOX
@Override
public String getCountryByIp(String ipAddress) throws
Exception {
    Document soapRequest =
        soapElement("S:Envelope",
            $("S:Body",
                wsxElement("wsx:GetGeoIP",
                    $("wsx:IPAddress", ipAddress))));
    Document soapResponse
       endpoint.postRequest(getSOAPAction(), soapRequest);
    return $(soapResponse).xpath("/Envelope/Body/*")
              .xpath("GetGeoIPResult/CountryName").text();
}
public Document postRequest(String soapAction, Document soapRequest) {
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    connection.setDoInput(true);
    connection.setDoOutput(true);
    connection.addRequestProperty("SOAPAction", soapAction);
    connection.addRequestProperty("Content-Type", "text/xml");
    $(soapRequest).write(connection.getOutputStream());

     int responseCode = connection.getResponseCode();
     if (isErrorResponse(responseCode)) {
         String response = toString(connection.getErrorStream());
         String responseContentType = connection.getContentType();
         if (responseContentType.startsWith("text/xml")) {
             return response;
         }
         throw new ServiceCommunicationException(
                 "On POST to " + url + ": " + responseCode + " "
                 + connection.getResponseMessage() + ": " + response);
     }
     return $(connection.getInputStream()).document();
d}
Conclusion:
YAGNI
No calculator
      until…
Don’t use a framework
    you couldn’t have
       written yourself
Thank you
           jbr@exilesoft.com

 http://johannesbrodwall.com
           http://exilesoft.com

    http://twitter.com/jhannes

Mais conteúdo relacionado

Mais procurados

Remy Sharp The DOM scripting toolkit jQuery
Remy Sharp The DOM scripting toolkit jQueryRemy Sharp The DOM scripting toolkit jQuery
Remy Sharp The DOM scripting toolkit jQuerydeimos
 
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
 
HTML5 & The Open Web - at Nackademin
HTML5 & The Open Web -  at NackademinHTML5 & The Open Web -  at Nackademin
HTML5 & The Open Web - at NackademinRobert Nyman
 
Desenvolvimento web com Ruby on Rails (extras)
Desenvolvimento web com Ruby on Rails (extras)Desenvolvimento web com Ruby on Rails (extras)
Desenvolvimento web com Ruby on Rails (extras)Joao Lucas Santana
 
Mad Max is back, plus the rest of our new reviews and notable screenings
Mad Max is back, plus the rest of our new reviews and notable screeningsMad Max is back, plus the rest of our new reviews and notable screenings
Mad Max is back, plus the rest of our new reviews and notable screeningschicagonewsonlineradio
 
Remote code-with-expression-language-injection
Remote code-with-expression-language-injectionRemote code-with-expression-language-injection
Remote code-with-expression-language-injectionMickey Jack
 
Joe Walker Interactivewebsites Cometand Dwr
Joe Walker Interactivewebsites Cometand DwrJoe Walker Interactivewebsites Cometand Dwr
Joe Walker Interactivewebsites Cometand Dwrdeimos
 
GWT integration with Vaadin
GWT integration with VaadinGWT integration with Vaadin
GWT integration with VaadinPeter Lehto
 
Windows 8 metro applications
Windows 8 metro applicationsWindows 8 metro applications
Windows 8 metro applicationsAlex Golesh
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Domenic Denicola
 
"Auth for React.js APP", Nikita Galkin
"Auth for React.js APP", Nikita Galkin"Auth for React.js APP", Nikita Galkin
"Auth for React.js APP", Nikita GalkinFwdays
 
Web Crawling with NodeJS
Web Crawling with NodeJSWeb Crawling with NodeJS
Web Crawling with NodeJSSylvain Zimmer
 
EmberConf 2015 – Ambitious UX for Ambitious Apps
EmberConf 2015 – Ambitious UX for Ambitious AppsEmberConf 2015 – Ambitious UX for Ambitious Apps
EmberConf 2015 – Ambitious UX for Ambitious AppsLauren Elizabeth Tan
 
Open Source Ajax Solution @OSDC.tw 2009
Open Source Ajax  Solution @OSDC.tw 2009Open Source Ajax  Solution @OSDC.tw 2009
Open Source Ajax Solution @OSDC.tw 2009Robbie Cheng
 
The rise and fall of a techno DJ, plus more new reviews and notable screenings
The rise and fall of a techno DJ, plus more new reviews and notable screeningsThe rise and fall of a techno DJ, plus more new reviews and notable screenings
The rise and fall of a techno DJ, plus more new reviews and notable screeningschicagonewsyesterday
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDDeveloping application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDMichele Capra
 

Mais procurados (20)

Remy Sharp The DOM scripting toolkit jQuery
Remy Sharp The DOM scripting toolkit jQueryRemy Sharp The DOM scripting toolkit jQuery
Remy Sharp The DOM scripting toolkit jQuery
 
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 ...
 
HTML5 & The Open Web - at Nackademin
HTML5 & The Open Web -  at NackademinHTML5 & The Open Web -  at Nackademin
HTML5 & The Open Web - at Nackademin
 
JavaScript JQUERY AJAX
JavaScript JQUERY AJAXJavaScript JQUERY AJAX
JavaScript JQUERY AJAX
 
Desenvolvimento web com Ruby on Rails (extras)
Desenvolvimento web com Ruby on Rails (extras)Desenvolvimento web com Ruby on Rails (extras)
Desenvolvimento web com Ruby on Rails (extras)
 
Mad Max is back, plus the rest of our new reviews and notable screenings
Mad Max is back, plus the rest of our new reviews and notable screeningsMad Max is back, plus the rest of our new reviews and notable screenings
Mad Max is back, plus the rest of our new reviews and notable screenings
 
Remote code-with-expression-language-injection
Remote code-with-expression-language-injectionRemote code-with-expression-language-injection
Remote code-with-expression-language-injection
 
Joe Walker Interactivewebsites Cometand Dwr
Joe Walker Interactivewebsites Cometand DwrJoe Walker Interactivewebsites Cometand Dwr
Joe Walker Interactivewebsites Cometand Dwr
 
GWT integration with Vaadin
GWT integration with VaadinGWT integration with Vaadin
GWT integration with Vaadin
 
Windows 8 metro applications
Windows 8 metro applicationsWindows 8 metro applications
Windows 8 metro applications
 
jQuery Presentasion
jQuery PresentasionjQuery Presentasion
jQuery Presentasion
 
Vaadin7
Vaadin7Vaadin7
Vaadin7
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
 
"Auth for React.js APP", Nikita Galkin
"Auth for React.js APP", Nikita Galkin"Auth for React.js APP", Nikita Galkin
"Auth for React.js APP", Nikita Galkin
 
Protractor Training in Pune by QuickITDotnet
Protractor Training in Pune by QuickITDotnet Protractor Training in Pune by QuickITDotnet
Protractor Training in Pune by QuickITDotnet
 
Web Crawling with NodeJS
Web Crawling with NodeJSWeb Crawling with NodeJS
Web Crawling with NodeJS
 
EmberConf 2015 – Ambitious UX for Ambitious Apps
EmberConf 2015 – Ambitious UX for Ambitious AppsEmberConf 2015 – Ambitious UX for Ambitious Apps
EmberConf 2015 – Ambitious UX for Ambitious Apps
 
Open Source Ajax Solution @OSDC.tw 2009
Open Source Ajax  Solution @OSDC.tw 2009Open Source Ajax  Solution @OSDC.tw 2009
Open Source Ajax Solution @OSDC.tw 2009
 
The rise and fall of a techno DJ, plus more new reviews and notable screenings
The rise and fall of a techno DJ, plus more new reviews and notable screeningsThe rise and fall of a techno DJ, plus more new reviews and notable screenings
The rise and fall of a techno DJ, plus more new reviews and notable screenings
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDDeveloping application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDD
 

Destaque

Manufacturing process & material selection for knuckle joint
Manufacturing process   & material selection for knuckle jointManufacturing process   & material selection for knuckle joint
Manufacturing process & material selection for knuckle jointmohan jetthy
 
Design, Analysis and fabrication of ATV (All Terrain Vehicle) for the event B...
Design, Analysis and fabrication of ATV (All Terrain Vehicle) for the event B...Design, Analysis and fabrication of ATV (All Terrain Vehicle) for the event B...
Design, Analysis and fabrication of ATV (All Terrain Vehicle) for the event B...vinay kumar
 
Design of half shaft and wheel hub assembly for racing car
Design of half shaft and wheel hub assembly for racing carDesign of half shaft and wheel hub assembly for racing car
Design of half shaft and wheel hub assembly for racing carRavi Shekhar
 

Destaque (8)

Solid code via tdd
Solid code via tddSolid code via tdd
Solid code via tdd
 
Manufacturing process & material selection for knuckle joint
Manufacturing process   & material selection for knuckle jointManufacturing process   & material selection for knuckle joint
Manufacturing process & material selection for knuckle joint
 
Modeling and fem analysis of knuckle joint
Modeling and fem analysis of knuckle jointModeling and fem analysis of knuckle joint
Modeling and fem analysis of knuckle joint
 
Suspension system
Suspension systemSuspension system
Suspension system
 
Design, Analysis and fabrication of ATV (All Terrain Vehicle) for the event B...
Design, Analysis and fabrication of ATV (All Terrain Vehicle) for the event B...Design, Analysis and fabrication of ATV (All Terrain Vehicle) for the event B...
Design, Analysis and fabrication of ATV (All Terrain Vehicle) for the event B...
 
How To Build A Baja Atv
How To Build A Baja AtvHow To Build A Baja Atv
How To Build A Baja Atv
 
Cotter and knuckle joints
Cotter and knuckle jointsCotter and knuckle joints
Cotter and knuckle joints
 
Design of half shaft and wheel hub assembly for racing car
Design of half shaft and wheel hub assembly for racing carDesign of half shaft and wheel hub assembly for racing car
Design of half shaft and wheel hub assembly for racing car
 

Semelhante a Bare-knuckle web development

async/await in Swift
async/await in Swiftasync/await in Swift
async/await in SwiftPeter Friese
 
Angular Tutorial Freshers and Experienced
Angular Tutorial Freshers and ExperiencedAngular Tutorial Freshers and Experienced
Angular Tutorial Freshers and Experiencedrajkamaltibacademy
 
Ajax for dummies, and not only.
Ajax for dummies, and not only.Ajax for dummies, and not only.
Ajax for dummies, and not only.Nerd Tzanetopoulos
 
Javascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & TricksJavascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & TricksHjörtur Hilmarsson
 
Html5 and web technology update
Html5 and web technology updateHtml5 and web technology update
Html5 and web technology updateDoug Domeny
 
May 2010 - RestEasy
May 2010 - RestEasyMay 2010 - RestEasy
May 2010 - RestEasyJBug Italy
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on AndroidSven Haiges
 
Micro app-framework - NodeLive Boston
Micro app-framework - NodeLive BostonMicro app-framework - NodeLive Boston
Micro app-framework - NodeLive BostonMichael Dawson
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejsNick Lee
 
HTML5 - The 2012 of the Web - Adobe MAX
HTML5 - The 2012 of the Web - Adobe MAXHTML5 - The 2012 of the Web - Adobe MAX
HTML5 - The 2012 of the Web - Adobe MAXRobert Nyman
 
Paris js extensions
Paris js extensionsParis js extensions
Paris js extensionserwanl
 
OSCON 2011 CouchApps
OSCON 2011 CouchAppsOSCON 2011 CouchApps
OSCON 2011 CouchAppsBradley Holt
 

Semelhante a Bare-knuckle web development (20)

servlets
servletsservlets
servlets
 
Html5 For Jjugccc2009fall
Html5 For Jjugccc2009fallHtml5 For Jjugccc2009fall
Html5 For Jjugccc2009fall
 
XQuery Rocks
XQuery RocksXQuery Rocks
XQuery Rocks
 
async/await in Swift
async/await in Swiftasync/await in Swift
async/await in Swift
 
Angular Tutorial Freshers and Experienced
Angular Tutorial Freshers and ExperiencedAngular Tutorial Freshers and Experienced
Angular Tutorial Freshers and Experienced
 
Os Pruett
Os PruettOs Pruett
Os Pruett
 
Ajax for dummies, and not only.
Ajax for dummies, and not only.Ajax for dummies, and not only.
Ajax for dummies, and not only.
 
Javascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & TricksJavascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & Tricks
 
jQuery
jQueryjQuery
jQuery
 
Html5 and web technology update
Html5 and web technology updateHtml5 and web technology update
Html5 and web technology update
 
RESTEasy
RESTEasyRESTEasy
RESTEasy
 
Android dev 3
Android dev 3Android dev 3
Android dev 3
 
May 2010 - RestEasy
May 2010 - RestEasyMay 2010 - RestEasy
May 2010 - RestEasy
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
 
Micro app-framework - NodeLive Boston
Micro app-framework - NodeLive BostonMicro app-framework - NodeLive Boston
Micro app-framework - NodeLive Boston
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejs
 
HTML5 - The 2012 of the Web - Adobe MAX
HTML5 - The 2012 of the Web - Adobe MAXHTML5 - The 2012 of the Web - Adobe MAX
HTML5 - The 2012 of the Web - Adobe MAX
 
Paris js extensions
Paris js extensionsParis js extensions
Paris js extensions
 
OSCON 2011 CouchApps
OSCON 2011 CouchAppsOSCON 2011 CouchApps
OSCON 2011 CouchApps
 

Mais de Johannes Brodwall

Build Your Stuff with Privacy by Design
Build Your Stuff with Privacy by DesignBuild Your Stuff with Privacy by Design
Build Your Stuff with Privacy by DesignJohannes Brodwall
 
Remote Pair Programming (Agile India)
Remote Pair Programming (Agile India)Remote Pair Programming (Agile India)
Remote Pair Programming (Agile India)Johannes Brodwall
 
Getting your project off the ground (BuildStuffLt)
Getting your project off the ground (BuildStuffLt)Getting your project off the ground (BuildStuffLt)
Getting your project off the ground (BuildStuffLt)Johannes Brodwall
 
Remote pair programming (BuildStuffLt)
Remote pair programming (BuildStuffLt)Remote pair programming (BuildStuffLt)
Remote pair programming (BuildStuffLt)Johannes Brodwall
 
DevDay.lk - Bare Knuckle Web Development
DevDay.lk - Bare Knuckle Web DevelopmentDevDay.lk - Bare Knuckle Web Development
DevDay.lk - Bare Knuckle Web DevelopmentJohannes Brodwall
 
Extreme Programming Live - JavaZone
Extreme Programming Live - JavaZoneExtreme Programming Live - JavaZone
Extreme Programming Live - JavaZoneJohannes Brodwall
 
2013 09-11 java zone - extreme programming live
2013 09-11 java zone - extreme programming live2013 09-11 java zone - extreme programming live
2013 09-11 java zone - extreme programming liveJohannes Brodwall
 
2013 08-07 agile 2013 - remote pair programming
2013 08-07 agile 2013 - remote pair programming2013 08-07 agile 2013 - remote pair programming
2013 08-07 agile 2013 - remote pair programmingJohannes Brodwall
 
WeActuallyBuildStuff - Extreme Programming Live
WeActuallyBuildStuff - Extreme Programming LiveWeActuallyBuildStuff - Extreme Programming Live
WeActuallyBuildStuff - Extreme Programming LiveJohannes Brodwall
 
Bare-Bones Software Architecture
Bare-Bones Software ArchitectureBare-Bones Software Architecture
Bare-Bones Software ArchitectureJohannes Brodwall
 
Agile Architecture in Odessa
Agile Architecture in OdessaAgile Architecture in Odessa
Agile Architecture in OdessaJohannes Brodwall
 
Agile Programming Live - AgilePrague2012
Agile Programming Live - AgilePrague2012Agile Programming Live - AgilePrague2012
Agile Programming Live - AgilePrague2012Johannes Brodwall
 
Agile Contracts - AgilePrague2012
Agile Contracts - AgilePrague2012Agile Contracts - AgilePrague2012
Agile Contracts - AgilePrague2012Johannes Brodwall
 
Experience Agile Programming
Experience Agile ProgrammingExperience Agile Programming
Experience Agile ProgrammingJohannes Brodwall
 

Mais de Johannes Brodwall (20)

Build Your Stuff with Privacy by Design
Build Your Stuff with Privacy by DesignBuild Your Stuff with Privacy by Design
Build Your Stuff with Privacy by Design
 
The new new mobile web
The new new mobile webThe new new mobile web
The new new mobile web
 
Remote Pair Programming (Agile India)
Remote Pair Programming (Agile India)Remote Pair Programming (Agile India)
Remote Pair Programming (Agile India)
 
Getting your project off the ground (BuildStuffLt)
Getting your project off the ground (BuildStuffLt)Getting your project off the ground (BuildStuffLt)
Getting your project off the ground (BuildStuffLt)
 
Remote pair programming (BuildStuffLt)
Remote pair programming (BuildStuffLt)Remote pair programming (BuildStuffLt)
Remote pair programming (BuildStuffLt)
 
DevDay.lk - Bare Knuckle Web Development
DevDay.lk - Bare Knuckle Web DevelopmentDevDay.lk - Bare Knuckle Web Development
DevDay.lk - Bare Knuckle Web Development
 
Extreme Programming Live - JavaZone
Extreme Programming Live - JavaZoneExtreme Programming Live - JavaZone
Extreme Programming Live - JavaZone
 
2013 09-11 java zone - extreme programming live
2013 09-11 java zone - extreme programming live2013 09-11 java zone - extreme programming live
2013 09-11 java zone - extreme programming live
 
2013 08-07 agile 2013 - remote pair programming
2013 08-07 agile 2013 - remote pair programming2013 08-07 agile 2013 - remote pair programming
2013 08-07 agile 2013 - remote pair programming
 
WeActuallyBuildStuff - Extreme Programming Live
WeActuallyBuildStuff - Extreme Programming LiveWeActuallyBuildStuff - Extreme Programming Live
WeActuallyBuildStuff - Extreme Programming Live
 
Bare-Bones Software Architecture
Bare-Bones Software ArchitectureBare-Bones Software Architecture
Bare-Bones Software Architecture
 
Agile Architecture in Odessa
Agile Architecture in OdessaAgile Architecture in Odessa
Agile Architecture in Odessa
 
Agile Architecture
Agile ArchitectureAgile Architecture
Agile Architecture
 
Agile Prague Coding Dojo
Agile Prague Coding DojoAgile Prague Coding Dojo
Agile Prague Coding Dojo
 
Agile Programming Live - AgilePrague2012
Agile Programming Live - AgilePrague2012Agile Programming Live - AgilePrague2012
Agile Programming Live - AgilePrague2012
 
Agile Contracts - AgilePrague2012
Agile Contracts - AgilePrague2012Agile Contracts - AgilePrague2012
Agile Contracts - AgilePrague2012
 
Smidig Stykkpriskontrakt
Smidig StykkpriskontraktSmidig Stykkpriskontrakt
Smidig Stykkpriskontrakt
 
Experience Agile Programming
Experience Agile ProgrammingExperience Agile Programming
Experience Agile Programming
 
Agile Contracts
Agile ContractsAgile Contracts
Agile Contracts
 
Smidig ansvarsprosjekt
Smidig ansvarsprosjektSmidig ansvarsprosjekt
Smidig ansvarsprosjekt
 

Bare-knuckle web development

  • 1. Bare-knuckle web development XP Days Ukraine Johannes Brodwall, Chief scientist Exilesoft Global
  • 2. • Bare-knuckle philosophy • Demonstration of bare- knuckle web in Java • Further directions
  • 4. The bare-knuckle philosophy
  • 5. High impact with low ceremony
  • 6. Framework light • Test-driven • No calculators
  • 8. Frameworks solve 80% of the job…
  • 9. … and makes the rest 10 times as hard
  • 11. “How do I implement a custom SOAP header with JAX-WS?”
  • 12. “How to do X with Spring”
  • 13. @AutoWire + package scan with 100s of beans
  • 15. No more architecture than what’s needed
  • 16. Fast feedback cycle – also in the future
  • 19. Demo: Phonebook web app
  • 21. WebDriver browser = createWebDriver(); browser.get(url); browser.findElement(By.linkText("Add contact")).click(); browser.findEleme(By.name("fullName")).sendKeys("Vader"); browser.findEleme(By.name("phoneNumber")).sendKeys("27"); browser.findEleme(By.name("saveContact")).click(); browser.findElement(By.linkText("Find contact")).click(); browser.findElem(By.name("nameQuery")).sendKeys("vader"); browser.findElement(By.name("nameQuery")).submit(); assertThat(browser.findElem(By.id("contacts")).getText()) .contains("555-33274-7827");
  • 22. Server server = new Server(0); server.setHandler( new WebAppContext("src/main/webapp", "/contacts")); server.start(); int port = server.getConnectors()[0].getLocalPort(); String url = "http://localhost:" + port + "/contacts";
  • 23. <web-app version="2.5“> <servlet> <servlet-name>contactServlet</servlet-name> <servlet-class> com.exilesoft.bareknuckleweb.ContactServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>contactServlet</servlet-name> <url-pattern>contact/*</url-pattern> </servlet-mapping> </web-app>
  • 24. public class ContactServlet extends HttpServlet { }
  • 25. @Test public void shouldShowAddForm() throws Exception { ContactServlet servlet = new ContactServlet(); HttpServletRequest req = mock(HttpServletRequest.class); HttpServletResponse resp = mock(HttpServletResponse.class); StringWriter html = new StringWriter(); when(resp.getWriter()).thenReturn(new PrintWriter(html)); when(req.getPathInfo()).thenReturn("/create.html"); servlet.doGet(req, resp); verify(resp).setContentType("text/html"); assertThat(html.toString()) .contains("<form method='post'") .contains("<input type='text' name='fullName'") .contains("<input type='text' name='phoneNumber'") .contains("<input type='submit' name='createContact'"); }
  • 27. void showFindPage(String q, PrintWriter writer) { Document doc = Xml.read("contact/index.html"); doc.selectFirst("[name=nameQuery]").val(nameQuery); Element contactsEl = doc.select("#contacts"); Element template = contactsEl.select(".contact"); contactsEl.clear(); for (Contact contact : contactRepository.find(q)) { contactsEl.add( template.copy().text(contact.print())); } doc.write(writer); }
  • 28. .NET
  • 29. [TestMethod] public void ShouldFindSavedContacts() { var server = new WebServer(); server.Start("http://localhost:12380/"); var url = "http://localhost:12380"; var browser = new SimpleBrowser.WebDriver.SimpleBrowserDriver(); browser.Url = url + "/contacts"; browser.FindElement(By.LinkText("Add contact")).Click(); browser.FindElement(By.Name("fullName")).SendKeys("Darth Vader"); browser.FindElement(By.Name("phoneNumber")).SendKeys("555-33274-7827"); browser.FindElement(By.Name("saveContact")).Click(); browser.FindElement(By.LinkText("Find contact")).Click(); browser.FindElement(By.Name("nameQuery")).SendKeys("vader"); browser.FindElement(By.Name("nameQuery")).Submit(); browser.FindElement(By.Id("contacts")).Text.Should() .Contain("555-33274-7827"); }
  • 30. public class WebServer { public void Start(string baseAddress) { var config = new HttpSelfHostConfiguration(baseAddress); config.Routes.MapHttpRoute( "web Default", "{controller}/{id}", new { id = RouteParameter.Optional }); using (var server = new HttpSelfHostServer(config)) { server.OpenAsync().Wait(); Console.WriteLine("Press Enter to quit."); Console.ReadLine(); } } }
  • 34. Java web application with an MVC architecture
  • 35. Controllers: • Create a view • Retrieve model from repo • Set model on view • Render view
  • 37. @Override public void render(HttpServletResponse resp) throws IOException { Match document = $("html", head(), $("img").attr("src", "/sms-varsel/Sparebank1.jpg"), $("h1", "Internet bank simulator"), $("form").attr("method", "post").append( hiddenField(this.bankNum, "bankNum"), hiddenField(this.customerId, "customerId"), $("h2", "Set Mobile Phone Number"), phoneNumberField(this.phoneNumber), $("h2", "Account numbers"), accountNumbersField(this.accountNumbers), $("h2", "Payment account"), paymentAccountField(this.defaultAccount), $("h2", "Save changes"), $("div", $("input").attr("type", "submit").attr("value", "Store")).attr("nam e", "update"))); resp.setContentType("text/html"); resp.setCharacterEncoding("UTF-8"); resp.getWriter().write(document.toString()); }
  • 38. Match document = $("html", head(), $("img").attr("src", "/logo.jpg"), $("h1", “Page name"), $("form").attr("method", "post").append( hiddenField(this.bankNum, "bankNum"), hiddenField(this.customerId, "customerId"), $("h2", "Save changes"), $("div", $("input").attr("type", "submit") .attr("value", "Store")) .attr("name", "update")));
  • 39. Norwegian Power Transmission System Operator
  • 40. Universal repository Universal service Commands and Queries One domain model
  • 41. No Spring – 100 KLOC
  • 42. Single-jar deployment • Includes scripts • Includes Jetty
  • 43. public class StatnettWebServer { private final org.eclipse.jetty.server.Server server; public ContactWebServer(int port) { server = new Server(port); server.setHandler(new WebAppContext(“…", "/statnett")); } void start() throws Exception { server.start(); } String getUrl() { int port = server.getConnectors()[0].getLocalPort(); return "http://localhost:" + port + "/contacts"; } public static void main(String[] args) throws Exception { StatnettWebServer server = new StatnettWebServer(10080); server.start(); System.out.println(server.getUrl()); } }
  • 45. 10 web service clients
  • 47. @Override public String getCountryByIp(String ipAddress) throws Exception { Document soapRequest = soapElement("S:Envelope", $("S:Body", wsxElement("wsx:GetGeoIP", $("wsx:IPAddress", ipAddress)))); Document soapResponse endpoint.postRequest(getSOAPAction(), soapRequest); return $(soapResponse).xpath("/Envelope/Body/*") .xpath("GetGeoIPResult/CountryName").text(); }
  • 48. public Document postRequest(String soapAction, Document soapRequest) { HttpURLConnection conn = (HttpURLConnection) url.openConnection(); connection.setDoInput(true); connection.setDoOutput(true); connection.addRequestProperty("SOAPAction", soapAction); connection.addRequestProperty("Content-Type", "text/xml"); $(soapRequest).write(connection.getOutputStream()); int responseCode = connection.getResponseCode(); if (isErrorResponse(responseCode)) { String response = toString(connection.getErrorStream()); String responseContentType = connection.getContentType(); if (responseContentType.startsWith("text/xml")) { return response; } throw new ServiceCommunicationException( "On POST to " + url + ": " + responseCode + " " + connection.getResponseMessage() + ": " + response); } return $(connection.getInputStream()).document(); d}
  • 50. YAGNI
  • 51. No calculator until…
  • 52. Don’t use a framework you couldn’t have written yourself
  • 53. Thank you jbr@exilesoft.com http://johannesbrodwall.com http://exilesoft.com http://twitter.com/jhannes