/ DEVOXX

Devoxx 2012 – Day 2

-- after a few hours of sleep and a fresh mind to boot, I’m ready to start the day with some Scala. Inside, I’m wondering how much time I’ll be able to keep on understanding the talk --

Scala advanced concepts by Dick Wall and Bill Venners

Implicit are the first subject tackled. First, know that implicit is one of the reasons that the Scala compiler has such a hard time doing its job. In order to illustrate implicit, a Swing anonymous class snippet code is shown:

val button = new JButton
button.addActionListener(new ActionListener {
	def actionPerformed(event: ActionEvent) {
		println("pressed")
	}
})
button.addActionListener(_:ActionEvent) => println("pressed") // Compile time error with type mismatch

The implicit keyword is a way for the Scala compiler to try conversions from one type to another type until it compiles. The only thing that matters is the type signature, the name doesn’t. Since implicit functions are so powerful (thus dangerous), in Scala 2.10, you have to explicitly import language.implicitConversions. Moreover, other such features (e.g. macros) have to be imported in order to be used. If not imported, compiler issues warnings, but in future versions, it will be handled as errors.

Rules for using implicit are the following:

  • Marking rule: only defs marked as implicit are available
  • Scope rule: an implicit conversion must be in scope as a single identifier (or be associated with either the source or target type of the conversion). This is something akin to inviting the implicit conversion. If the implicit is in the companion object, it will be automatically used. Another more rational alternative would be to put it in a trait, which may be in scope, or not.
  • One at a time rule: only a single implicit conversion must satisfy the compiler.
  • Explicit-first rule: if the code compiles without implicit, implicits won’t be used.
  • Finally, if Scala has more that one implicit conversion available, the compiler will choose the more specific one if it can. If it cannot, it will choose none and just throw an error.

Even though the compiler doesn’t care about the implicit def’s name, people reading your code do so that naming should be chosen for both explicit usage of the conversion and explicit importing into scope for the conversion. Note that some already available implicits are in the Predef object.

In Scala 2.10, implicit can set on classes, so that implicit are even safer. As a corollary, you don’t have to import the feature. Such classes must take exactly one parameter and must be defined where a method could be defined (so they cannot be top-level). Note that the generated method will have the same name as the class.

Implicit parameters can be used in curried defs and replace the last parameter.

def curried(a: Int)(implicit b: Int) = a + b
implicit val evilOne: Int = 1
curried(1)(2) // Returns 3 as expected
curried(1) // Returns 2 because evilOne is implicit and used in the def

Implicit parametes are best used as one of your own type you control: don’t use Int or String as implicit parameters. It also lets you set meaningful names on the types (such as Ordered in the Scala API).

By the way, in order to ease the use of you API, you can specify the @ImplicitNotFound annotation to provide a specific error message to the compiler. Also, when an implicit isn’t applied, the compiler doesn’t offer much debugging information. In this case, a good trick is to start explicitly using the parameter and see what happens. In conclusion, use implicits with care: ask yourself if there’s no other way (such as inheritance or trait).

Scala 2.10 also offers some way into duck typing through the applyDynamics(s:String) (which is also a feature that has to be imported in order to use). It looks much like reflection, but let compiler checks pass-through and fails at runtime instead at compile time (if the desired method is not present).

Now is time for some good Scala coding practices.

  • First, favor immutability: in particular, if you absolutely need to use a var, use the minimum scope possible. Also, mutable collections are particularly evil. If you need to use mutability in this context, it’s most important you do not expose it outside your method (in the signature).
  • For collections, consider map and flatMap above foreach: this tend to make you think in functional programming.
  • Then, don’t chain more than a few map/filter/…​ calls in order to make your code more readable. Instead, declare intermediate variables with meaningful names.
  • Prefer partial functions to bust out tuples:
    wl.zipWithIndex.map { case(w, i) => w.toList(i) } // better than
    wl.zipWithIndex.map { t => t._1.toList(t._2) } // not a good thing
  • Consider `Either`as alternative to exceptions since exceptions disturb the flow of your code.
  • The more if and `for`you can eliminate from your code, the least you’ll have to take all cases in account. Thus, it’s better to favoir tail recursion and immutables over loops and mutables.
  • Have a look at Vector over List. The former is constant-time performance…​
  • *Know your collections!*-- already began! --
  • When developing `public`methods, always provide a return type. Not only it let you avoid runtime errors (it compiles because of type inference), it also nicely documents your code and makes it more readable.
  • Deeply think about case classes: you get already-defined methods (toString(), apply(), unapply(), etc.) for free.

-- here my battery goes down--

Faster Websites: Crash Course on Frontend Performance by Iliya Grigorik

-- Even though backend performance matters, I do tend to think, like the speaker, that in most "traditional" webapps, most of the time is spent on the frontend. I hope to increase my palette of tools available in case it happens --

The speaker is part of the Web Fast team inside of Google. The agenda is separated into three main parts: the problem, browser architecture and best practices, with context.

The problems

What’s the point of making fast websites? Google and Bing tried to measure the impact of delays, by injecting artificial delays at various points during the response. All metrics, including Revenue per User go down, and the more the delay, the sharper the decrease in a linear fashion. As a sidenote, once the delay is removed, metrics take time to go back to their original value. Another company did correlate the page load speed and the bounce rate. Mobile web is putting even more pressure on the load of the sites…​

If you want to succeed with web-performance, don’t view it as a technical metric. Instead, measure and correlate its impact with business metrics

 Delay User reaction

0-100ms

Instant

100-300ms

Feels sluggush

300-1000ms

Machine is working

+1s

Mental context switch

+10s

I’ll come back later

Google Page Analytics show that on the desktop web, the median page load time is roughly 3ms while the mobile web, it’s 5ms (only taking in account those new Google phones). The problem is that an average page is made of 84 requests of is and weights about 1MB!

Let’s have a look at the life a HTTP request: DNS lookup, socket connect, request management itself and finally content download. Each phase in the lifecycle can be optimized.

  • For example, most DNS servers are pretty bad. That’s why Google provide free public DNS servers: 8.8.4.4 and 8.8.8.8. A project named namebench can help you find the best DNS servers, in part according to your browser history.
  • Socket connection can be reduced by moving the server closer. Alternatively, we could use CDN.

In the case of devoxx.com, there are only 67 requests but it’s a little less that 4Mb. Those requests are not only HTML, but also CSS, JavaScript and images. Requesting all these resources can be graphically represented as a waterfall. There are 2 ways to optimize the waterfall: making it shorter and thinner. Do not understimate the time taken in the frontend: on average, the frontend takes 86% of the time.

One could argue that improvements in network speed could save us. Most "advanced" countries have an average 5Mb/s speed, and is increasing. Unfortunately, bandwidth don’t matter that much, latency is much more important! Over 5Mb/s, increasing bandwidth won’t gonna help much Page Load Time (PLT) improvements, even though it will for downloading movies 🙂 The problem is that increasing bandwith is easy (just lay out more cables), while improving latency is expensive (read impossible) since it’s bound by the speed of light: it would require laying out shorter cables.

HTTP 1.1 is an improvement over HTTP 1.0 in that you can keep your connections alive: in the former version, one request required one connection, which is not the case in the later version. Now, this means that browsers open up to 6 TCP connections to request resources. This number is basically a limit, because of TCP slow start: it’s a feature of TCP that is meant to probe for network performance and not overload the network. In real-life, most HTTP traffic is composed of small, bursty, TCP flows because there are many requests, each of limited size (think JS files). A improvement would be to increase TCP initial congestion window, but it requires tweaking low-level system resources.

An ongoing work is HTTP 2.0! The good thing is that SPDY is already there and v2 is intented as a base for HTTP 2.0. HTTP 2.0 goals are making things better (of course), built on HTTP 1.1 and be extensible. Actual workarounds to increase PLT include concatenating files (CSS, JS), images spriting and domain sharding (in order to mislead the browser into making more than 6 connections because there are "fake" domains). SPDY is intended to remove these workarounds so that developers won’t have to sully their nails with dirty hacks anymore. You don’t need to modify your site to work with SPDY, but you can optimize it (stop spriting and sharding)

In essence, with SDPY, you open a single TCP connection and inside this single connection send multiple "streams", which are multiplexed. SPDY also offers Server Push so that server can push resources to the client…​ so long as the client doesn’t cancel the stream. Note that inlining resources inside the main HTML page can be seen as a form of Server Push. Today, SPDY is supported across a number of browsers, including Chrome (of course), Firefox 13+ and Opera 12.10+. Additionnally, there are a number of servers that are compatible (Apache through the mod_spdy, nginx, Jetty, …​).

The mobile web is exploding: mobile Internet users will reach desktop Internet users in 2 years. In countries like India, it’s already the case! There’s a good part of Internet users that are striclty accessing if from their mobile, the exact figure depends on the country, of course (25% in the US, 79% in Egypt). The heart of the matter is that though we don’t want to differenciate between desktop and mobile access, make to mistake: the physical layer is completely different. In fact, for mobile, the latency is much worse because exiting from idle state is time-consuming, both in 3G or in 4G (though numbers are reduced in the latter case).

There are some solutions to address those problems:

  • Think again SPDY
  • Re-use connections, pipeline
  • Download resources in bulk to avoid waking up the radio
  • Compress resources
  • Cache once you’ve got them!

Browser architecture

The good news is that the browser is trying to help you. Chrome, for example, has the following strategies: DNS prefetch (for links on the same page), TCP preconnect (same here), pooling and re-use TCP connections and finally caching (for resources already downloaded). More precisely, hovering the mouse over the link will likely fire DNS prefect and TCP preconnect. Many optimization parametes are available in Chrome, just go play with them (so long as you understand).

Google Analytics provides you with the means to get the above metrics when your site uses the associated script. An important feature is segmenting, to analyze the differences between users. As an example, the audience could be grouped into Japan, Singapore and US: it let us see that a peak PLT only for Singapore users was caused by the temporary unavailibility of a social widget, but only for the Singapore group.

Now, how does the browser render the bytes that were provided by the server? The HTML parser does a number of different things: create the DOM tree, as well as the CSS tree to create the Render tree. By the way, HTML5 specify how to parse the HTML, which was not the case in HTML 4: bytes are tokenized, tokens are built into the tree. However, JavaScript could change the DOM through doc.write so the browser must first manage scripts before doing anything. Consequence, sync scripts do block the browser; corollary, code async scripts, like so

(function()) {
	// do something here
})();

In HTML5, there are more simpler ways to async scripts, with script tag attributes:

  • regular, which is just standard script
  • defer tells the browser to download in the background and execute the script in order
  • async tells it to also download in the background but execute it when ready

-- 3 hours talk are really too much, better take a pause and come back aware than sleep my way through --

In order to optimize a page, you can install PageSpeed extension in Chrome, which will basically audit the page (-- note it’s also available as a Firebug plugin --). Checks include:

  • Image compression optimization: even better, the optimized content is computed by PageSpeed so you could take it directly and replace your own.
  • Resizing to 0x0 pixels (yes, it seems to happen and enough there’s a rule to check for it)
  • Looking for uncompressed resources. Web servers can easily be put in place to use gzip compression without updating the site itself

Alternatively, you can use the online PageSpeed Insights

Performance best practices

  • Reduce DNC lookups
  • Avoid redirect
  • Make fewer HTTP requests
  • Flush the document early so as to help the document parser discover external resources early
  • Uses a CDN to decrease latency: the content has to be put the closest to your users
  • Reduce the size of your pages
    • GZIP your text assets
    • Optimize images, pick optimal format
    • Add an `Expires`header
    • Add ETags
  • Optimize for fast first render, do not block the parser
    • Place stylesheets at the top
    • Load scripts asynchronously
    • Place scripts at the bottom
    • Minify and concatenate
  • Eliminate memory leaks
    • Build buttery smooth pages (scroll included)
    • Leverage hardware acceleration where possible
    • Remove JS and DOM memory leaks
    • Test on mobile devices
  • Use the right tool for the job (free!)
    • Learn about Developer Tools
    • PageSpeed Insights
    • WebPageTest.org
    • Test on mobile devices (again)

Reference: the entire slides are available there (be warned, there are more than 3)

Maven dependency puzzlers by Geoffrey de Smet

-- seems like a nice change of pace, recreational and all…​--

The first slide rejoins my experience: if you deploy a bad POM to a Maven repo, your users will feel the pain (-- see last version of log4j for what not to do --)

-- he, you can win beers! --

What happens when you add an artifact with different groupId?

Maven doesn’t know it’s the same artifact so it adds both. For users, this means you have to ban outdated artifacts, and exclude transitive dependencies. For providers, use relocation. In no case should you redistribute other project’s artifacts under your own!

What happens when you define a dependency’s version different from the dependency management’s version parent?

Maven overwrites the version. In order to use the parent’s version, don’t use any version in the project.

What happens when you define a version and you get a transitive dependency with a different version?

Maven correctly detects a conflict and uses the version from the POM with the least number of relations from the project. To fail fast, use the maven-enforcer-plugin and the enforce goal.

What happens when the number of relations is the same?

Maven chooses the version from the dependency declared first in the POM! In essence, this means dependencies are ordered; the version in itself plays no role, whereas a good strategy would be to retain the highest version.

-- hopes were met, really fun! --

Junit rules by Jens Schauder

-- though I’m more of a TestNG fanboy, it seems the concept of rules may tip the balance in favor of the latter. Worth a look at least --

Rules fixes a lot of problems you encounter when testing:

  • Failing tests due to missing tear down
  • Inheriting from multiple base test classes
  • Copy-paste code in tests
  • Running with different runners

When JUnit tries to run a test class, it finds all methods annotated with @Test and wraps them in "statement". Rules are things that take a statement as a parameter and returns a statement. Creating a rule is as simple a creating a class inheriting from Rule and annotating it with @Rule. Thus, bundling setup and teardown code is as simple as creating a rule that does something before and after evaluating the statement. Rules can also be used to enforce a timeout, to run the test inside the Event-Dispatch thread, or even to change the environment. Additionally, rules can be used to create tests that are run only under specific conditions, for example to test Oracle-specific code in some environment and H2-specific code in other. Finally, rules may be used to provide services to test classes.

Once you start using rules, you’ll probably end up having more than one rule during in the test execution. As a standard, rules shouldn’t depend on each other, so order shouldn’t be a problem. However, real-life cases prove a need to have rules chaining: JUnit provides a RuleChain to achieve this.

Finally, if you need a rule to execute before a single run (something akin to @BeforeClass), you can use @RuleClass.

-- IMHO, it seems rules are like TestNG listeners, which are available since ages. At least, I tried --

Nicolas Fränkel

Nicolas Fränkel

Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Also double as a trainer and triples as a book author.

Read More
Devoxx 2012 – Day 2
Share this