+ KOTLIN 46 | FUNCTIONAL JAVA 50 | CDI 59 | CAREERS 77 Testing HUNTING DOWN HARD-TO-FIND ERRORS
SEPTEMBER/OCTOBER 2015
AUTOMATED 14 TESTING FOR JAVAFX
JUNIT’S MOST 20 UNDERUSED FEATURES
BUILDING 26 A SELENIUM TEST GRID
ORACLE.COM/JAVAMAGAZINE //table of contents /
14 20 26 32 42 EIGHT GREATLY BUILDING AND STRESS TESTING THINK LIKE UNDERUSED AUTOMATING JAVA EE A TESTER AND TEST JAVAFX APPS FEATURES OF JUNIT A FUNCTIONAL APPLICATIONS GET RID OF QA WITH TESTFX By Mert Çalişkan TEST GRID By Adam Bien By Mark Hrynczak By Bennet Schulz Make your testing a whole By Neil Manvar Identify application server Atlassian represents the Simple JUnit-style testing of JavaFX UIs lot easier with little-used How to assemble a grid configuration problems, bleeding edge in testing: JUnit capabilities. for Selenium testing potential bottlenecks, its developers are required synchronization bugs, to formulate tests before and memory leaks in they code and after. QA is Java EE code. there to help—but not test. Here’s how it’s working.
COVER ART BY I-HUA CHEN
03 46 59 77 From the Editor JVM Languages Java EE Career One of the most effective tools for Kotlin: A Low-Ceremony, Contexts and Dependency More Ideas to Boost defect detection is rarely used due to High-Integration Language Injection: The New Java EE Your Developer Career old prejudices, except by companies By Hadi Hariri Toolbox By Bruno Souza and Edson Yanaga who can’t afford bugs. They all use it. Work with a statically typed, low- By Antonio Goncalves Skills to develop, activities to explore 06 ceremony language that provides More loose coupling with observers, 25 Letters to the Editor first-class functions, nullability interceptors, and decorators Java Proposals of Interest Corrections, questions, and kudos protections, and complete integration with existing Java libraries. 70 JEP 259: Stack-Walking API 07 Architecture 45 Events 50 A First Look at Microservices Functional Programming User Groups Calendar of upcoming Java By Arun Gupta The Virtual JUG conferences and events Functional Programming The latest trend in enterprise computing in Java: Using Collections is microservices. What exactly are they? 80 10 By Venkat Subramaniam 75 Contact Us Java Books Part 2 of our coverage of functional Have a comment? Suggestion? Reviews of books on JavaFX programming explains the code smells Fix This Want to submit an article proposal? and Java EE 7 that can arise from lambda-based Our latest code challenges from Here’s how to do it. the Oracle certification exams functional routines. 01
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 EDITORIAL PUBLISHING Editor in Chief Publisher Andrew Binstock Jennifer Hamilton +1.650.506.3794 Managing Editor Associate Publisher and Audience Claire Breen Development Director Copy Editor Karin Kinnear +1.650.506.1985 20 Years of Karen Perkins Audience Development Manager Section Development Jennifer Kurtz Michelle Kovac ADVERTISING SALES Technical Reviewers Josie Damian +1.626.396.9400 x 200 Stephen Chin, Reza Rahman, Simon Ritter Advertising Sales Assistant Innovation DESIGN Cindy Elhaj +1.626.396.9400 x 201 Senior Creative Director Mailing-List Rentals # Francisco G Delgadillo Contact your sales representative. 1 Development Platform Design Director Richard Merchán RESOURCES Oracle Products Senior Designer +1.800.367.8674 (US/Canada) Arianna Pucherelli Oracle Services Designer +1.888.283.0591 (US) Jaime Ferrand Senior Production Manager Sheila Brennan Production Designer Kathy Cygnarowicz Since 2002 Since 1999 Since 1995
ARTICLE SUBMISSION Since 1996 Since 1998 Since 1996 If you are interested in submitting an article, please e-mail the editors. SUBSCRIPTION INFORMATION Subscriptions are complimentary for qualified individuals who complete the subscription form. MAGAZINE CUSTOMER SERVICE Since 1996 Since 2008 Since 1998 [email protected] Phone +1.847.763.9635 PRIVACY Oracle Publishing allows sharing of its mailing list with selected third parties. If you prefer that your mailing address or e-mail address not be included in this program, contact Customer Service. Since 1999 Since 2001 Since 1996 Since 2012
Copyright © 2015, Oracle and/or its affiliates. All Rights Reserved. No part of this publication may be reprinted or otherwise reproduced without permission from the editors. JAVA MAGAZINE IS PROVIDED ON AN “AS IS” BASIS. ORACLE EXPRESSLY DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ORACLE BE LIABLE FOR ANY DAMAGES OF ANY KIND ARISING FROM YOUR USE OF OR RELIANCE ON ANY INFORMATION PROVIDED HEREIN. The information is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle. Oracle and Java are registered trademarks of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Java Magazine is published bimonthly at no cost to qualified subscribers by Oracle, 500 Oracle Parkway, MS OPL-3A, Redwood City, CA 94065-1600. Digital Publishing by GTxcel 02
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //from the editor /
BIO
The Unreasonable Effectiveness of Static Analysis It’s easy to run, provably effective, and greatly underused. Why?
here is perhaps no greater peculiarity in the demics study real-life projects, both open source Tprofession of software development than the and inside companies, the perception that they are lack of interest in software engineering. This field, disconnected from reality endures. Their utility, which is the empirical, quantitative analysis of however, shows up when a project with unusual software-development techniques, should be the requirements confronts an organization. Suppose cornerstone of the trade. And yet for most devel- after several years of leading various teams at your opment organizations, it remains a closed domain company and delivering projects roughly on time into which they never venture. Even the emerg- and of the desired quality, you’re charged with ing emphasis on metrics and dashboards has not a green-field project that requires a much lower led to curiosity about what thousands of projects level of defects than your organization is accus- tell us about those very numbers. The disregard tomed to. How will you amp up the quality? extends even to the parlance we use: In most This is where software engineering becomes a locales, a “software engineer” is a seasoned pro- crucial resource: You can see which techniques grammer. There is no implication of familiarity deliver lower defect rates and what their impact with software engineering. on productivity has been historically. Informed Part of this neglect is the view that practitioners with this data, you’ll be able to plan how to go are mostly academics. Although those same aca- about reaching the new goals for this project. (In
PHOTOGRAPH BY BOB ADLER/GETTY IMAGES 03
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //from the editor /
real life, of course, most organi- and to a lesser extent Checkstyle. false positives a decade ago aver- zations just call in consultants.) Commercial tools—such as those aged 10 percent but now are well Were you to perform this from Coverity, Parasoft, Rogue below 3 percent. In commercial inquiry, it might lead to con- Wave Software, and other ven- products, the rate is even lower. sideration of what practices you dors—are significantly more The other perceived drawback could add to existing projects to advanced. They can do magical is that the tools are slow. This raise their overall quality with- things such as data-motion anal- remains true. You typically run out sacrificing productivity. In ysis, which reveals defects that the high-end tools once a day for many—likely in most—cases, are hard to see via other means. the whole project, but always on that additional practice would be For example, this analysis can code about to be checked in. The static analysis of code. Relying show that a given data item can tools can analyze new code by on the work of Capers Jones, one never be null because all paths cross-checking with the database of the most widely experienced that touch it first pass through of artifacts from the most recent analysts of software-engineering another module far afield that whole-project scan. data, static analysis reduces guarantees nonnullness. Or it can Static analysis has an addi- defects in projects by 44 percent find the opposite, that a method tional upside: It’s not disruptive (from an average of 5.0 defects that counts on being passed only to existing site practices. You per unit of functionality to 2.8 prescreened objects can in fact can add it to a testing pipeline defects). Among standard quality be passed a null. Some of these with ease. This aspect and its assurance techniques, only formal tools excel at finding other very remarkable effectiveness make inspections have a higher effec- difficult bugs, such as unwanted it one of the simplest, but unde- tiveness (60 percent). By com- interactions between two servedly underused, ways to parison, test-driven development threads, or the rare case that a improve quality. (TDD) comes in at 37 percent. data item can be read incorrectly These numbers are not additive, due to the design of the Java Andrew Binstock, Editor in Chief of course. Inspections plus static memory model. These are subtle [email protected] analysis don’t deliver 100 percent items that can be hard to locate @platypusguy defect-free code. By the same and costly to fix—and they’re token, static analysis reveals typically not revealed by formal PS: Update on our evolution: problems that inspections and inspections or unit testing. In this issue, you’ll see that we TDD cannot find. Let me explain. The resistance to static analy- updated our fonts to improve Static-analysis tools today fall sis, I believe, stems from a repu- legibility and we’ve begun into roughly two tiers. There are tation built up in its early days of what will be a long-running the open source tools, which in delivering false positives—that series of articles on JVM lan- Java are particularly good. These is, claiming to find a defect where guages. Let me know if you have include FindBugs, PMD, walkmod, in fact none exists. Per Jones, any suggestions. 04
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 SPONSORED CONTENT
Adobe ColdFusion Celebrates 20 Years of Making Complex Coding Tasks Easy
riginally developed by Jeremy Allaire And it can be used to develop pretty much every on security in ColdFusion give enterprises the and JJ Allaire in 1995 to make it easier application required to meet dynamic business confidence and edge to easily adopt the latest for developers to connect simple HTML needs—which is why it is so prevalent in large technologies as they make their digital transitions. pages to a database, ColdFusion has enterprises and government setups. The future roadmap for improvement in the mobile Obeen around almost as long as the web itself and ColdFusion has a fan following in smaller development platform and the addition of social predates many popular web development languages. organizations, too. “When we started out, as [with] any analytics while staying true to the ColdFusion credo A full scripting language—CFML—and an integrated startup, the budget was always short. So we needed of ‘making hard things easy‘ indicate exciting times development environment were added, and a language that allowed us to develop the application for ColdFusion in the coming years.” ColdFusion remains popular with coders for being in a short period of time. ColdFusion dramatically cut a rapid web application down the development cost,” says Sumit Verma, co- Tridib Roy Chowdhury, General Manager and Senior development platform owner at Ten24 Digital Solutions. Director of Products, Adobe that helps them reduce “ColdFusion has clearly stood the test of time,” development time by an says Rakshith Naresh, product manager at ColdFusion. order of magnitude. “One of the reasons why customers keep coming back Adobe ColdFusion Summit 2015 to ColdFusion is the productivity benefit it offers.” (November 9–10, Las Vegas, Nevada) A history of innovation brings together the web application Over two decades ColdFu- Continuing to blaze the trail community. Interact with ColdFusion sion has been at the fore- “There really isn’t a comparison at all between how experts, domain leaders, and peers, front of simplifying all tasks Adobe reacts to our needs versus any of the other and learn about the latest technologies, programmers find tedious software companies that we work with. Basically, and time consuming, such what happens is ColdFusion allows us to change our techniques, and strategies to help you as charts and graphs, PDF market,” quotes Eric Kratz, president at VSR Systems. rapidly build and successfully deliver Tridib Roy Chowdhury, General Manager and generation and manipu- Be it overhauling your company’s HR operations, web applications to market. Explore how Senior Director of Products, Adobe lation, WebSockets and updating your firm’s global intranet, or powering the ColdFusion is driving change and how you many more. Many of the things that seem so obvious world’s busiest electronic storefronts, you can be sure can propel this momentum. to us now were innovative solutions first offered by this 20-year-old will rise to the occasion. Adobe ColdFusion Summit is the largest ColdFusion, allowing developers to create robust, scal- “ColdFusion continues to do well while staying at summit for ColdFusion developers and has able, high-performing, secure web- and mobile-based the forefront of technology. The unique integration had three successful annual installments. applications with minimal effort. with HTML5 along with the end-to-end mobile Each release has built on the previous ones, and development platform and the increased focus ColdFusion has long since gone beyond its “tag- based scripting language” past. Today, ColdFusion can talk to pretty much everything, from legacy COM and CORBA to .NET assemblies and Java classes. For more information, visit adobe.com/coldfusion //letters to the editor /
Casting for long? May/June issue. We will have many How About a Kindle Version? In the article “What’s New in JPA” more similar articles in the future.” The magazine needs to be avail- in the May/June 2015 issue, I saw able in the Kindle format. I don’t in Listing 17 that the author uses Inside the CPU get why people would download a cast to long. But in fact, if the Thank you so much for driving a PDF, or read the same on their code were the magazine in a more techni- phones. It’s too cumbersome. cal direction. The article “Inside Having a Kindle version will get return em.createQuery( the CPU: The Unexpected Effects you 10x the readers. ..., Long.class) of Instruction Execution” (in —Jude Pereira .getSingleResult(); the March/April and July/August MAY/JUNE 2015 issues) is absolutely awesome! Editor Andrew Binstock responds: it would remove the need for the —Yury Pitsichin “In Silicon Valley, at least, most cast. people in tech read magazines on —Josh Toepfer A Paper Version of Java tablets (which, in my opinion, are Magazine? better for reading articles with code). Author Josh Juneau responds: “You I was wondering if there is a For users of tablets, we offer both are correct that we can get rid of the possibility of getting a printed iOS and Android apps. For all others, cast by passing Long.class as the edition of the magazine, at least we offer PDF. We are actively looking second argument to createQuery() through a third-party provider? at expanding our list of distribution on line 6 of the listing. Thanks for After a complete day of work in targets, and the Kindle is at the top of pointing this out.” front of the computer, it’s good that list. However, we don’t expect to to have a print magazine for a be able to provide that upgrade before IoT Coverage change of environment. the end of the year or early next year.” Now that we’re in an IoT-based —Raj Thondepu world, I wish to see articles Contact Us covering the ecosystem of embed- Publisher Jennifer Hamilton We welcome comments, sugges- ded Java for IoT. This includes the responds: “I totally understand tions, grumbles, kudos, article processor, programming, devel- wanting to disconnect and enjoy a proposals, and chocolate chip opment kits, embedded Java, and printed publication. However, Java cookies. All but the last two might so on. Magazine is being published only in be edited for publication. If your —Sam Desd digital format. When I want to read note is private, please indicate a hard-copy version of an article, this in your message. Please write Editor Andrew Binstock responds: I download the PDF and print the to us at [email protected]. “We had a long article on using Java pages in landscape mode using the For other ways to reach us, please for IoT on the Raspberry Pi in the Fit option in Adobe Acrobat Reader.” see the last page of this issue. 06
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //events /
attended this free commu- GeeCON San Francisco, California nity event where developers OCTOBER 23–24 learn from fellow developers. PRAGUE, CZECH REPUBLIC In addition to technical topics, Join more than 2,000 par- speakers present on software ticipants at GeeCON, which is branding and legal issues. focused on JVM-based tech- nologies with special attention JAX London to dynamic languages such OCTOBER 12–14 as Groovy and Ruby. GeeCON LONDON, ENGLAND participants share experi- JAX London brings Java, JVM, ences about development and enterprise professionals methodologies and craftsman- together for a technology- and ship, enterprise architectures, methodology-packed event. design patterns, distributed Participants get full access to computing, and more. Big Data Con London, which features modern datastores, W-JAX 15 big data architectures based NOVEMBER 2–6 on Hadoop, and advanced data MUNICH, GERMANY JavaOne 2015 OCTOBER 25–29 JavaDay Kharkiv processing techniques. The W-JAX conference cov- SAN FRANCISCO, CALIFORNIA OCTOBER 1 ers current and future aspects JDD Join the single largest gathering of Java KHARKIV, UKRAINE of technologies such as Java, OCTOBER 13–14 developers. From sessions, workshops, Enjoy and learn in a full day Scala, and Android. Also KRAKOW, POLAND labs, and exhibits to keynotes and Birds- of world-class talks. Topics addressed are web applications JDD is a two-day confer- of-a-Feather sessions, learn about the include core JVM platform and techniques, agile development ence for all Java enthusiasts, latest language changes to improve cod- Java SE (Java 8), JVM languages models, and DevOps. who can participate in more ing efficiency. You’ll also learn how to and new programming para- than 30 lectures, workshops, build modern enterprise and server- digms, web development, and J-Fall 2015 interactive trainings, and net- NOVEMBER 5 based applications, create rich and Java enterprise technologies. working opportunities. JDD EDE, NETHERLANDS immersive client-side solutions, build attracts speakers from all over next-generation apps targeting smart Silicon Valley Code Camp The annual Java conference the world and offers lectures devices, and compose sophisticated Java OCTOBER 3–4 organized by the Dutch Java in English. web services and cloud solutions. SAN JOSE, CALIFORNIA User Group (NLJUG) typically Last year, 4,500 people sells out and has outgrown its usual venue. This year, J-Fall PHOTOGRAPH BY WESTEND61/GETTY IMAGES 07
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //events /
ence, this event is a university Codemotion Spain Apache Hadoop Innovation Summit day of training, workshops, and NOVEMBER 27–28 FEBRUARY 11–12 labs followed by conference days MADRID, SPAIN SAN DIEGO, CALIFORNIA of sessions on software devel- This two-day event draws nearly With presentations from more opment, web, mobile, gaming, 2,000 attendees, represents more than 25 hands-on industry speak- security, methodology, Internet of than 30 communities, and features ers, topics covered will include Things, and cloud. The Decision coding lectures and workshops. MapReduce and Spark, building Makers evening includes discus- Activities for startups, recruiting, privacy-protected data systems, sion of issues related to the IT and networking are included. scalable data curation, best prac- industry in Morocco. tices, and architectural consider- Clojure eXchange 2015 ations for Hadoop applications. QCon San Francisco 2015 DECEMBER 3–4 NOVEMBER 16–20 LONDON, ENGLAND Embedded World 2016 SAN FRANCISCO, CALIFORNIA Meet with the world’s leading FEBRUARY 23–25 A practitioner-driven software experts, learn how to use Clojure NUREMBERG, GERMANY development conference, QCon is with your team, and discuss war The 14th annual gathering of will take place in the CineMec designed for technical team leads, stories with your peers. Both days embedded system developers in Ede. architects, engineering directors, will feature a mixture of talks will explore the latest develop- Devoxx Belgium and project managers who influ- covering various aspects of Clojure ments, define trends, and once NOVEMBER 9–13 ence innovation in their teams. development: from libraries to again present the key areas of ANTWERP, BELGIUM Tracks this year include Taking music, from ClojureScript to data. focus for future developments. By developers for developers, Java to the Next Level and The This is where hardware, software, Groovy and Grails eXchange 2015 this event has 200 speakers and Dark Side of Security. The last two and system development engi- DECEMBER 14–15 3,500 attendees from 40 coun- days are devoted to workshops. neers come together to turn the LONDON, ENGLAND tries. Tracks this year include Java next milestones of the Internet of Codemotion Milan Stay ahead of the curve and hear SE, JVM languages, and server- Things into reality. NOVEMBER 18–21 the 2016 roadmap for Groovy side Java, as well as cloud and big MILAN, ITALY and Grails from core commit- data, mobile, and architecture and Have an upcoming confer- This conference is open to users ters and Groovy authorities security, among others. ence you’d like to add to our of all languages and platforms. It Guillaume Laforge and Graeme listing? Send us a link and a Devoxx Morocco offers full-day workshops on the Rocher. Engage with other lead- description of your event at NOVEMBER 16–18 first two days, followed by key- ing experts and fellow enthusiasts least four months in advance at CASABLANCA, MOROCCO notes and conference sessions. and learn the latest innovations [email protected]. We’ll Formerly the JMaghreb confer- and practices. include as many as space permits.
PHOTOGRAPH BY HENRYK SADURA/GETTY IMAGES 08
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 AOT Compilation Is Coming to Java 8
Excelsior JET 11 will support Java SE 8 and JavaFX 8 on all desktop platforms.
Get Your Early Access Copy Now Registration-Free Download
LICENSEE
LICENSEE // java books /
JAVA EE 7: THE BIG PICTURE By Danny Coward Oracle Press (McGraw-Hill)
For Java SE developers, Java EE Using Java EE from the start a web front end, a logic layer, has long appeared to be a large can facilitate the addition of and a persistence layer. He then tangle of technologies, primarily features, scalability, and even amplifies this content by bring- of interest to enterprise develop- security for many projects. ing in additional technologies, ers. Even though the Enterprise The trouble is how to go from including WebSocket, dependency Edition has vastly improved since Java SE to Java EE without get- injection, security, and so forth. the days of J2EE, it continues to ting overwhelmed by the seem- The explanations start at a be trailed by its early reputation. ing labyrinth of technologies? high level but quickly descend In part, this is because there is That question is precisely what to code. This code is both clear a sense that any development this book addresses. It provides and extensive. This book aims on Java EE requires familiarity an overview of Java EE 7, sys- squarely at developers, rather with many different services that tematically explaining the core than architects or executives, and need to be integrated just-so to technologies—how they work the programmer reader will find create a proper app. These skills and how they fit together. a clear, very well written text. are in addition to the language The author, a principal archi- My only reservation about the skills, which are assumed. For tect of Java EE, presents the book is that it does not cover many developers, this seeming material in the context of a secondary Java EE technologies, complexity has been solved by hypothetical application that such as Java Message Service or just using a standard container would use the core technologies: JavaMail. But these consider- (Tomcat, for instance) and JDBC on the back end for database When we began doing critical book reviews in the May/June issue, needs. Such an approach works we stated that due to possible conflicts of interest, we would not review well enough until the require- books from Oracle Press. However, after securing approval for indepen- ments expand, at which point dent reviews from both Oracle and McGraw-Hill (the publishers of Oracle continuing to organically grow Press books), we begin in this issue to examine two recent titles from that the app with other unintegrated imprint: one we liked a lot and one we did not. —Ed. technologies becomes a path of declining returns. 10
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //java books /
ations aside, this is an excellent system (not Eclipse’s OSGI) and undertaking a project using the incomplete introduction to the programming introduction to exposes an extensive UI meta- NetBeans platform will have that technology. Java EE 7. —Andrew Binstock phor—which includes a windows kind of background. For those First, let me touch on what manager with multiwindow sup- readers, this book is a godsend. it doesn’t cover, because these port, search capabilities, a wizard The question I’m led to ask is, are crucial gaps: FXML and CSS builder, and so forth. how many such readers could styling. These two technolo- Under this presentation good- there be? I expect it’s a small set, gies, essential elements of any ness is a lot of technology that which makes me admire both serious introduction, are dis- delivers useful services: for exam- the authors and the publisher for missed via this glib line: “[All ple, an entire file-management releasing a nearly 1,000-page vol- the examples in this book] are in layer, which includes goodies such ume on so narrow a topic. But for Java. Therefore, no understand- as a file-status monitor that issues anyone in that group, this volume ing of CSS or FXML is needed.” a message whenever a watched set is the guide to have. —AB The use of FXML and CSS precisely of files is modified; RESTful web to avoid coding details in Java is services; application update ser- apparently lost on the author. vices; and so on. Many other items are not cov- JAVAFX RICH CLIENT PROGRAMMING The explanations of the best ered. The author mentions JavaFX ON THE NETBEANS PLATFORM ways to exploit the NetBeans technologies that he tells readers Gail and Paul Anderson platform are clear, approach- to learn by themselves. However, Addison-Wesley able, and illustrated with useful if you turn to the section entitled examples. The integration with “For Further Study” to do this, you Of all the words in this book’s JavaFX, however, feels somewhat find only a list of books all writ- title, platform most indicates its rougher. Even though JavaFX is ten by this same author not one of true content. This book is not a presented from scratch (presum- which is about JavaFX. tutorial on JavaFX using NetBeans. ably aimed at someone new to the As to the actual content, the Rather, it’s a book about using technology), a beginner would be author is unhelpful. He covers the JavaFX in conjunction with unlikely to be capable of following INTRODUCING JAVAFX 8 easy things in great detail, and NetBeans as a software platform along without getting lost. The PROGRAMMING the hard things are glossed over. for developing desktop applica- ideal reader is proficient with Java By Herbert Schildt There is precious little here that tions. In this sense, NetBeans as and has familiarity with writing Oracle Press (McGraw-Hill) cannot be found in freely available platform corresponds roughly to UIs either in Swing or JavaFX. For tutorials. For serious developers, the Eclipse Rich Client Platform. such a reader, the JavaFX chap- As fun as JavaFX programming Hendrik Ebbers’ Mastering JavaFX That is, it provides the software ters will serve as a review and an is, it is a world unto itself that 8 Controls provides a far better platform on which rich desktop update that enables safe passage requires a good guidebook to introduction to JavaFX; it covers apps can be built. NetBeans pro- to the discussion of NetBeans fea- understand its ins and outs. both CSS and FXML and does not vides its own internal module But instead, this book is a most tures. Fortunately, almost anyone skirt difficult material. —AB 11
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015
Testing: WE’RE ALL IN THIS TOGETHER
etween the pre- and post-agile generations of developers, there is perhaps no greater difference than the role of developers in testing their code. The concept of developers Bwriting tests as they pushed out code was a radical idea that took root and became an essential part of the coding process. Today some companies, such as Atlassian (page 42), are radicalizing this notion even further by moving all the responsibilities for QA to developers and training newly hired programmers from their first day in QA principles and techniques. While agile values set the course in this new direc- tion, it was undoubtedly the advent of JUnit—a fast test framework with intuitive mechanics—that made developer testing a universal reality. Despite JUnit’s ubiquity, most of us, I fear, use only a familiar sub- set of its features and re-create capabilities already available. Our article on useful but underused fea- tures of JUnit (page 20) should help. User interfaces are not as amenable to JUnit and so require specialized tools. For JavaFX, that tool is increasingly TestFX (page 14). For web-based inter- faces, unfortunately, it is clusters of virtual machines exercising hundreds of combinations of browser releases and operating systems (page 26). Whatever your project’s test tools, it is clear that we will not soon return to the days when coding and testing were segregated activities performed by different teams. I’m good with that. —Andrew Binstock ART BY I-HUA CHEN 13
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing / Test JavaFX Apps with TestFX Simple JUnit-style testing of JavaFX UIs
BENNET SCHULZ estFX is an API for testing user interfaces written in Getting Started with Maven TJavaFX. It automates tests for JavaFX applications by Adding TestFX to a Maven build is as simple as adding the BIO simulating user interactions such as button clicks, typ- JUnit dependency. You need to add only the following snippet ing text into a field, and many other interactions done in to your pom.xml file: JavaFX applications. This article starts with a short background on the TestFX
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
} In contrast to other implementations, this calculator shows return parent; all user input in a field, and when the equals (=) button is } clicked, the result is calculated. Other calculators show only // ... the last numeric input and after the = button is clicked, they } show the result without showing intermediate steps. The view of this application is an FXML file created with By extending GuiTest, you also get additional UI test Gluon Scene Builder 8.0.0, and the buttons are styled with methods that simulate user interactions. For example, you CSS using a linear gradient. The more interesting part is have access to methods for finding UI elements, such as but- the corresponding controller. It contains three methods: tons or fields, and methods for clicking buttons, scrolling handleButtonAction, handleRemoveButtonAction, and scrollbars, and so forth. handleCalculationAction. The first two methods are The Sample Application simple. The last one is the method that calculates the result after the = button is clicked. I’ll focus on testing it. The sample application is a calculator based on the GNOME Listing 1 shows the method for calculating the result gcalctool (see Figure 1). It looks like gcalctool and behaves like depending on the user’s input. gcalctool, but it is written in JavaFX (instead of gcalctool’s original language, Vala). Listing 1. @FXML private void handleCalculationAction(ActionEvent e) { String displayText = display.getText(); int textLength = displayText.length(); String result = ""; if (displayText.contains("+")) { int plusIndex = displayText.indexOf("+"); Double a = Double.valueOf( displayText.substring(0, plusIndex)); Double b = Double.valueOf( displayText.substring(plusIndex + 1, textLength)); result = String.valueOf((a + b)); } else if (displayText.contains("x")) { int multiplyIndex = displayText.indexOf("x"); Double a = Double.valueOf( displayText.substring( 0, multiplyIndex)); Double b = Double.valueOf( Figure 1. The view of the sample application 15
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
displayText.substring( Logger.getLogger( multiplyIndex + 1, textLength)); CalculatorControllerTest result = String.valueOf((a * b)); .class.getName()) display.setText(result); .log(Level.SEVERE, null, ex); } } return parent; This method multiplies, divides, adds, and so on. At the end } of this method, the calculated result will be set as the text for the field that is shown at the top of the UI. In the next sec- The next step is about initializing the gcalctoolFX.fxml tion, this method is used to introduce how to write tests for view (see Listing 2) that we want to test with this test class. this application using TestFX. This can be done by loading the respective view and returning Some features (such as subtraction, square, curly brackets, it as the result of the getRootNode method of the test class. floating points, and so on) were left out for simplicity’s sake After that initialization step, we can start writing tests for in this tutorial. If you want to have a version of this calculator this test scenario. A TestFX test must follow standard JUnit 4 that has all its features, it is available in the download area conventions, including using the @Test annotation, a public for this issue of Java Magazine. access modifier, and a return type of void. A sample TestFX test is shown in Listing 3. Writing Tests for the Sample Application Let’s write a test that simulates a user who wants to calculate Listing 3. the sum of 1 + 2. The user does this by clicking 1, +, and 2. @Test public void testAddition() { After the user clicks =, the calculator should display the result Button one = find("#one"); of 3 in the field at the top of the UI. Button plus = find("#plus"); To test this scenario with automated tests, first we add the Button two = find("#two"); Maven dependency, as described earlier, and initialize the Button equalSign = find("#equal"); test class (see Listing 2). click(one); Listing 2. click(plus); public class CalculatorControllerTest click(two); extends GuiTest { verifyThat("#display", hasText("1+2")); @Override click(equalSign); protected Parent getRootNode() { verifyThat("#display", hasText("3.0")); Parent p = null; } try { p = FXMLLoader.load(getClass() As you can see in Listing 3, the test is as simple as a plain .getResource("gcalctoolFX.fxml")); JUnit test. Before the test is run, the view will be constructed } catch (IOException ex) { by the getRootNode method in Listing 2. You need only to 16
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
find the button you want to click able, and easy to reconstruct. Therefore, it’s important that via a literal by using the find TestFX is a great the assertions be clear so it’s evident what’s wrong with the method, which is provided by framework for code when a failure occurs. In TestFX, Hamcrest matchers extending the GuiTest class. In are helpful, because they provide more-readable assertions. case of an FXML view, the lit- testing JavaFX Listing 4 shows the simplicity of TestFX tests and the usage of eral is the identifier (fx:id) of a applications. It is Hamcrest matchers for verification. UI element. This identifier has simple and intuitive, to be set to use the UI element Listing 4. in a controller class for bindings and beginners can @Test and event handling. This can be learn it quickly. In public void testMultiplication() { done either by setting it in Scene Button two = find("#two"); addition, it offers a Button times = find("#times"); Builder or editing the FXML file clear API that results Button three = find("#three"); itself. When using programmati- Button equalSign = find("#equal"); cally created views, this identi- in understandable fier has to be set with a setId() tests, which facilitates click(two); method call on the UI elements click(times); that are used in test classes. diagnosing the errors click(three); After getting the buttons with that cause test failures. find()calls, the buttons need verifyThat("#display", hasText("2x3")); click(equalSign); to be clicked in this order: 1, +, 2, verifyThat("#display", hasText("6.0")); =. This can be done by using the } click() method. Before clicking the = button, the calcula- tor should display “1+2” in the field. After clicking the = but- The test in Listing 4 expects a value of 6. A bug is simulated ton, the display should change and show “3.0” to indicate the by changing the multiply operation of the controller so that result of the addition. The display text can be verified with it multiplies two operands and spuriously adds “+1” at the verifyThat(), and the expected text should be an argument end of the multiplication. This bug is introduced to show how of the hasText() method call. TestFX deals with errors. Because of this bug, the test fails, Note that TestFX is compatible with the open source JaCoCo and the corresponding stack trace looks like the following: coverage tool and likely with other tools. It recognizes the lines of code that are covered by your TestFX tests, and you testMultiplication(...CalculatorControllerTest) can track the code coverage as you can do with JUnit tests. Time elapsed: 2.434 sec <<< FAILURE! java.lang.AssertionError: Tests That Fail Expected: Node should have label "6.0" but: Label was "7.0" Screenshot saved as Another important part of unit tests is information about /home/…/screenshot1436949687849.png the ones that fail, especially when you are testing user inter- at ...testfx.Assertions faces. Failing tests should be interpretable, understand- 17
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
.verifyThat(Assertions.java:38) this issue is to use different CSS IDs for every object, which at ...testfx.Assertions means that the same gradient will need to be applied to each .verifyThat(Assertions.java:26) button separately. at . . . Another limitation is that screenshots are taken as full- ... screen screenshots. Instead of showing the UI window only, Caused by: java.lang.AssertionError: Expected: Node should have label "6.0" TestFX grabs the complete screen with all the other opened but: Label was "7.0" windows in the background. In most cases, the opened win- at org.hamcrest.MatcherAssert dows in the background are unimportant for the re-creation .assertThat(MatcherAssert.java:20) of failed tests. They offer too much information and could at org.loadui.testfx.Assertions show private information about testers or developers, for .verifyThat(Assertions.java:33) example. In addition to that, there is currently no enable ... 35 more and disable mode for taking screenshots. Screenshots will be taken for every test that fails. Sometimes this This (abbreviated) stack trace tells us in a very clear way is undesirable. which test failed, in which line, and with which condi- Also, there has been less development activity for TestFX tion, and it also tells us where the corresponding screenshot lately. TestFX 4.0 has been in prerelease development since was saved. 2014. To ensure that there are future releases of this very Limitations useful software, it would be helpful if there were additional active developers. While TestFX is a very helpful project for testing JavaFX apps, it has some limitations you should be aware of. Conclusion One of the major limitations of TestFX is that debugging TestFX is a great framework for testing JavaFX applications. tests written in TestFX is not necessarily easy. TestFX doesn’t It is simple and intuitive, and beginners can learn it quickly. allow mouse movements while running tests. If you are run- In addition, it offers a clear API that results in understand- ning tests in debug mode and you want to check the values able tests, which facilitates diagnosing the errors that cause of variables in the NetBeans view, for example, TestFX won’t test failures. Nevertheless, there are a few limitations, which react on break points, and the test will also abort because of you should keep in mind when using the current release of the mouse movement. TestFX. There is another major limitation when styling components with CSS, as I did with the calculator buttons for the sample calculator application. The styled component has two IDs: the controller ID and one in CSS. In this version of TestFX, the framework searches for the occurrence of id instead of LEARN MORE fx:id and, therefore, it will use the CSS ID instead of the • Download the calculator controller ID. This results in an error, because TestFX won’t • Video lecture on TestFX, with additional usage details be able to find the respective button. The workaround for • Gluon Scene Builder 8.0.0 18
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 with The Lightweight Java Profiler //testing / Eight Greatly Underused Features of JUnit Make your testing a whole lot easier. MERT ÇALIS¸KAN
BIO hen it comes to unit testing, we can safely say that class, which should be an implementation of either the WJUnit is the most popular test framework among TestRule or MethodRule interface. Both interfaces con- Java developers. Despite the headline on the official JUnit tain the method signature: Statement apply(…). website stating that it’s a simple framework, there is a Implementation of this apply() method can be executed good deal of extensive functionality bundled within it. before, after, or instead of a test method. This approach adds Unfortunately, most of us use a familiar set of features, and flexibility for applying new behaviors for each test method, so we duplicate available goodies by reinventing them. With à la interceptors. this article, I dig into nine convenient but underused features JUnit 4.9 introduced the @ClassRule annotation that of JUnit that should ease writing test code—including cre- extends the test method rule approach to the class level so ating and automatically cleaning up temporary directories, that it can be invoked before or after all test methods of that running all assertions despite one failing, killing wayward class. It’s efficient to use this capability, if, for example, a tests, and the like. server needs to be started before running all the test meth- All the examples in this article are based on JUnit ver- ods so that it won’t be started and shut down for each test sion 4.12, which is the latest available version at the time of method inside a test class. this writing. However, unless otherwise noted, all the fea- tures mentioned here have been available since JUnit 4.7. Creating Temporary Files and Folders Using @Rule The complete source code for the article is available at the From time to time, you might need to create certain files and Java Magazine download site. folders in your application, but how would you test that with code to see whether the files are created as expected? You can First Things First: @Rule do all the work in a temporary folder with some extra cod- I will make use of JUnit’s @Rule annotation, which offers a ing, but most solutions present portability conflicts if the test generic way to add extended features on a per-test-method environment is moved. In addition, any handmade solution basis. By employing rules, the various activities I want to can get messy if cleanup is not done carefully. enable can be stated in one place, and I won’t need to define Since version 4.7, JUnit has offered the TemporaryFolder them over and over again for each test method. test rule, which provides a convenient way to create and The @Rule annotation applies to a public field of a test manage a temporary directory. It guarantees that the new 20
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
directory’s name does not conflict with existing files or directories. It @Rule also guarantees that content will be deleted after the test method fin- public TestName name = new TestName(); ishes, whether the execution result is successful or not. @Test Listing 1 creates a file named sample.txt in a temporary folder that public void methodNameShouldBePrinted() { JUnit creates and then writes “JUnit Rocks!” The test then reads the first System.out.println("Test method name: " + line of the newly created file and compares the text value that was writ- name.getMethodName()); ten. For testing purposes, the Apache Commons IO framework is used } for the simplicity that it provides in handling files. }
Listing 1. The name of the test method can be accessed via getMethodName(). public class TemporaryFolderTests { The output of the test method will be
@Rule Test method name: methodNameShouldBePrinted public TemporaryFolder tempFolder = new TemporaryFolder(); Collecting Errors When Multiple Assertions in One Test Fail
@Test With the ErrorCollector class, JUnit offers a way to handle multiple public void fileCreatedAndWrittenSuccessfully() test failures of a single test case. So, you can enable a test not to stop on throws IOException { an error by doing all assertions and listing the failed ones at the end. File file = tempFolder.newFile("sample.txt"); Listing 3 shows a test method with three statements that are checked FileUtils.writeStringToFile( with the ErrorCollector. file, "JUnit Rocks!"); Listing 3. String line = FileUtils.readFileToString(file); public class ErrorCollectorTests { assertThat(line, is("JUnit Rocks!")); } @Rule } public ErrorCollector collector = new ErrorCollector(); JUnit deletes the file and the directory once the test is completed (regardless of whether the test passes or fails). @Test public void statementsCollectedSuccessfully() { Getting the Name of the Currently Executing Test String s = null; collector.checkThat If you’d like to get the name of a test while it’s executing, simply instan- ("Value should not be null", null, is(s)); tiate a TestName rule as a field and annotate it with the @Rule annota-
tion, as shown in Listing 2. s = ""; collector.checkThat( Listing 2. "Value should have the length of 1", public class TestNameTests { s.length(), is(1)); 21
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
s = "Junit!"; the number of parameters passed to the constructor must match the collector.checkThat( item count of each element of the list. Listing 4 shows how this is done. "Value should have the length of 10", s.length(), is(10)); Listing 4. } @RunWith(Parameterized.class) } public class FibonacciNumbersTests {
Note the use of the ErrorCollector instance in the tests themselves. @Parameterized.Parameters If the first statement passes but the next two fail, the output is as fol- public static List data() { lows (condensed here by removing the stack trace detail): return Arrays.asList(new Object[][]{ {0, 0}, {1, 1}, {2, 1}, java.lang.AssertionError: Value should have the length of 1 {3, 2}, {4, 3}, {5, 5}, Expected: is <1> {6, 8}}); but: was <0> } at org.hamcrest.MatcherAssert... private int value; java.lang.AssertionError: Value should have the length of 10 private int expected; Expected: is <10> but: was <6> public FibonacciNumbersTests( at org.hamcrest.MatcherAssert... int input, int expected) { value = input; Running One Test Multiple Times with Different Parameters this.expected = expected; } It is fairly common to need to run the same method with varying inputs to see that the executed results are asserted successfully. Since version @Test 4.0, JUnit provides the flexibility to do this with the @Parameters anno- public void fibonacciNumberCalc () { tation, which enables you to run one test method again and again pro- assertEquals(expected, fib(value)); viding different input values each time. } To demonstrate the parameterized usage, I will test a method that public static int fib(int n) { calculates a Fibonacci number according to a given index value of it in if (n < 2) { the sequence. To get the @Parameters annotation picked up, I need to return n; state that the test class should be handled with a custom runner, which } else { is Parameterized.class, rather than with the default runner that return fib(n - 1) + fib(n - 2); JUnit uses. } To provide input values for the Fibonacci series, a public static method } with a list of objects should be defined, and it should be marked with the } @Parameterized.Parameters annotation. Each element of that list will be provided as a parameter to the constructor of the test class. Thus, Note the first line with the @RunWith annotation, which tells JUnit to use a specialized runner. 22
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
Here, with each item, we are providing the input value first and then Grouping Your Tests with @Category the expected value to make the assertion. For purposes of illustration, I In a sophisticated build process, it’s frequently useful to group and run have included the fib() method that we are testing as a static method the fast-running tests first to get quick feedback from them. To achieve within the test class. Also note that the test class can have only one con- this, JUnit 4.8 first offered the @Category annotation to group tests structor defined. Multiple constructor declarations will lead to an illegal with a marker interface or a class. Listing 6 illustrates two test methods, argument exception. one annotated with @Category.
Adding a Timeout for Execution Listing 6. It is frequently useful to be able to kill a test that is taking too long to public class CategorizedTests {
execute. Unexpected stalls, for example, can turn quick runs of unit @Test tests into long-lasting affairs. The @Test annotation offers the timeout @Category(SlowTests.class) attribute, which specifies a time that, if exceeded, causes a test method public void thisTestRunsSlowly() { to fail. The timeout attribute uses milliseconds. A time limit applied to System.out.println("Slow test running"); all tests in a test class is a common need, and JUnit offers the Timeout } rule class to handle this. It can use units of seconds or milliseconds. Listing 5 defines a global timeout rule with five seconds and a test @Test method that never finishes. public void thisTestRunsFast() { System.out.println("Fast test running"); Listing 5. } public class LongRunningTests { }
@Rule SlowTests.class is just a marker interface that is used to determine public Timeout globalTimeout = Timeout.seconds(5); the test methods that will run more slowly than normal:
@Test public interface SlowTests { public void whatWeDoInATestMethodEchoesInEternity() { } while(true); } One approach to run the categorized tests is to implement a test suite } class. Listing 7 gives an example of this by employing a custom runner, which is Categories.class. Without the custom runner, @Category An excerpt of the output of this test after five seconds of execution will annotations cannot be interpreted. In order to state which categories be as follows: should run within this test suite, the @IncludeCategory annotation with the value of the SlowTests marker interface is used. All sub- org.junit.runners.model.TestTimedOutException: classes of the SlowTests interface will also be picked up with this cat- test timed out after 5 seconds at tr.com.t2.labs.tdd.sample5.LongRunningTests… egory inclusion.
23
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
Listing 7. System.out.println(label + " before"); @RunWith(Categories.class) base.evaluate(); @Categories.IncludeCategory(SlowTests.class) System.out.println(label + " after"); @Suite.SuiteClasses(CategorizedTests.class) } public class SlowTestsTestSuite { } } } } Besides the test suite approach, JUnit categories are supported by popular build tools—such as Maven, Gradle, and SBT—to run specific Using our custom rule is done in the same way as using the built-in groups of tests. You can exclude a category with the @ExcludeCategory rules provided by JUnit. Listing 9 shows the usage. annotation, which operates precisely as you would expect. Listing 9. Creating Your Own Rules public class CustomRuleTests {
Implementing your own rules is as simple as implementing the @Rule TestRule interface. This interface has only one method, apply(). public MyCustomRule myCustomRule = You should implement the apply() method and return an instance of new MyCustomRule("custom"); Statement, which is an abstract class that provides an evaluate() method. An outcome will be evaluated from that method when a rule is @Test applied with the invocation of the apply() method. Listing 8 gives an public void myAwesomeMethodInvokedSuccessfully() { example implementation of a custom rule. System.out.println("Test worked OK"); } Listing 8. } public class MyCustomRule implements TestRule { The following is the execution output: private String label; custom before public MyCustomRule(String label) { Test worked OK this.label = label; custom after } Chaining Rules @Override Once you start working with rules, especially when writing your own, public Statement apply( you might want to chain them so that they run in a specific order. With final Statement base, the RuleChain rule, it’s possible to order multiple rules according to Description description){ your needs. This feature, which has been available only as of JUnit 4.10, is return new Statement() { @Override effective if you need to do configuration in a specified order, such as -con public void evaluate() throws Throwable figure your web server with one rule and then start it with another rule. { The outerRule() method defines the first rule to execute and the 24
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing / //java proposals of interest /
around() method defines the subsequent rules. Listing 10 gives an example implementation that employs my previously created custom rule definition, the MyCustomRule class from Listing 9.
Listing 10. public class RuleChainTests { FEATURED JDK ENHANCEMENT PROPOSAL
@Rule public RuleChain chain = RuleChain.outerRule( JEP 259: Stack-Walking API new MyCustomRule("outer")) .around(new MyCustomRule("inner")); [JDK Enhancement Proposals (JEPs) are proposals that allow OpenJDK committers and other participants to come @Test together on a project that might eventually evolve into a public void ruleChainWorkedOK() { System.out.println("Test worked OK"); full-blown JSR. Having covered many JSRs in past issues of } Java Magazine, we’ll be looking at some of the more interest- } ing JEPs. —Ed.]
This is the execution output of the test class: JEP 259: Stack-Walking API proposes an API for walking the stack. The goal is that at any moment (although almost cer- outer before tainly during debugging), the API will enable a developer to inner before walk up or down the entire calling stack. As currently pro- Test worked OK posed, the API, which is intended to have only three principal inner after outer after methods, can locate a specific stack frame (based on filter parameters) and locate a caller’s stack frame. A possible addi- Conclusion tional method that would return a stream of stack frames has been proposed, although it’s not currently part of the JEP. It JUnit contains many options that facilitate testing. JUnit’s developers should be noted that the entire stack trace can be accessed via know that the framework is used for far more than unit testing. They’ve existing APIs, such as in . This provided numerous capabilities for running large test suites in various getStackTrace() Throwable JEP simply refines the access to specific stack frames. More ways, for customizing test runs, and for handling many of the minor information on the JEP can be found here. “busy” tasks that testing requires. Pay attention to new releases of JUnit for small additions that make automated testing easier.
LEARN MORE • A good tutorial on JUnit • JUnit Anti-Patterns 25
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing / Building and Automating a Functional Test Grid How to assemble a grid for Selenium testing NEIL MANVAR
BIO n July 9, 2015, Apple released Mac OS X El Capitan beta, You soon find that the matrix of browser types and versions Owhich offered significant new functionality. In this gets complicated quickly. Add the OS versions and configura- release, Apple introduced the mandate that all applications tions, Selenium versions, and individual browsers’ web driv- use SSL with a certificate that exceeds 1024-bit encryption. ers, and you suddenly have an unmanageably complex test Google Chrome has also launched an update that now flags all environment. This calls for automation. Without automation, SSL certificates that are from authorities not on the whitelist a testing grid provides only modest help to an organization. (that is, those that do not have public records) and certificates that use the (insecure) SHA-1 hash function. The Balance What does all this have to do with functional testing? When it comes to testing grids, the entire test suite should These seemingly innocuous changes will make users of be run against the top 80 percent of browsers used. This rule Safari and the latest update of Chrome question security, and is important, because testing on less common browsers has they could possibly raise some uncomfortable questions. The an effort cost that is greater than the impact of the poten- only way for IT organizations to spot these issues is by using tial issues that are found. The remaining browsers should be a strong and current functional testing grid. In this article, available for testing when specific issues arise, usually from I discuss how to set up your own testing grid for browser- some support request. The idea is to create a system where based apps using Selenium, the widely those browsers could be available for testing on demand. used open source testing tool. According to the online course site W3Schools, its traf- A testing fic shows that 97 percent of browser usage is shared among The Grid grid without Chrome, Firefox, Internet Explorer, and Safari, in that order. The idea of running manual tests on a Sites with a more business-oriented audience see a greater browser of a particular type and ver- automation ratio of Internet Explorer, especially older versions of the sion is straightforward. But applications provides only browser. This shows that it is hard to predict what combi- in the wild do not run on just one type modest help to nations of browser, version number, and operating system or version of a browser. No matter what releases a given application must be tested for browser your customers use, they expect an organization. The caveat to the 80-percent rule is effort cost. Most shops a quality experience. find that they don’t even have the ability to test the top 50 26
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
percent of browsers. The reason: Even the top 50 percent approach. To implement your testing environment, you will include a lot of variation when you add operating systems. need a virtual machine hypervisor or container. (From here (Most of the time, it ends up that only Chrome and Firefox are on, I will refer to all types of containers and virtual machines no more than two versions back.) as “VMs.”) To be most effective, the QA team needs access to You can safely say that to have a testing grid with approxi- VMs and the ability to control the provisioning of VMs. mately 80 percent testing coverage, you would need to have Before you start installing your browsers, you need to con- instances of Chrome C42 through C45, Firefox 37 through sider some very important questions, such as Firefox 40, Internet Explorer 9 through 11, and Safari S7 ■■ Should you put browser installations on the same VM? and S8 on Mac OS X 10.8 through 10.10, Microsoft Windows ■■ Should you use a new VM for each? 7 through 8.1 and XP, Debian, Ubuntu, CentOS, Red Hat, ■■ Should you use a new VM per group of browsers? Gentoo, Fedora, and SUSE—for a total of 226 combinations. As an example, putting all browsers on the same VM offers This really is not possible without a cloud-based solution. the benefit of bringing everything together in one place, An on-premises combination is usually Chrome C43 through thus making it easier to deploy and run automated scripts. C45, Firefox 38 through Firefox 40, Internet Explorer 9 However, it does not allow you to test against different ver- through 11, and Safari S7 and S8 running on Mac OS X 10.9, sions of the same browser type in parallel, and it increases Windows 7 and 8, and Debian. the risk of environmental variables that could affect func- When considering your grid, the team needs to keep cur- tionality, especially over time when reused. rent on the ecosystem. There are periodically some large Automation helps with infrastructure as well. Automation changes in the ecosystem. For example, some notable recent helps not only to run tests but also to provision the ideal and upcoming events are the launch of Mac OS X 10.11 and environment’s infrastructure. Usually, developers and QA Microsoft’s Edge browser in Windows 10, and engineers are hands-off when it comes to automation. This the end of Chrome support for Windows XP at approach is not always beneficial. It encourages an immu- The best the close of 2015. table infrastructure that is reused and contaminated, and it environment When teams set up testing in the cloud, ultimately limits the test grid variation mix and throttles is where every they can test even more-obscure browser the number of tests that can be run at any given moment in versions and types on demand. time. With cloud solutions, automation infrastructure does automated test The lowest common denominator of what not matter, because provisioning is the job of the QA-tailored automatically is possible is based on your organization’s testing solution. provisions a new infrastructure capabilities, and your QA There are three quality levels for environments: workable, team’s ability to use them. It is not one size good, and best. And it is not always possible to implement the VM, runs the test, fits all. ideal environment. and shares the Workable environments. In these environments, you provision results with the The Needed Infrastructure a hub VM once. It then acts as the Selenium Hub (formerly, Installing browsers on local machines pro- the Selenium Remote Control), which can distribute tests QA team. hibits flexible functional testing, and in the across your test nodes. Test nodes are also VMs that have world of automation, it is not a sustainable been provisioned once, and they house the actual browser 27
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
configurations. On the nodes, the client libraries run the tests Test Automation provided by the hub. Repeated tests are done automatically Using automation tools such as Selenium breaks teams free by rerunning the test suite from the hub. The system is only from the risk and limitations associated with manual testing. as strong as the weakest node, which means that because you Automation is far more scalable, can be run anytime without are repeatedly using the same infrastructure over time, the human intervention, and allows the expansion of test cases. risk of something breaking increases. But automation requires infrastructure and setup. The first Here is how you start the hub: step is to decide what you will test on—that is, the combina- tion of operating systems and browsers. Then you need to java -jar selenium-server-standalone-2.44.0.jar create a baseline infrastructure that the browsers will run on. -role hub And, finally, you need to wire up the automation processes with tools or direct API calls. Then start the node(s) connected to the hub:
java -jar selenium-server-standalone-2.44.0.jar Setup of Browser Grids -role node I recommend the following steps: -hub http://localhost:4444/grid/register 1. Select your host operating system(s). Most of the time, the operating system does not have a large impact on If you are creating a Selenium grid with many nodes, then browser functionality. The notable changes will be in for each node, you have to specify the hub: performance, because operating systems optimize the running of processes—as well as security—with new java -jar selenium-server-standalone-2.44.0.jar releases, as seen with the operating system releases -role node mentioned earlier. These releases typically don’t have a -hub http://
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
Updates to browsers and configurations will happen, // public static final String URL = and when they are completed, a new snapshot should // "http://localhost:4444/wd/hub"; be taken, creating an ever-expanding library of browser versions and types. public static void main(String[] args) throws Exception { 3. You now run the Selenium Hub and connect it to all the
running test nodes. You can initiate a test directly from DesiredCapabilities caps = the Selenium Hub. new DesiredCapabilities(); Always provision on a clean VM to avoid contamination and caps.setCapability( to create a history of snapshots, both of which are essential CapabilityType.BROWSER_NAME, "firefox"); for the versioning of your grid. The snapshots will allow you caps.setCapability( to go back to previous browser versions, if necessary, for sup- CapabilityType.VERSION, "37"); port reasons. caps.setCapability( CapabilityType.PLATFORM, "Windows 7");
Wiring up Test Automation WebDriver driver = Once you have the infrastructure, you need to wire up the new RemoteWebDriver(new URL(URL), caps); automation capability. Selenium is used to drive the tests. driver.get("http://www.amazon.com"); Listing 1 shows a basic example that will navigate the browser WebElement element = to a Google page and submit a query. A simple test might look driver.findElement( like this. By.name("field-keywords"));
Listing 1. element.sendKeys("Sauce Labs"); element.submit(); import org.openqa.selenium.By;
import org.openqa.selenium.Platform; System.out.println(driver.getTitle()); import org.openqa.selenium.WebDriver; driver.quit(); import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.*; } import java.net.URL; }
public class SampleSeleniumTest { public static final String USERNAME = The script is run on the same machine on which the System.getenv("USERNAME"); browser resides. Selenium has a large set of functions for public static final String ACCESS_KEY = finding and executing web applications. However, running System.getenv("ACCESS_KEY"); the test without results is useless. You also need to track data public static final String URL = on how the test ran. "http://
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
are creating the reporting element of your testing environ- But PASS, FAIL, and SKIP do not tell you a great deal about ment, you will need to programmatically collect this data and how and when a test failed. That is why it is best to report report it to an output of your choosing—commonly XML via other metadata such as timestamps, page elements, test case JUnit, HTML, or CSV with Microsoft Excel. However, there are names, and even stack traces—anything that will support tools that help with the depth of test reporting, with custom faster identification of the location of the error and assign- web-based dashboards built for reporting. This approach is ment of a ticket item to a developer. ideal, due to faster visuals, and it makes sharing data with the In addition to the various data elements you can collect, you team easier. should consider taking a screenshot of every exception and Below is a sample JUnit output generated by TestNG that failure, as shown in Listing 2. For extra credit, you can capture includes a failed test: video as well. This requires integration with video recording, which demands a lot of effort, but some cloud providers have this functionality built in.
Listing 2. catch(Exception e) { Assert.fail(); //To fail test in case of any //element identification failure }
and
public void takeScreenShotOnFailure( ITestResult testResult) throws IOException { if (testResult.getStatus() == ITestResult.FAILURE) { System.out.println( testResult.getStatus()); File scrFile = ((TakesScreenshot)driver) .getScreenshotAs(OutputType.FILE); FileUtils.copyFile( scrFile, new File("D:\\testScreenShot.jpg")); } }
30
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
By storing the screenshots in a location that is associated waste a lot of time. Don’t let the tools create the workflow with a build, application version, test run ID, and so on, you for you. can quickly focus only on the exceptions. It is also useful to tie these back to the elements being acted on at the time, so What to Be Aware Of that you can quickly reference your Selenium script and know Bear in mind the following concerns: what test was being run. ■■ On-premises testing. Choosing to maintain the testing infrastructure in-house is naturally limiting. For small, Best Practices manual testing, it works fine. But when automation picks Once you set up your test grid and begin using it, you’ll up, it is usually necessary to turn to cloud infrastructure quickly find that certain basic best practices will go a long and automated tools, ranging from provisioning to running way to giving you the results you need. These practices tests on new instances. include the following: ■■ Testing on the Mac OS. Testing on the Mac OS is not simple. ■■ Avoid contamination. System-level bugs are the hardest The primary reason is licensing. In order to comply with to track down. And the likelihood of having system-level Mac OS X licensing, you need to test on a physical Mac. You issues when reusing VMs is incrementally higher with each can virtualize, but when you do, the VM also has to be on a test run. (It cannot be overstated that you should use a new physical Mac. VM for each test run.) ■■ Mobile testing. Mobile testing and mobile applications ■■ Establish consistent naming conventions. As the number of are coming into play rapidly—faster than the estab- test cases increases, the management of the entire library lished methods for testing. It can feel like the Wild West. becomes more complex. Using a consistent naming con- However, many tools are already available, such as Appium, vention for tests (for example, tying them to the appli- which will allow Selenium-style automated testing on cation name and release) will help substantially when it emulators. (A lot of the elements are the same as with web comes time to cull unneeded tests or rerun old tests for application testing, but the testing grid size is multiplied issues that resurface. nearly by four.) ■■ Ensure test results are not stored on VMs directly. Reporting is key. In order to build in autonomy and support testing on Conclusion a new VM with each test run, make sure all the processes If you are not doing automated testing on a functional test store test results and screenshots grid today, you will be soon—so it is important to think about in a centralized location. If you are not doing how you will set up the process. On-demand setup of a test- ■■ Build a workflow for exceptions. ing grid most often results in something that is not sustain- Beyond video and screenshots, automated testing able and doesn’t leverage all the possibilities of automation. building an entire workflow for on a functional test Today, however, you do not always need to worry about infra- exceptions is recommended. Some grid today, you will structure. QA teams can actually take over the infrastruc- teams take automation too far and ture. Teams can elect to use cloud-based testing, and then have all exceptions go directly be soon. spend most of their time writing test cases and building into tickets. But the false positives test strategies. 31
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //from the vault / Stress Testing Java EE Applications Identify application server configuration problems, potential bottlenecks, synchronization bugs, and memory leaks in Java EE code.
ADAM BIEN nit and integration tests are helpful for the identifica- Instead of applying optimizations prematurely, you should BIO Ution of business logic bugs, but in the context of Java EE 6 concentrate on implementing pure business logic and and later, they are meaningless. Both integration and unit verifying the expected behavior with automated tests and tests access your application in a single-threaded way. After hard numbers. the deployment, however, your code will always be executed concurrently. Don’t Be Realistic Load tests are configured by taking into account the expected Stop Talking, Start Stressing number of concurrent users and realistic user behavior. To It is impossible to predict all nontrivial bottlenecks, dead- meet the requirements, “think times” need to be kept real- locks, and potential memory leaks by having theoretical dis- istic, which in turn reduces the amount of concurrency in cussions. It is also impossible to find memory leaks with unit the system. The heavier the load, the easier it is to find prob- and integration tests. Bottlenecks are caused by locks and I/O lems. Realistic load tests are usually performed too late in problems that are hard to identify in a single-threaded sce- the development cycle and are useful only for ensuring that nario. With lots of luck and patience, memory leaks can be nonfunctional requirements are met. They are less valuable identified with an integration test, but they can be far more in verifying system correctness. easily spotted under massive load. The heavier the load, the Instead of relying on realistic but lax load tests defined greater is the probability of spotting potential concurrency by domain experts, we should utilize as much load as pos- and robustness problems. Cache behavior, the frequency of sible using developer-driven stress tests. The goal is not to Java Persistence API (JPA) OptimisticLockException, and verify expected scalability or performance. Instead, it is to the amount of memory needed in production can also be find defects, of course, and to learn about the behavior of the evaluated easily with stress tests. system under load. Even in the unlikely case of a perfect application without defects, your application server will typically be unable to Stressing the Oracle handle the load using default factory settings. Stress tests are My “oracle” application records predictions and returns them a perfect tool to learn the behavior of your application under as a JavaScript Object Notation (JSON) string. (For more infor- PHOTOGRAPH BY load in the first iterations without any stress. Stress-test- mation on the “oracle” application, see “Unit Testing for THOMAS EINBERGER/ GETTY IMAGES driven development is a good choice for Java EE. Java EE”.) 32
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //from the vault /
Sending a GET request to the URI http://localhost:8080/ oracle/resources/predictions returns a Prediction entity serialized as: {"prediction": {"result": "JAVA_IS_DEAD", "predictionDate": "1970-01-01T19:57:39+01:00", "success":"false"} Figure 1. HTTP request configuration in JMeter }. Services provided by Java API for RESTful Web Services (JAX-RS) are easily stress-testable; you need only execute several HTTP requests concurrently. The open source load-testing tool Apache JMeter comes with built-in HTTP support. After creating the ThreadGroup and setting the number of threads (and, thus, concurrent Figure 2. JMeter Summary Report users), an HTTP request has to be configured to execute the GET requests (right-click, select Sampler, and then select HTTP Request). See Figure 1. While the results can be visualized in various ways, the JMeter Summary Report is a good start (see Figure 2). It turns out that the sample application is able to handle 1,700 trans- actions per second for five concurrent users “out of the box.” Every request is a true transaction and is processed by an Enterprise JavaBeans 3.1 (EJB 3.1) JAX-RS Prediction ArchiveResource, delegated to the PredictionAudit EJB 3.1 bean, which in turn accesses the database through EntityManager (with exactly one record). At this point, we have learned only that with EJB 3.1, JPA 2, and JAX-RS, we can achieve 1,700 transactions per second without any optimization. But we still have no idea what is happening under the hood.
VisualVM Turns Night to Day GlassFish Server Open Source Edition 3.1.x and Java DB (the open source version of Apache Derby) are Java processes that Figure 3. VisualVM CPU and memory monitoring overview can be easily monitored with VisualVM. Although VisualVM is 33
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //from the vault /
shipped with the current JDK, you should check the VisualVM load generators to the cloud. Website for updates. In a stress-test scenario, the plain numbers are interesting VisualVM is able to connect locally or remotely to a Java but unimportant. Stress tests do not generate a realistic load process and monitor it. VisualVM provides an overview but, rather, they try to break the system. To ensure stability, showing CPU load, memory consumption, number of loaded you should monitor the VisualVM Overview average values. classes, and number of threads, as shown in Figure 3. All the lines should be, on average, flat. The overview is great for estimating resource consump- An increasing number of loaded classes might indi- tion and monitoring the overall stability of the system. We cate problems with class loading and can lead to an learn from Figure 3 that for 1,700 transactions per second, OutOfMemoryError due to a shortage of PermGen space. An GlassFish Server Open Source Edition 3.1 needs 58 MB for the increasing number of threads indicates slow, asynchronous heap, 67 threads, and about 50 percent of the CPU. The other methods. A ThreadPool configured with an unbounded 50 percent was consumed by the load generator (JMeter). number of threads will also lead to an OutOfMemoryError. Although this colocation is adequate for the purposes of And a steady increase in memory consumption can eventually this article, it blurs the results. The load generator should lead to an OutOfMemoryError caused by memory leaks. run on a dedicated machine or at least in an isolated (virtual) VisualVM comes with an interesting profiling tool called environment. Sometimes, you even have to run distributed Sampler. You can attach and detach to a running Java process JMeter load tests to generate enough load to stress the server. with a little overhead and measure the most expensive invo- For internet applications, it might be necessary to deploy the cations or the size of objects (see Figure 4). The sampling overhead is about 20 percent, so with an active sampler, you can still achieve 1400 transactions per second. As expected, the application spends the largest amount of time communicating with the database.
How Expensive Is System.out.println? A single System.out.println can lead to significant per- formance degradation. To measure the overhead, every invocation of the method allPredictions is logged with a System.out.println invocation, as shown in Listing 1.
Listing 1. public List
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //from the vault /
Instead of 1,700 transactions per second, the insertion of this simple print command has reduced our performance to about 800 transactions per second, as shown in Figure 5. Figure 5. Performance degradation of 50 percent Let’s take a look at the VisualVM Sampler output shown in Figure 6. More time is spent in ThreadPrintStream .println() than in the most expensive database operation. The actual EJB 3.1 overhead is negligible. The call to $Proxy285.allPredictions() is in the very last posi- tion and orders of magnitude faster than a single System.out.println. Having a reference measurement makes identification of potential bottlenecks easy. You should perform stress tests as often as possible and compare the results. Performing nightly stress tests from the very first iteration is desirable. You will get fresh results each morning so you can start fix- ing potential bottlenecks.
Figure 6. CPU Sampler with System.out.println Causing More Trouble Misconfigured application servers are a common cause of bottlenecks. GlassFish Server Open Source Edition 3.1 comes with reasonable settings, so we can reduce the maximum Figure 7. Performance after reducing the pool size number of connections from the Derby pool to two connec- tions to simulate a bottleneck. With five concurrent threads (users) and only two database connections, there should be some contention (see Figure 7). The performance is still surprisingly good. We get 1.400 transactions per second with two connections. The max response time went up to 60 seconds, which correlates sur- prisingly well with the “Max Wait Time: 60000 ms” connec- tion pool setting in GlassFish Server Open Source Edition 3.1. A hint in the log files also points to the problem, as shown in Listing 2.
Listing 2. WARNING: RAR5117 : Failed to obtain/create connec- tion from connection pool [ SamplePool ]. Reason : Figure 8. Sampler output with two connections in the pool 35
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //from the vault /
com.sun.appserv.connectors.internal.api.Pooling- DataSource dataSource = getDataSource(); Exception: In-use connections equal max-pool-size try{ and expired max-wait-time. Cannot allocate more ... connections. return dataSource. getConnection(user, password); WARNING: RAR5114 : Error allocating connection : } catch (SQLException exception) { [Error in allocating a connection. Cause: In-use throw DatabaseException.sqlException( connections equal max-pool-size and expired max- exception, true); wait-time. Cannot allocate more connections.] } } Also interesting is the Sampler view in VisualVM (see Figure 8). How to Get the Interesting Stuff The method JNDIConnector.connect() became the The combination of JMeter and VisualVM is useful for ad hoc most expensive method. It even displaced the Reply.fill() measurements. In real-world projects, stress tests should be method from its first rank. not only repeatable but also comparable. A history of results The package org.eclipse.persistence is the JPA pro- with visualization makes the resultant comparison and iden- vider for GlassFish Server Open Source Edition 3.1, so it tification of hotspots easier. should give us a hint about the bottleneck’s location. There is VisualVM provides a good overview, but the really interest- nothing wrong with the persistence layer; it only has to wait ing monitoring information can be obtained only from an for a free connection. This contention is caused by the arti- application server in a proprietary way. All major application ficial limitation of having only two connections available for servers provide extensive monitoring information via Java five virtual users. Management Extensions (JMX). A look at the JNDIConnector.connect method con- You can easily GlassFish Server Open Source firms our suspicion (see Listing 3). In the method Edition 3.1 exposes its monitoring JNDIConnect.connect, a connection is acquired from a persist monitoring and management data through an DataSource. In the case of an empty pool, the method will data with a easily accessible REST interface. block until either an in-use connection becomes free or simple Java EE 6 To activate the monitoring, open the Max Wait Time is reached. The method can block up to the GlassFish Admin Console by 60 seconds with the GlassFish Server Open Source Edition application. JPA 2, specifying the Admin Console default settings. This rarely happens with the default set- EJB 3.1, Contexts URL (http://localhost:4848). Then tings, because the server ships with a Maximum Pool Size of and Dependency select Server, select Monitor, and 32 database connections. then select Configure Monitoring. Injection, and JAX-RS Then select the HIGH level for all Listing 3. reduce the task to components. Alternatively, you can public Connection connect(Properties properties) activate monitoring by using the throws DatabaseException, ValidationException { only three classes. asadmin command from the com- .String user = properties.getProperty("user"); 36
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //from the vault /
mand line or by using the REST management interface. the data has to be persistently stored. A periodic snapshot Now, all the monitoring information is accessible from the between 1 and 30 seconds is good enough for smoke tests and following root URI: http://localhost:4848/monitoring/domain/ stress tests. server. The interface is self-explanatory. You can navigate It turns out that you can easily persist monitoring data with through the components from a browser or from the com- a simple Java EE 6 application. JPA 2, EJB 3.1, Contexts and mand line. Dependency Injection (CDI), and JAX-RS reduce the task to The command curl -H "Accept: application/json" only three classes. The JPA 2 entity Snapshot holds the rel- http://localhost:4848/monitoring/domain/server/ evant monitoring data (see Listing 5). jvm/memory/usedheapsize-count returns the current heap size formatted as a JSON object (see Listing 4). Listing 5. @XmlAccessorType(XmlAccessType.FIELD) Listing 4. @XmlRootElement {"message":"", @Entity "command":"Monitoring Data", public class Snapshot { "exit_code":"SUCCESS", @Id "extraProperties":{ @GeneratedValue "entity":{ private long id; "usedheapsize-count":{ @Temporal(TemporalType.TIME) "count":217666480, private Date monitoringTime; "lastsampletime":1308569037982, //...field declarations omitted "description": "Amount of used memory in bytes", public Snapshot(long usedHeapSize, "unit":"bytes", int threadCount, int totalErrors, "name":"UsedHeapSize", int currentThreadBusy, int committedTX, "starttime":1308504654922} int rolledBackTX, int queuedConnections) { }, this(); "childResources":{}} this.usedHeapSize = usedHeapSize; }. //... } The most interesting key is usedheapsize-count. It con- public Snapshot() { tains the amount of used memory in bytes, as described by this.monitoringTime = new Date(); the description tag. The good news is that the entire moni- } toring API relies on the same structure and can be accessed in } a generic way. The entity Snapshot represents the interesting data, such Monitoring Java EE 6 with Java EE 6 as the number of busy threads, queuedConnections, errors, Executing HTTP GET requests from the command line still committed and rolled-back transactions, heap size, and the does not solve the challenge. In order to be comparable, time stamp. You can extract such information from any other 37
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //from the vault /
application server through different channels and APIs. //other accessors omitted Listing 6 shows how to access REST services with Jersey. The managed bean DataProvider uses the Jersey client to access long getLong(String uri,String name) the GlassFish Server Open Source Edition’s REST interface and throws JSONException{ ClientResponse result = convert the JSON result into Java primitives. The fetchData client.resource(uri) method is the core functionality of DataProvider, and it .accept(MediaType.APPLICATION_JSON) returns the populated Snapshot entity. .get(ClientResponse.class); return getJSONObject(result,name) Listing 6. .getLong("count"); public class DataProvider { } public static final String BASE_URL = "http://localhost:4848" + //accessors omitted "/monitoring/domain/server/"; public static final String HEAP_SIZE = JSONObject getJSONObject( "jvm/memory/usedheapsize-count"; ClientResponse result,String name) private Client client; throws JSONException { JSONObject response = public Snapshot fetchData(){ result.getEntity(JSONObject.class); try { return response.getJSONObject( long usedHeapSize = usedHeapSize(); "extraProperties") //… other assignments omitted .getJSONObject("entity") return new Snapshot( .getJSONObject(name); usedHeapSize, threadCount, } totalErrors, currentThreadBusy, } committedTX, rolledBackTX, queuedConnections); Every five seconds, the MonitoringController } catch (JSONException e) { @Singleton EJB 3.1 bean shown in Listing 7 asks the throw new IllegalStateException( "Cannot fetch monitoring" + DataProvider for a Snapshot and persists it. In addition, "data because of: " + e); the persisted data is exposed through REST. You can access } all snapshots using http://localhost:8080/stm/resources/ } snapshots, and you will get Snapshot instances as a JSON object (see Listing 8). long usedHeapSize() throws JSONException{ final String uri = BASE_URL + HEAP_SIZE; Listing 7. return getLong(uri,"usedheapsize-count"); @Singleton } @Path("snapshots") @Produces(MediaType.APPLICATION_JSON) public class MonitoringController { 38
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //from the vault /
@Inject "queuedConnections":"0"}, DataProvider dataProvider; {"id":"2", @PersistenceContext "monitoringTime":"1970-01-01T10:50:35+01:00", EntityManager em; "usedHeapSize":"160421672", @Schedule(minute="*",second="*/5",hour="*") "threadCount":"131", public void gatherAndPersist(){ "totalErrors":"4", Snapshot current = "currentThreadBusy":"-1", dataProvider.fetchData(); "committedTX":"23", em.persist(current); "rolledBackTX":"2", } "queuedConnections":"0" @GET }] public List
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //from the vault /
asadmin deploy --force […]/StressTestMonitor.war. You will get the number of concurrent requests, the cur- rent number of active instances (and, thus, the number JMeter can also be started without the GUI in head- of concurrent transactions accessing the bean), and busi- less mode. It requires another line: jmeter -n -t ness method runtime statistics, such as slowest and average predictions.jmx -l predictions.jtl. The parameter execution times. -n prevents the GUI from appearing, the parameter -t speci- For example, PredictionAudit EJB bean pool data is fies the configuration file (created with JMeter in GUI mode), accessible under http://localhost:4848/monitoring/ and -l specifies the log file, which can be analyzed with domain/server/applications/com.abien_TestingEJBAndCDI JMeter after the test. .war_1.0-SNAPSHOT/PredictionAudit/bean-pool. A Hudson or Jenkins “Free Style Because of JSR 77 All the monitoring data is stored in a single table, which Software Project” build with two makes the data available to tools such as JasperReports and build steps (Execute Windows Shell (the management Eclipse BIRT. Charts and reports are only a few clicks away. Command or Execute Shell) does and monitoring API), The Snapshot entity is exposed through JSON, which makes the job: Deploy STM and Execute all application it “consumable” by all JavaScript and JavaFX applications Stress Tests. You don’t need to as well. create a shell script or a batch file. servers also Furthermore, the Snapshot entity is a Java class and can The commands can be executed provide access to contain additional validation or processing logic. It is trivial directly by Hudson or Jenkins. the statistics of all to escalate “suspicious” Snapshot instances with CDI events, VisualVM can still be used to as shown in Listing 9. monitor the application in real deployed Java EE time or identify the hot spots. components. Listing 9. All the relevant monitoring data @Inject is persisted in a database table Event
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //from the vault /
Conclusion: No Excuses Java EE 6+ applications are always executed concurrently. Even with unrealistic stress tests, you will learn a lot about Prove Your system behavior and identify some bottlenecks or concur- rency bugs. The earlier and more frequently stress tests are executed, the more you will learn about the application’s runtime Tech Creds behavior. Application server configuration problems, poten- tial bottlenecks, synchronization bugs, and memory leaks can be also identified during stress tests. Get Java Certified
[This article first appeared in this magazine in the November/ December 2011 issue and has since been updated. —Ed.] Save up to 20%
Get noticed by hiring managers
Learn from Java experts
Join online or in the classroom
96% of participants recommend it
100% report promotions, raises, and more
LEARN MORE • Real World Java EE Night Hacks: Dissecting the Business Tier • Sample Java EE testing code on Project Kenai web page • StressTestMonitoring application • “Unit Testing for Java EE” • JSR 77 41
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing / Think Like a Tester and Get Rid of QA Atlassian’s developers are required to formulate tests before they code and after. MARK HRYNCZAK QA is there to help—but not test.
BIO ne of the best practices of modern software develop- We start the workshop by explaining that the whole team is Oment is to actively involve developers in software testing. responsible for quality. For developers, owning quality means This practice mirrors the trend driven by DevOps of involving that they should think about error cases, security vulnerabili- developers intimately with operations. However, some orga- ties, and nonstandard user scenarios before they start coding. nizations, such as the one I work in, are making developers We explain why good automation is important but insuffi- take on almost all the testing—a move that has proven suc- cient, and promote exploratory testing as a technique to find cessful and redefined the role of QA. I work at Atlassian, and problems efficiently. here QA stands for quality assistance rather than quality assur- Some developers have a preconception that exploratory ance. The QA team is not able to test everything and does not testing means manual scripted testing, which is tedious, aim to. Testing activities are mainly carried out by developers, low-value, and as a rule should never be done by a human while QA engineers focus on teaching developers the skills to (because it can be automated). effectively and efficiently test software. We also steer developers away from what we call “ad hoc In this article, I discuss the techniques we use to train testing”—that is, mindlessly clicking around the UI in the developers, and how you can start thinking like a tester, too. hope that bugs will just appear. The approach we recommend is anything but mindless. Exploratory testing involves think- Testing from Day 1 ing critically about the feature you are testing, and finding New developers joining our company are put through “boot problems by identifying specific valid risks. camp”—a series of classes that get them up to speed as The second half of the workshop invites attendees to give quickly as possible. Members of the QA team run a class exploratory testing a try on a real feature, with QA guidance entitled “Exploratory Testing Workshop for Developers.” to avoid the mindless-clicking-around trap. Generally, we The content is aimed at new hires, who might not have been need to give hints like these: expected to perform their own testing previously. More- ■■ Don’t test the “happy path.” Instead, think about what experienced developers are always welcome to use the class might not work and what should not work (such as users with as a refresher. The goal is to teach developers how to use and without expected permissions, or conflicting concur- manual testing effectively and deliver high-quality features. rent actions on a multiuser system). 42
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
■■ Use challenging data input, and avoid relying on provided enable the original developers to reliably test their own work. defaults and demo content (such as overly long text, char- Use of a DoT is an interim step toward this end goal, because acters from non-English alphabets, or XSS strings). having two people performing testing on a single story is ■■ Think about the implementation choices that were made, ultimately inefficient. and the risks they imply (such as inefficient queries on When developers take on a DoT role for the first time, they massive data sets, or Ajax requests on an expired session). need to shift away from a code-centric view of a story and ■■ Imagine ways users might ask the feature to do something take on an end-user mindset. So we give them some tips: unexpected (such as spoofing other users, or using REST Feature exploration. API endpoints to access content they should not access). ■■ Set a time limit to explore most of the functionality rel- ■■ Remember that a UI isn’t necessary for exploratory testing evant to the story. (you can find problems by theorizing without touching your ■■ Focus on exploration and familiarization. computer—even before code has been written). Quick attacks. Initially, developers often do a poor job of testing due to ■■ Use known problematic input wherever data input is inexperience. But as exploratory testing becomes part of their required or data is displayed. routine, they learn to think from a new perspective and iden- ■■ Check the well-known problematic cases whenever there tifying risks becomes second nature. are commonly used elements such as lists, trees, sessions, or permissions. Story-Level Testing ■■ Establish a time limit for the activity to make sure you have Known internally as Developer on Test (DoT), we set up the enough time left for more-diligent attempts to test the team’s workflow so that when one developer finishes imple- feature. menting a story, another developer, the DoT, verifies that it 20 percent use case. meets the team’s quality requirements. The DoT is the gate- ■■ Think about what could go wrong and affect the feature’s keeper for that story—once the gatekeeper is satisfied, the functionality. code goes into production. ■■ Consider user, product, and environment. When starting off with a new We are careful not ■■ Avoid the happy path. team, the process of DoT validation Heuristics. is a good way to introduce develop- to simply produce ■■ Do some modeling and analysis to generate ideas that ers to the idea that they can—and checklists that are not immediately obvious for what and how to test. must—be able to test. We might start can be mindlessly Heuristics will help you. them on simple stories, leaving the ■■ Identify any values that can change in a feature and the more-complex ones to QA engineers. followed. The interaction between them. Or we might provide QA pairing aim is to get the QA can provide resources to help a DoT with the above by sessions to get them up to speed. In developers to providing a catalog of known problematic input or a list of both cases, the long-term goal is to proven valuable heuristics, for example. But we are careful get the team to a level where both think like testers. not to simply produce checklists that can be mindlessly fol- skill and confidence in testing can lowed. The aim is to get the developers to think like testers, 43
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing /
after all. This can be presented as developers are aware of edge cases and potential problems, a challenge: Assume that problems As the team matures, they can code and test to mitigate them rather than rework- exist, and keep searching until you developers no longer ing to fix them. find them. depend on the QA The outcome of the kickoff is a set of testing notes, which We measure the effectiveness of developers can use to determine when the story is done. Once the team’s quality process by two engineer being they are confident, the story can be shipped. Voilà! We have important metrics: the ratio of available for removed the need for an additional testing step. successful stories (those that did every discussion. The format of kickoffs and testing notes varies according to not result in a shipped bug) and the context, but here are some common elements: the ratio of rejected stories (those Specific risks. What are the critical areas that must work? where the DoT found an issue Which are the parts most likely not to work? What needs to be before shipping) to total stories. tested thoroughly? Obviously, we want the first metric to be trending toward Test ideas. What user scenarios should be covered? What 100 percent. If we are shipping problems to production, then should be automated? What level of automation is appropri- the DoT has not done a good job. QA’s focus is on improving ate? What needs to be checked manually? that with more workshops, more pairing, and so on. Notes. A kickoff often raises a lot of questions and details Once the team is reaching the quality bar on nearly all sto- that do not form coherent test ideas but still are good to jot ries, the second metric is of particular interest. The DoT adds down at this point—for example, in-product analytics, fea- value by rejecting stories that aren’t up to par, but rejections ture discoverability and accessibility, and so on. are an inefficiency in the process. We want the rejection rate Again, we use metrics to validate that the kickoff process is to trend toward zero. Ultimately, we want to remove the DoT achieving the quality goals of the team. As the team matures, step and have the original developer deliver high quality on developers can take on both roles in a QA kickoff—they no the first go, not after someone else has pointed out problems. longer depend on the QA engineer being available for every discussion on every story. Precoding Test Thinking As the team matures, we focus more on prevention rather The Big Picture than detection. This means removing the DoT step—often As a team succeeds with the processes described previously, against the wishes of the team, who come to see it as a safety the developers take on more of the testing activities, while net. We replace the postcoding DoT step by a precoding step the QA engineer takes on less. You might wonder what QA we call a QA kickoff: the developers talk a QA engineer through can do with all that free time. A high-performing team of the story, explaining what they plan to implement. Together developers means that QA can focus on big-picture quality the developer and QA engineer brainstorm test ideas, possible improvements. Here are some examples: risks, and anything else related to the story. Scale. We can increase the number of developers for whom Typically, the QA engineer asks lots of questions, such as, a single QA engineer can provide value. At Atlassian, for “What happens when you do X? What if we move Y to Z and example, the ratio is often between 1:10 and 1:20. then back again?” This discussion adds huge value. When Knowledge. We can look ahead to see how the team can 44
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //testing / //user groups /
meet customer needs better, and teach that to the whole team through the kickoffs. THE VIRTUAL JUG Innovation. We can experiment with process changes and measure their impact. The Virtual JUG (vJUG) is an online-only Java user group with Tools. We can identify ways to make testing easier for a global audience in more than 100 countries. It is now 18 developers. For example, the Atlassian QA team built an months old and already has more than 3,500 members. To date, Amazon EC2 service that provides quick and easy access it has hosted 39 online ses- to any supported browser for testing and troubleshooting. sions and runs at least two sessions every month, as Results well as a monthly podcast. We’ve had great results with these techniques. They have The most popular live enabled the QA function to scale effectively with a rapidly sessions have included growing development team; individual QA engineers have one by Java creator successfully innovated and multiplied their value; and we James Gosling on his have rendered obsolete much of the tedious busy work that is new Wave Glider proj- accepted as a necessary evil of the traditional QA role. ect, and a deep tech ses- But perhaps most importantly, the team of (often skepti- sion on the Java memory cal) developers has enthusiastically accepted these changes. model with Oracle’s Aleksey Shipilëёv. The most watched We’ve given them confidence that they can test their own session in the vJUG’s short history is a look at 55 new fea- work, deliver it to a measurable high standard, and make tures in Java 8 by Simon Ritter, who heads Java Technology efficiency savings that increase the team’s velocity without Evangelism at Oracle. Sessions can be watched live or in sacrificing quality. Internal surveys about the process and the replay at http://virtualjug.com. All of our speakers are team consistently show this. interviewed after their sessions to talk about what makes If you are a developer who currently relies on a traditional them tick and to answer many probing and sometimes testing phase to catch the bugs that you produce, you should uncomfortable questions. question whether this is a satisfactory state of affairs. Which The vJUG has created a couple of new initiatives in 2015, statement matches your mindset? “I’m a good developer; I including a new podcast called the Java Council. Its goal is to don’t need to test” or “Developers are not good developers fill the gap left by the Java Posse, which ended in 2014. unless they can also test.” Another new initiative this year is the vJUG book club, which coordinates the worldwide reading of a chosen book, a review, and a discussion over several vJUG sessions. The sub- LEARN MORE ject of the book could be anything from a deep look at tech- • Further details on the Atlassian process (by the same nology to time management. The first book will be Effective author) Java, Second Edition by Joshua Bloch. Which book will be next? • “The Day the QA Died” (another view of the same The great thing is the community will decide! If you want to be part of a unique online JUG, visit us. transition) 45
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //jvm languages / Kotlin: A Low-Ceremony, High-Integration Language Work with a statically typed, low-ceremony language that provides first-class functions, nullability HADI HARIRI protections, and complete integration with existing Java libraries.
BIO t has been more than five years since Project Kotlin, an aspects in our decision, so we opted not to go with Scala. Thus Iopen source language targeting the JVM, was announced by was born Project Kotlin. JetBrains. Since then, much progress has been made, some Shortly afterward, news about the JVM language Ceylon language designs have changed, a new platform—namely was announced; and at one point we considered joining JavaScript—is now supported, and even the project name has efforts. However, at the time, Ceylon’s focus on interoper- changed. It’s now simply known as Kotlin. But if there’s one ability was somewhat of a low priority. Given that we have a thing that still remains, it is the initial goals and intent for large codebase in Java, being able to use and extend it was of why Kotlin was developed. considerable importance to us. Thus, we decided to continue At JetBrains, we have been developing IDEs for many pro- down our own path with Kotlin. gramming languages, and yet despite this, much of our code continues to be written in Java. In 2009, we were looking for Removing the Pain an alternative to Java, something that could reduce the size Five years later and close to reaching the 1.0 milestone, of our codebase by being more concise and, at the same time, Kotlin remains true to its initial goals of being concise, safe, offer features that we felt could provide important benefits. interoperable, “toolable,” and performant. Many, if not all, of We needed a language that these goals are for a single purpose: removing some of the was also syntactically similar pain and the errors we encounter when writing code. enough to Java that ramp-up One of Kotlin’s goals The IntelliJ platform is an extremely large codebase on time would not be substan- is to reduce the which all our IDEs, including IntelliJ IDEA, are built. The tial. The main contender at the open source Community Edition alone, which is hosted on time was Scala, but the com- amount of somewhat GitHub, has millions of lines of code. While there is a lot of piler performance wasn’t that pointless code yet functionality, much of the code is often boilerplate code that great and providing tooling for maintain readability and is necessary because, well, because it’s Java. One of Kotlin’s Scala was (and continues to be) goals has been to reduce the amount of somewhat pointless quite challenging. Tooling and functionality. code yet maintain readability and functionality. For instance, performance were important a typical Java bean with property getters, setters, toString, 46
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //jvm languages /
and equality in Kotlin can be reduced to the following: fun toSentenceCase(input: String) { . . . data class Customer( } var name: String, var email: String) Much like C#, Kotlin also allows extension functions, Things such as smart-casting remove the need for verbos- meaning a type (either of Java or Kotlin) can be extended ity by delegating the work to the compiler. For example, when with new functionality simply by suffixing the type. Taking checking an immutable value for a specific type, it’s no longer the previous example, if I want the String type to have necessary to cast to that type when operating on it: toSentenceCase(), I can simply write the following:
fun convert(obj: Shape) { fun String.toSentenceCase() { if (obj is Circle) { ... // 'this' would hold an val radius = obj.radius() // instance of the object ... } } } To work efficiently with functions as primitives, there needs to be support for higher-order functions—that is, Kotlin also has support for named objects, which, in essence, functions that take functions as parameters or return func- means a singleton would simply be written as follows: tions. With Kotlin, this is possible, for example:
val MySingleton = object { fun operate(x: Int, y: Int, val numberOfDays = 10 operation: (Int, Int) -> Int) { } ... } Another pain point Kotlin addresses is the need to use functional constructs—such as lambda expressions and This code declares a function that takes three parameters: higher-order functions—and to treat functions as first-class two integers and a third parameter that is a function that, in citizens. While Java 8 addresses some of these concerns, turn, takes two integers and returns an integer. We can then our goal was and continues to be to provide this functional- invoke functions as follows: ity when using Java 6, 7, or 8—thus, even allowing support for these features on the Android platform. This is one rea- fun sum(x: Int, y: Int) { son that Kotlin has enjoyed considerable popularity in the . . . Android development community. } Functions can be top-level in Kotlin, much like they are in operate(2, 3, ::sum) JavaScript, meaning there’s no need to attach a function to an object. As such, we could simply declare a function in a file This code shows a function, sum, being defined and passed like this: as a parameter to operate. It shows that Kotlin supports ref- 47
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //jvm languages /
erencing functions by name. Of course, a lambda expression file only if file were not null. The standard library, a small can be passed in as well: runtime that ships with Kotlin, also provides additional func- tions in this area, such as the let function, which when operate(2, 3, { x, y -> x +y }) combined with the safe call operator allows for succinct code, such as the following: These capabilities deliver an elegant way of doing function pipelining: obj?.let { ... // execute code here val numbers = 1..100 }
numbers.filter { it % 2 == 0 } This results in the code .map { it + 5 } block executing if the object is .forEach { not null. Kotlin has the ability println(it) } One last thing worth men- to easily create tioning about Kotlin is its abil- DSLs—without the One more issue we attack with Kotlin is null pointer excep- ity to easily enable the creation tions. In Kotlin, by default, things cannot be null, meaning of DSLs—without the overhead overhead that necessarily that potentially the only way we’d get a null reference excep- that necessarily comes with comes with maintaining tion would be if we explicitly force it. maintaining them or the lan- guage knowledge required to them or the language var city = "London" implement them. Top-level knowledge required to functions, higher-order func- implement them. In the code above, city could never be assigned a null tions, extension functions, and value. If we want it to be null, we need to go out of our way to a few conventions, such as not be explicit: having to use brackets when the last parameter to a function is another function—these var city : String? = null features allow for creating rich DSLs that are strongly typed. The quintessential example is that of type-safe Groovy- where ? indicates that a type can be nullable. When interop- style builders. The following function generates the expected erating with Java, we provide certain mechanisms to warn of HTML output: possible null references, as well as providing some operators to make the code more concise, such as the safe call operator: html { head { var file = File("...") title {+"XML encoding with Kotlin"} file?.length() } body { Because of the ?., this code would invoke length() on h1 {+"XML encoding with Kotlin"} 48
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //jvm languages /
p {+"this is an alternative markup to XML"} ily migrate code to newer syntax. We believe that this way, } we create a smooth experience for developers that are already } using Kotlin in production. Beyond these quick fixes, we’re also focusing on improving Growth and the Road Ahead other aspects of tooling. For Kotlin to be successful, the entry The previous code snippets are just a few examples of what barrier should be low in all aspects. That is why we not only Kotlin provides. It wouldn’t be possible to cover all the little provide tooling for IntelliJ IDEA, in both Ultimate and the details and conveniences Kotlin offers in a single article. open source Community Edition, but also for build tools such Over the past year, and despite not having released ver- as Gradle, Ant, and Maven, as well as a simple command-line sion 1.0, we’ve noticed a substantial growth and interest in compiler. We’ve also released a preliminary version of Kotlin Kotlin. There has been an increase in downloads and visits to for Eclipse, and we’re hoping that much like there are contri- the Kotlin site, as well as an increase in technical questions in butions to Kotlin in other areas, the community will contrib- both our forums and public venues such as StackOverflow. ute to Eclipse support as well. While a lot of this interest is due to the Android com- munity and our contributions in terms of additional tool- Conclusion ing and frameworks for this space, there’s also interest in In conclusion, we developed Kotlin for our own use primar- other more generic areas such as web development, both ily and are heavily invested in it. For us, it’s a tool that we’re client-side (given Kotlin’s ability to compile to JavaScript) and using to drive our own business, which is developer tools. We server-side. already have several internal and public-facing web applica- We’re close to reaching the first major release, and we’ve tions written in Kotlin. Some of our newer tools are being made significant steps toward that. Over the past few mile- written in Kotlin and our existing tools, such as IntelliJ IDEA stone releases, we’ve been removing and adjusting some and YouTrack, are adopting Kotlin. things in the language to make sure that once we release, we’ll be fairly certain that what we Some of our ship is there to stay. As any language [This article is the inaugural installment of a new series on newer tools are designer or developer knows, what- JVM languages that will appear in Java Magazine. We will ever goes in a language stays as bag- examine the full range of languages, from large commercial being written gage pretty much forever. efforts to projects driven by determined groups of hackers. In in Kotlin and our As a company that provides tool- the next issue, we’ll cover Jython. —Ed.] ing for developers, we’ve tried to existing tools, such make language release transitions as IntelliJ IDEA as smooth as possible. To this end, LEARN MORE and YouTrack, are a new release usually comes with a compiler warning about a potential • Kotlin home adopting Kotlin. upcoming change or deprecation. The • Kotlin on StackOverflow IDE also provides a quick fix to eas- • Kotlin on Reddit 49
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //functional programming / Part 2 Functional Programming in Java: Using Collections VENKAT Removing code smells from lambda-based functional routines SUBRAMANIAM
BIO n the first article in this two-part series, I demonstrated Arrays.asList("Brian", "Jackie", Ihow lambda expressions harness the power of the func- "John", "Mike"); tional style of programming in Java. Lambdas create more- expressive and concise code with less mutability and fewer final List
Reusing Lambda Expressions final long countEditorsStartN = editors.stream() Now, let’s see how easy it is to fall into the duplication trap .filter(name -> name.startsWith("N")) when using lambda expressions, and consider ways to avoid .count(); it. Suppose we have a few collections of names: friends, editors, and comrades: final long countComradesStartN = comrades.stream() final List
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //functional programming /
change to the lambda expression requires changes in more than one the guise of the Predicate instance. place—that’s a no-no. Fortunately, we can assign lambda expressions The new variable gently removed the duplication that sneaked in. to variables and reuse them, just like with objects. Unfortunately, it’s about to sneak back in with a vengeance, as we’ll see The filter() method, the receiver of the lambda expression in next, and we need something a bit more powerful to thwart it. the previous example, takes a reference to a java.util.function .Predicate functional interface. Here, the Java compiler works its Using Lexical Scoping and Closures magic to synthesize an implementation of the Predicate’s test() There’s a misconception among some developers that using lambda method from the given lambda expression. Rather than asking Java to expressions might introduce duplication and lower code quality. synthesize the method at the argument-definition location, we can be Contrary to that belief, even when the code gets more complicated, we more explicit. In this example, it’s possible to store the lambda expres- still don’t need to compromise code quality to enjoy the conciseness that sion in an explicit reference of type Predicate and then pass it to the lambda expressions give, as we’ll see in this section. function; this is an easy way to remove the duplication. We managed to reuse the lambda expression in the previous example; Let’s refactor the previous code to make it adhere to the DRY (Don’t however, duplication will sneak in quickly when we bring in another let- Repeat Yourself) best practice. ter to match. Let’s explore the problem further and then solve it using lexical scoping and closures. final Predicate
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //functional programming /
cates are mere duplicates, with only the letter they use being different. be invoked lazily or from multiple threads. To avoid race conditions, Let’s figure out a way to eliminate this duplication. the local variables we access in the enclosing scope are not allowed to Removing duplication using lexical scoping. As a first option, we could change once they are initialized. Any attempt to change them will result extract the letter as a parameter to a function and pass the function as in a compilation error. Variables marked final directly fit this bill, but an argument to the filter() method. That’s a reasonable idea, but the Java does not insist that we mark them as such. Instead, Java looks for filter() method will not accept some arbitrary function. It insists on two things. First, the accessed variables have to be initialized within the receiving a function that accepts one parameter representing the context enclosing methods before the lambda expression is defined. Second, the element in the collection, and returning a boolean result. It’s expecting values of these variables don’t change anywhere else—that is, they’re a Predicate. effectively final although they are not marked as such. For comparison purposes, we need a variable that will cache the letter When using lambda expressions that capture local state, we should for later use and hold onto it until the parameter, name in this example, also be aware that stateless lambda expressions are runtime constants, is received. Let’s create a function for that: but those that capture local state have an additional evaluation cost. With these restrictions in mind, let’s see how to use the lambda public static Predicate
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //functional programming /
that by using a Function interface. checkIfStartsWith(), like so:
final Function
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //functional programming /
Let’s create a method that looks for an element that starts with a given public static void pickName( letter and prints it. final List
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //functional programming /
pickName(friends, "N"); element, and transforming a collection. All these operations have one pickName(friends, "Z"); thing in common: they all worked independently on individual elements in the collection. None required comparing elements against each other The code picks out the first matching element, if found, and prints an or carrying over computations from one element to the next. In this appropriate message otherwise. section, we look at how to compare elements and carry over a computa- tional state across a collection. A name starting with N: Nate Now let’s begin with some basic operations and then build up to A name starting with Z: No name found something a bit more sophisticated. As the first example, we are going The combination of the findFirst() method and the Optional to read over the values in the friends collection of names and deter- class reduced our code and its smell quite a bit. We’re not limited to the mine the total number of characters. preceding options when working with Optional, though. For example, System.out.println( rather than providing an alternate value for the absent instance, we can "Total number of characters in all names: " + ask Optional to run a block of code or a lambda expression only if a friends.stream() value is present, like so: .mapToInt(name -> name.length()) .sum()); foundName.ifPresent( name -> System.out.println("Hello " + name)); To find the total of the characters, we need the length of each name. We can easily compute that using the mapToInt() method. Once we When compared to using the imperative version to pick the first transform the names to their lengths, the final step is to total them. We matching name, the nice, flowing functional perform this step using the built-in sum() method. Here’s the output style looks better. But are we doing more We could lose all for this operation: work in the fluent version than we did in the imperative version? The answer is no—these the gains we made Total number of characters in all names: 26 methods have the smarts to perform only as from concise and much work as necessary. elegant code if not We leveraged the mapToInt() method, a variation of the map opera- The search for the first matching element tion (variations such as mapToInt(), mapToDouble(), and so on create demonstrated a few more neat capabilities for a newly added type-specialized streams such as IntStream and DoubleStream) and in the JDK. Next, we’ll look at how lambda join() function. This then reduced the resulting length to the sum value. expressions help compute a single result simple method is so Instead of using the sum() method, we could use a variety of meth- from a collection. ods, such as max() to find the longest length, min() to find the shortest useful that it’s poised length, sorted() to sort the lengths, average() to find the average of Reducing a Collection to a Single Value to become one of the the length, and so on. We’ve gone over quite a few techniques most used functions in The hidden charm in the preceding example is the increasingly popu- to manipulate collections so far: picking lar MapReduce pattern, with the map() method being the spread opera- matching elements, selecting a particular the JDK. tion and the sum() method being the special case of the more general reduce operation. In fact, the implementation of the sum() method in 55
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //functional programming /
the JDK uses a reduce() method. Let’s look at the more general form of As the reduce() method iterated through the collection, it called the reduce operation. the lambda expression first, with the first two elements in the list. The As an example, let’s read over the given collection of names and dis- result from the lambda expression is used for the subsequent call. In the play the longest one. If there is more than one name with the same second call, name1 is bound to the result from the previous call to the longest length, we’ll display the first one we find. One way we could do lambda expression, and name2 is bound to the third element in the col- that is to figure out the longest length, and then pick the first element of lection. The calls to the lambda expression continue for the rest of the that length. But that would require going over the list twice, which is not elements in the collection. The result from the final call is returned as efficient. This is where a reduce() method comes into play. the result of the reduce() method call. We can use the reduce() method to compare two elements against The result of the reduce() method is an Optional because the list each other and pass along the result for further comparison with the on which reduce() is called might be empty. In that case, there would remaining elements in the collection. Much like the other higher-order be no longest name. If the list had only one element, reduce() would functions on collections we’ve seen so far, the reduce() method iter- return that element and the lambda expression would not be invoked. ates over the collection. In addition, it carries forward the result of the From the example, we can infer that the reduce() method’s result is computation that the lambda expression returns. An example will help at most one element from the collection. If we want to set a default or clarify this: a base value, we can pass that value as an extra parameter to an over- loaded variation of the reduce() method. For example, if the short- final Optional
The lambda expression we are passing to the reduce() method takes If any name is longer than the given base, it is picked up; otherwise, two parameters, name1 and name2, and returns one of them based on the function returns the base value, which is “Steve” in this example. the length. The reduce() method has no clue about our specific intent. This version of reduce() does not return an Optional because if the That concern is separated from this method into the lambda expression collection is empty, the default will be returned; there’s no concern strategy pattern that we pass to it—this is a lightweight application of the . about an absent or nonexistent value. This lambda expression conforms to the interface of an apply() Before I wrap up, let’s visit a fundamental, yet seemingly difficult, method of a JDK functional interface named BinaryOperator. This is operation on collections: joining elements. the type of the parameter the reduce() method receives. Let’s run the reduce() method and see whether it picks the first of the two longest Joining Elements names from the friends list. We’ve explored how to select elements, iterate, and transform collec- tions. Yet in a trivial operation—concatenating a collection—we could A longest name: Brian lose all the gains we made from concise and elegant code if not for a 56
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //functional programming /
newly added join() function. This simple method is so useful that it’s We no longer have to endure that pain. A StringJoiner class cleans poised to become one of the most used functions in the JDK. Let’s see up all that mess in Java 8, and the String class has an added conve- how to use it to print the values in a comma-separated list. nience method, join(), to turn that smelly code into a simple one-liner. Let’s work with our friends list. What does it take to print the list of System.out.println(String.join(", ", friends)); names, separated by commas, using only the old JDK libraries? We have to iterate through the list and print each element. Because Let’s quickly verify that the output is as charming as the code that the enhanced Java 5 for construct is better than the archaic for loop, produced it. let’s start with that. Brian, Nate, Neal, Raju, Sara, Scott for(String name : friends) { System.out.print(name + ", "); Under the hood, the String’s join() method calls upon the } StringJoiner to concatenate the values in the second argument, a System.out.println(); varargs, into a larger string separated by the first argument. We’re not limited to concatenating only with a comma using this feature. We That was simple code. It yielded this: could, for example, take a bunch of paths and concatenate them to form a classpath easily, thanks to the new methods and classes. Brian, Nate, Neal, Raju, Sara, Scott, We saw how to join a list of elements; we can also transform the ele- ments before joining them. We already know how to transform elements Darn it! There’s a stinking comma at the end (shall we blame it on using the map() method. We can also be selective about which elements Scott?). How do we tell Java not to place a comma there? Unfortunately, we want to keep by using methods such as filter(). The final step of the loop will run its course and there’s no easy way to tell the last joining the elements, separated by commas or something else, is simply element apart from the rest. To fix this, we can fall back on the a reduce operation. habitual loop. We could use the reduce() method to concatenate elements into for(int i = 0; i < friends.size() - 1; i++) { a string, but that would require some effort on our part. The JDK has System.out.print(friends.get(i) + ", "); a convenience method named collect(), which is another form of } reduce that can help us collect values into a target destination. The collect() method does the reduction but delegates the actual if(friends.size() > 0) implementation or target to a collector. We could drop the transformed System.out.println( elements into an ArrayList, for instance. Or, to continue with the cur- friends.get(friends.size() - 1)); rent example, we could collect the transformed elements into a string concatenated with commas. Let’s see if the output of this version was decent. System.out.println( Brian, Nate, Neal, Raju, Sara, Scott friends.stream() .map(String::toUpperCase) The result looks good, but the code to produce the output does not. .collect(joining(", "))); Beam us up, modern Java. 57
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //functional programming /
We invoked the collect() method on the transformed list and pro- vided it a collector returned by the joining() method, which is a static method on a Collectors utility class. A collector acts as a sink object to receive elements passed by the collect() method and stores them in a desired format: ArrayList, String, and so on. Here are the names, now in uppercase and comma-separated.
BRIAN, NATE, NEAL, RAJU, SARA, SCOTT
The StringJoiner gives a lot more control over the format of concat- enation; we can specify a prefix, a suffix, and infix character sequences, if we desire.
Conclusion As we’ve seen in this two-part series, lambda expressions and the newly added classes and methods make programming in Java so much easier and more fun, too. Collections are common in programming and, thanks to lambda expressions, using them is now much easier and simpler in Java. We can trade the long-winded old methods for elegant, concise code to perform common operations on collections. Internal iterators make it conve- nient to traverse collections, transform collections without enduring mutability, and select elements from collections without much effort. Using these functions means less code to write. That can lead to more maintainable code, more code that does useful domain- or application- related logic, and less code to handle the basics of coding.
This article was adapted from Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions with kind permission from the publisher, The Pragmatic Bookshelf.
LEARN MORE • Overview of functional programming • Cay Horstmann’s explanation of using lambdas in Java 8 58
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //java ee / Part 3 Contexts and Dependency Injection: The New Java EE Toolbox ANTONIO GONCALVES More loose coupling with observers, interceptors, and decorators BIO
his series of four articles attempts to demystify Contexts What Is Interception? Tand Dependency Injection (CDI). In the previous two Let’s start with an explanation of interception, which is articles, I discussed what strong typing really means in used to interpose on method invocations. It is a program- dependency injection and how to use CDI to integrate third- ming paradigm that separates cross-cutting concerns from party frameworks. In this article, I focus on how to get loose our business code. Most applications have common code coupling with interceptors, decorators, and events. The final that is repeated across components—the cross-cutting con- article will cover the integration of CDI within Java EE. cerns. These could be technical concerns, such as logging the If you have read the previous articles, you should know entry and exit from each method or logging the duration of a by now that CDI is all about loose coupling. But CDI can go method invocation. Or they could be business concerns, such even further by using interceptors, decorators, and events. as to perform additional checks if a customer buys more than Interceptors are a way US$10,000 of items or send a refill order when the inven- to solve the prob- tory level is too low. Both technical concerns and business lem of cross-cutting concerns rely on the container to do much of the legwork technical concerns by of implementation. intercepting method The container does the interception. We need to remember invocation. Decoration that CDI beans live in a managed environment known as a is similar to intercep- container or bean manager. This bean manager provides tion but is applied to many services, one of which is the ability to intercept business concerns. method invocation. As can be seen in Figure 1, Bean A and CDI events bring about Bean B are both managed by the CDI container. When we even more loose cou- invoke a method on Bean A or Bean B, we can ask the pling by implement- container to intercept the calls and process some busi- ing the observer/ ness logic. This can happen before or after the bean method observable pattern in is invoked, so we can also add business logic when the Figure 1. Intercepting method calls a very easy way. invocation returns. 59
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //java ee /
Interceptors return new Book( Interceptors allow adding cross- An interceptor title, price, cutting technical concerns to our binding is just generator.generateNumber()); beans. For technical concerns, think of } @Loggable transaction management, authentica- an annotation. public Book raisePrice(Book book) { tion, authorization, or even a logging You can think of it book.setPrice(book.getPrice() * 2.5F); mechanism that logs every method as a qualifier but return book; invocation. Once we know how to log a } method entry, we isolate the code into for interceptors. } an interceptor, and enable this inter- ceptor for several beans. Interceptor binding. An interceptor binding is just an annota- Take the BookService class defined inListing 1. Let’s say tion. You can think of it as a qualifier but for interceptors. We we want to log an entry each time the createBook method give it a meaningful name—here, Loggable—and annotate is invoked. A simple way of doing this is by injecting a logger it with @InterceptorBinding. Now that we have an inter- and tracing the entry. It appears that this technical concern ceptor binding, we need to attach it to the interceptor itself, can also be used by other methods and other beans. Instead which will provide the logging mechanism. of copying and pasting code around, we can isolate this code in an interceptor, give it a name (here, it is @Loggable), and @InterceptorBinding @Retention(RUNTIME) apply it on whatever method we want. This tells the con- @Target({METHOD, TYPE}) tainer, “intercept this method, and do whatever you need to @Documented do to log an entry.” This behavior can be extended to other public @interface Loggable { technical concerns. In Listing 1, we tell the container that } every method of the bean needs to be secured and trans- actional. @Transactional, @Secured, and @Loggable are Interceptor implementation. The LoggingInterceptor called interceptor binding. (see Listing 2) is a separate class, annotated with our @Loggable interceptor binding, but it also needs the spe- Listing 1. cial @javax.interceptor.Interceptor annotation. This @Transactional will tell CDI that LoggingInterceptor is the interceptor @Secured called @Loggable. This class uses a logger to log method public class BookService { entries. Notice here that interceptors are CDI beans and can take advantage of dependency injection, for example. @Inject private IsbnGenerator generator; Despite being annotated with @AroundInvoke, the intercept method—which could be called whatever we want, by the @Loggable way—must follow certain rules: The method must have an public Book createBook(String title, InvocationContext parameter and must return Object. Float price) { But what is an invocation context? 60
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //java ee /
Listing 2. Notice that the interceptor needs to invoke the proceed @Loggable method. Calling InvocationContext.proceed() is impor- @Interceptor tant, because it tells the container that it should proceed to public class LoggingInterceptor { the next interceptor or call the bean’s business method. Not calling proceed would stop the interceptors chain and would @Inject private Logger logger; avoid calling the business method. Intercepting returned invocations. An interceptor can inter- @AroundInvoke cept method invocations but also the method returns. Just private Object intercept(InvocationContext ic) add a finally block to the code (see Listing 2). When the throws Exception { createBook method is called, the container intercepts the logger.info("> {}", ic.getMethod()); call and first logs a message with the method name. The try { interceptor proceeds to call the BookService, invokes the return ic.proceed(); createBook method, returns, and only then logs a message } finally { logger.info("< {}", ic.g13/16ethod()); after exiting the method. } Enabling interceptors. By default all interceptors are disabled, } so we need to enable them. We can do that using the beans } .xml descriptor (see Listing 3) by specifying the class name of the interceptor implementation Without this declaration, the Invocation context. The invocation context allows inter- interceptor is not taken into account. ceptors to control the behavior of the invocation chain. If several interceptors are chained, the same invoca- Listing 3. tion context is passed to each interceptor. For exam- ple, when we invoke the method createBook on the BookService bean (Listing 1), the call is intercepted by the LoggingInterceptor (Listing 2). As I’ll demonstrate later, the chain of interceptors can be longer, and the call can actu- ally be intercepted by interceptor 2, interceptor 3, and so on. All these interceptors can share the same invocation context. With the InvocationContext API, each interceptor can get information about the target class (here, BookService), the target method, or the method parameters, or it can add con- Dealing with Several Interceptors textual data to be processed by other interceptors. Interceptor bindings can be seen as qualifiers for intercep- In LoggingInterceptor (see Listing 2), we can see that the tors. So, like qualifiers, interceptor bindings can have some intercept method has an InvocationContext parameter advanced usage. For now we have a LoggingInterceptor and is then used to get the method of the bean class for which that logs each method invocation. Its interceptor binding is called @Loggable. But in certain cases we might want to log the interceptor was invoked (createBook or raisePrice). 61
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //java ee /
more debug information and use another interceptor—let’s logger.info("> Extended classes : {}", say LoggingDebugInterceptor (see Listing 4, which I’ll new Object[]{declaringClass explain shortly). How would we call its interceptor bind- .getClasses()}); ing—@LoggableWithDebug? And if we have other logging logger.info("> Annotations ({}) : {}", declaringClass.getAnnotations().length, interceptors, we would have as many interceptor bindings. declaringClass.getAnnotations()); Like qualifiers, we could create as many different interceptor try { bindings as we have implementations, or we could add mem- return ic.proceed(); bers to our interceptor bindings, or we could aggregate them. } finally { logger.info("< {}", ic.getMethod()); Listing 4. } @Loggable(debug = true) } @Interceptor } public class LoggingDebugInterceptor { Interceptor binding with members. An interceptor binding is @Inject an annotation, so it can have as many members of any type private Logger logger; as needed. Here, to differentiate between logging and debug logging, we could use a Boolean. Any other members of any @AroundInvoke data type are, of course, allowed. private Object intercept(InvocationContext ic) throws Exception { @InterceptorBinding logger.info("> {}", ic.getMethod()); @Retention(RUNTIME) logger.info("> Parameters : {}", @Target({METHOD, TYPE}) ic.getParameters()); @Documented final Class runtimeClass = public @interface Loggable { CDI events ic.getTarget().getClass(); boolean debug(); logger.info("> Runtime class : {}", implement } runtimeClass.getName()); the observer/ logger.info("> Extended classes : {}", new Object[]{runtimeClass.getClasses()}); So now we have two interceptor observable logger.info("> Implemented interfaces: {}", implementations: Logging design pattern new Object[]{runtimeClass Interceptor (see Listing 5) for and are perfect .getInterfaces()}); normal logging and Logging logger.info("> Annotations ({}) : {}", DebugInterceptor (see Listing 4) for for decoupling runtimeClass.getAnnotations().length, extra debug logging. To differentiate runtimeClass.getAnnotations()); components that them, we use our interceptor bind- final Class declaringClass = have no compile ing and set different values on the ic.getMethod().getDeclaringClass(); logger.info("> Declaring class : {}", Boolean member: debug = false for time dependency. declaringClass); LoggingInterceptor and debug 62
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //java ee /
= true for LoggingDebugInterceptor. Each interceptor public Book raisePrice(Book book) { implementation is now uniquely defined. // ... } Listing 5. } @Loggable(debug = false) @Interceptor Aggregating interceptor bindings. Another way of qualifying an public class LoggingInterceptor { interceptor and a bean is to specify multiple interceptor bind- ings. Like qualifiers, interceptor bindings can be aggregated. @Inject So we could keep @Loggable for the createBook method, private Logger logger; and add a @Debug interceptor binding (see Listing 7). @AroundInvoke private Object intercept(InvocationContext ic) Listing 7. throws Exception { public class BookService { logger.info("> {}", ic.getMethod()); try { @Loggable @Debug return ic.proceed(); public Book createBook( } finally { String title, Float price) { logger.info("< {}", ic.getMethod()); // ... } } } } @Loggable public Book raisePrice(Book book) { // ... The way we use interceptor bindings with members on our } beans is the same as qualifiers. InListing 6, the createBook } method will be intercepted and will trace a log, while the raisePrice method will log debug information. Ordering Interceptors Interceptors are very handy, and it’s quite common to have Listing 6. several of them intercepting methods. As an example, when public class BookService { we invoke the createBook method, we might want an inter- @Loggable(debug = true) ceptor to log the call, another one to see how many millisec- public Book createBook( onds the call takes, and an additional one to track the thread. String title, Float price) { The order in which interceptors are called is very important. // ... Do we want @Loggable to execute first? Would it make sense } to track the thread at the very end of the chain or at the beginning? It depends on what we want to do, but ordering @Loggable(debug = false) can definitely make a difference. 63
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //java ee /
Multiple interceptors. The BookService in Listing 8 Listing 9. shows how to pack a list of interceptor bindings on top of the createBook method. The Java language doesn’t take annotations ordering into account. It’s not because @ThreadTrackable is at the bottom, in the middle, or at the top that the ordering will change. Ordering comes in two flavors: with the beans.xml deployment descriptor, or with the @Priority annotation.
Listing 8. public class BookService {
@Inject private IsbnGenerator generator; Sequencing interceptors with @Priority. @Priority takes an integer that can have any value. The rule is that intercep- @Loggable tors with smaller priority values are called first. While any @Auditable @ThreadTrackable value can be used, keep in mind that Java EE 7 defines several public Book createBook( platform-level priorities and so interceptors can be called String title, Float price) { before or after a specific action. PLATFORM_BEFORE has the return new Book( value of zero, which is the starting value for early intercep- title, price, tors. LIBRARY_BEFORE equals 1000; it is for early intercep- generator.generateNumber()); tors defined by extension libraries. APPLICATION equals } 2000 and is for interceptors defined by applications; this is } usually when our interceptors will be executed. Then comes LIBRARY_AFTER for late interceptors defined by extension Sequencing interceptors with beans.xml. Remember that libraries and PLATFORM_AFTER for late interceptors. So if we interceptors are disabled by default, and they need to be want our interceptor to be executed before any application enabled in the beans.xml file. The order in which they are interceptor but after any early platform interceptor, we can listed in the file will be the order in which they will be use the value LIBRARY_BEFORE + 10. executed. For example, in Listing 9, LoggingInterceptor Ordering interceptors with @Priority. Instead of ordering with will be executed first, AuditInterceptor second, and beans.xml we can order our interceptors with the @Priority ThreadTrackerInterceptor last. If I change the order, the annotation (see Listing 10). AuditInterceptor will be exe- invocation chain will change. However, this activation and cuted first because it has the lowest priority value, 2010 (or ordering applies only to the beans in that archive, not to the APPLICATION + 10); then LoggingInterceptor, 2020; and beans in the entire application. Since CDI 1.1, interceptors can last, ThreadTrackerInterceptor. If we change the num- be enabled and ordered for the whole application using the bers, the ordering will change as well. Coming back to the @Priority annotation. 64
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //java ee /
interceptors of the createBook method defined in Listing 8, remember that interceptors are called before decorators when @Auditable will be executed first, then @Loggable, and applied to the same method. finally @ThreadTrackable. Figure 2 illustrates decoration. Here, the CDI bean PurchaseOrderService has one compute method that com- Listing 10. putes the total amount for a purchase order. An interceptor @Auditable could intercept the @Interceptor call to this method @Priority(APPLICATION + 10) and perform some public class AuditInterceptor { cross-cutting // ... } technical logic. @Loggable The decorator is @Interceptor slightly different @Priority(APPLICATION + 20) because it is aware public class LoggingInterceptor { of the target’s // ... logic. For example, } we could need a @ThreadTrackable decorator that @Interceptor @Priority(APPLICATION + 30) adds a discount to public class ThreadTrackerInterceptor { the purchase order // ... for Christmas. Figure 2. Inside a decorator } When we invoke the busi- Decorators ness method compute, a ChristmasDiscountDecorator Interceptors perform cross-cutting tasks and are perfect intercepts the call, gets the total amount of the purchase for solving technical concerns. By their nature, intercep- order, and then applies a certain discount percentage. tors are unaware of the actual semantics of the actions they The PurchaseOrderService is called the target, and the intercept, and therefore are not appropriate for separating ChristmasDiscountDecorator is the decorator. business-related concerns. The reverse is true for decora- Implementing the target. Now let’s illustrate this business case tors. Decorators are a common design pattern, initially with code. For decorators to be aware of the target’s business described by the the Gang of Four. The idea is to take a class logic, both the target and the decorator need to implement and wrap another class around it. This way, when you call the same interface. In our example, we use the Computable a decorated class you always pass through the surround- interface (see Listing 11), which has a compute method that ing decorator before you reach the target class, also known takes a list of items (let’s say books), computes the price, and as the @Delegate. Decorators are meant to facilitate adding returns a purchase order. additional logic to a business method. Interceptors and deco- rators, though similar in many ways, are complementary. Just 65
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //java ee /
Listing 11. return po; public interface Computable { } } PurchaseOrder compute(List
66
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //java ee /
@Inject Events @Discount Dependency injection, private Float discountRate; alternatives, inter- ceptors, and deco- @Inject rators enable loose @Delegate private Computable purchaseOrderService; coupling by allowing additional behavior to @Override vary, either at deploy- public PurchaseOrder compute(List
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //java ee /
time or runtime, but with a compile Next, the producer fires the event by calling the fire time dependency. It is important method of the Event interface, passing the PurchaseOrder In our case, we want to decouple the to understand object. The PurchaseOrder object will be carried from the dependencies, so we can have as many that the event producer to the consumers. As we can see, this code doesn’t services as needed, without chang- have any reference to any other service. Producers and ing the PurchaseOrderService. mechanism is observers are totally decoupled. Events go one step further, allow- synchronous. ing beans to interact with no com- Once the event is Listing 15. pile time dependency at all. Instead public class PurchaseOrderService { of depending on all these services, fired, the container @Inject PurchaseOrderService fires an pauses the code private Event
observe this event and performs some purchaseOrderEvent.fire(po); business logic. ShippingService return po; and StatisticService can also observe the same event } and perform their own business logic. All this happens in } a very loosely coupled way, because no service is aware of any other. Event producers fire events that are delivered to Event observer. Now the InventoryService in Listing 16 event observers by the container. Not only are event produc- needs to catch this event and do some processing. For that, ers decoupled from observers, but observers are completely it needs to declare an observer method. This method decoupled from producers. takes the PurchaseOrder as a parameter and is annotated Event producer. Let’s have a look at the event produce. The with @Observes. That’s it. The addItems method is noti- PurchaseOrderService is defined inListing 15. The create fied of the event by the container and can then keep the method takes a list of items, does some business logic, and inventory up to date. It is important to understand that returns a PurchaseOrder object. Now, to fire an event is the event mechanism is synchronous. Once the event is quite easy in terms of code. Event producers fire events fired from the PurchaseOrderService, the CDI container using an instance of the Event interface. An instance of this pauses the execution and passes the event to any regis- interface is obtained by injection and is typed the same as tered observers. In our case, the addItems method will be the producer’s object. In our example, we want to fire the invoked, the inventory will be updated, and the container PurchaseOrder, so Event is typed with PurchaseOrder. will then continue the code execution where it paused in 68
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //java ee /
the PurchaseOrderService. Events in CDI are not treated and the exception is rethrown by the fire method. One thing asynchronously. to keep in mind with observers is that there is no ordering in CDI 1.1 and the invocation is synchronous. The @Priority Listing 16. annotation doesn’t work with observers, so there is no solu- public class InventoryService { tion to guarantee the order of the observers’ execution. Ordering observers, however, is on the roadmap of CDI 2.0. @Inject private Logger logger; Conclusion public void addItems( In this article, we’ve seen that CDI delivers loose coupling @Observes PurchaseOrder po) { by implementing several design patterns in a very easy way. logger.info("Purchase Order of ${}", Interceptors interpose in method invocations and perform po.getTotal()); technical cross-cutting tasks, such as logging or audit- } ing. Decorators intercept invocations for a specified busi- } ness interface, and therefore are aware of all the seman- tics attached to that interface. Because decorators directly Multiple event observers. Now it’s just a matter of having as implement operations with business semantics, they are the many observers as needed. The ShippingService observes perfect tool for intercepting business concerns. Interceptors the same event and, once the event is received, it takes all and decorators can be ordered if needed. CDI events imple- the needed information from the PurchaseOrder to ship the ment the observer/observable design pattern and are per- items to a specific destination. fect for decoupling components that have no compile The StatisticService also time dependency. One thing to keep in observes the event to update mind with observers its statistics of items sold, just is that there is no by having a method annotated with Observes and by speci- ordering in CDI 1.1 fying the type of the event: and the invocation is PurchaseOrder. synchronous. There is Being synchronous, the method firing the event has no solution to guarantee to wait until the end of all the order of the observers’ the observer’s invocations execution. Ordering before executing the instruc- LEARN MORE tions after event firing. If any • CDI specification observers, however, is on observer method throws an • Beginning Java EE 7 (book) the roadmap of CDI 2.0. exception, the container stops • PluralSight course on CDI 1.1 calling observer methods, • Weld CDI reference implementation 69
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //architecture / A First Look at Microservices The latest trend in enterprise computing is microservices. What exactly are they?
ARUN GUPTA ustomers expect a solution to be available on a variety of Single-purpose. Each decomposed part of an application is Cdevices ranging from mobile clients and wearables to the responsible for a single purpose only, and does it well. This BIO Internet of Things. They expect a personalized experience and smallness of scope is what the micro in microservices refers to. more-frequent updates. Businesses are trying to gain advan- Loosely coupled services. Service consumers do not have any tage over competitors with shortened time to market and a knowledge about implementation of the producer service. faster release cadence. Microservices are quickly emerging as Producers and consumers communicate only through a pre- part of the solution of this quest for speed of delivery. defined contract. This makes the service loosely coupled, which leads to more manageable, Microservices Defined Each service robust, and scalable applications. This Microservices are the product of an architectural approach that also means that updating producer emphasizes the functional decomposition of applications into can be services doesn’t require changing single-purpose, loosely coupled services managed by cross- independently the consumer. functional teams for delivering and maintaining complex deployed, and Decomposed applications are loosely software systems quickly. coupled, which leads to more man- That’s quite a lot of terms in this definition. Let’s break redeployed ageable, robust, and scalable appli- them down and understand each one. again, without cations. This means that updating Architectural approach. Unlike Java EE, Spring, and .NET, affecting the one service doesn’t require changing the microservice architecture is a language-, platform-, and another service. operating system–agnostic style that provides recommended overall system. Cross-functional teams. Each guidelines on how applications need to be built. This approach microservice is created by a team that Functional decomposition. A typical monolithic application allows a service has a mix of different skills such as in Java EE, for example, would consist of an EAR or WAR file. persistence, API design, and UI. This The entire functionality expected from the application is to be easily gives each team the competence to packaged in that one archive. There are several advantages of upgraded, for control the technology stack. this approach, but the application tends to break down as it example, to add Complex software systems. The ben- grows. Such an application needs to be decomposed into mul- efits of such an architecture style are tiple WAR files where each WAR consists of a single function. more features. evident only when building a nontriv- This is where we get the concept of a microservice. ial software system. This is so because 70
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //architecture /
building a microservice simplifies break compatibility by changing contracts. the application code, but pushes the The scope of each ■■ Independent DURS (Deploy, Upgrade, Replace, Scale). Each problem of plumbing to an integra- microservice is service can be independently deployed, and redeployed tion layer and thus requires signifi- much smaller again, without affecting the overall system. This approach cant support from the infrastructure. allows a service to be easily upgraded, for example, to add Return on investment for a simple than a monolith, more features. Each service can also scale independently application might not be evident to and this leads to a using horizontal duplication or sharding. Implementation begin with. smaller executable. of the service, or even the underlying technology stack, can change as long as the exact same contract is published. This Characteristics As a result, the is possible because of the loose coupling. With this basic definition, let’s deployment and ■■ Potential heterogeneity. The implementation details of one examine the key characteristics of a the startup are service should not affect another service. This enables ser- microservices-based application. vices to be decoupled from each other, and allows the team ■■ Domain-driven design. Functional much faster. building a service to pick the language, persistence store, decomposition of an application can tools, and methodology that are most appropriate for them. be achieved using the well-defined A service that needs to store data in a relational database principles of domain-driven design can choose MySQL, and another service that needs to store (DDD), by Eric Evans. Decomposition by domain is not the documents can choose MongoDB. Different teams can only way to break down the application but certainly a very choose whatever technology is most efficient for them. common way. Each team is responsible for building the ■■ Lightweight communication. Services communicate with entire functionality around that domain or function of the each other using a lightweight communication, such as business. Each team that builds a service includes the full REST over HTTP. An alternative mechanism is to use a range of developer skills, thus enabling a full-stack devel- publish-subscribe mechanism that supports asynchronous opment methodology. messaging. Any of the messaging protocols, such as AMQP, ■■ Single responsibility. Each microservice should have STOMP, MQTT, or WebSocket, that meets the needs can be responsibility for a single part of the functionality, and it used here. Simple messaging implementations, such as should do that well. ActiveMQ, that provide a reliable asynchronous fabric are ■■ Explicitly published interface. Each service publishes an quite appropriate for such usages. The choice of synchro- explicitly defined interface and honors that at all times. The nous and asynchronous messaging is very specific to each consuming service cares only about that interface and should service; even a combination of the two approaches can be not have any runtime dependency on the consumed service. used. Similarly, the choice of protocol is very specific to The services agree upon the domain models, API, payload, each service, but there is enough choice and independence or some other contract; they communicate using only that. for each team building a service. A newer version of the interface may be introduced, but either the previous versions continue to exist or the newer Benefits services are backward-compatible. Microservices may not What are the benefits of a microservices-based application? 71
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //architecture /
■■ Easy to develop, understand, and maintain. Code in a are composed together to achieve business functionality. microservice is restricted to one function of the business Microservices also bear a resemblance to service location and is thus easier to understand than a full application transparency, service discovery, loose coupling, and stateless might be. services. But there are some fundamental differences. ■■ Starts faster than a monolith. The scope of each microser- ■■ Services tied to a common platform. SOA has been hijacked vice is much smaller than a monolith, and this leads to a by the enterprise service bus (ESB) vendors. All services smaller executable. As a result, the deployment and the are tied to an SOA product. Vendors pitch their propri- startup are much faster. etary products, with minimal to no common standards for ■■ Easy to deploy local change. Each service can be deployed interoperability across products. This limits the ability to independently of other services. Developers can easily innovate within each product. make any change local to the service without requiring ■■ Overly complex SOAP-based web You are free coordination with other teams. services. Web-service specifications ■■ Scales independently. Each service can scale indepen- are overly complex. All the XML to choose any dently based upon need. In contrast, monolithic applica- and SOAP processing makes it time stack of your tions might have different requirements and yet must be consuming to generate and con- choice. No one deployed and scaled together. sume messages. Implementations ■■ Improves fault isolation. A misbehaving service, such as one of these specifications require sig- framework is ideal with a memory leak or unclosed database connections, will nificant investment that is primarily for building your affect only itself as opposed to affecting the entire mono- done for Java and .NET only. These microservices; lithic application. This improves fault isolation. implementations serve a specific ■■ Eliminates long-term commitment to any stack. Developers purpose—in some enterprises today, pick the one that are free to pick the language and the stack that are best rather limited—but most of the you are most suited for their service. Although the organization may recent projects have been adopting comfortable with. restrict the choice of technology, you are not penalized the REST style of communication. because of past decisions. It also enables you to rewrite the ■■ Centralized routing and service using better languages and technologies. This gives transformation. All messages are you freedom of choice when selecting the technology, tools, routed through a central ESB, which can transform and and frameworks. route the messages based upon business rules. This is opposed to the “smart endpoint, dumb pipe” philoso- What Is the Relationship with SOA? phy for microservices, where the connection performs no A common misconception is that there is nothing new about transformation and is simply a conduit. microservices—that they are similar to service-oriented ■■ Centralized governance. SOA has a major emphasis on architecture (SOA). Some of the common pithy names for centralized governance that defines how services will be microservices are “fine-grained SOA,” “SOA for hipsters,” defined, developed, and maintained. All services are reg- and “SOA done right.” In this sense, microservices do cap- istered with a central registry and are invoked by an ESB ture the original essence of SOA, where multiple services to monitor and meter usage. Service registry and discov- 72
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //architecture /
ery in the microservices world to accomplish as it sees fit. This gives teams freedom from a are done using a third-party tool Ready or not, long-term commitment to any particular stack, and it allows such as ZooKeeper, Consul, or microservices them to innovate. There are some recent technologies in Java etcd. The services invoke each are coming your EE that make it particularly well suited to microservices, other directly, as opposed to going especially if team members have experience with server-side through a central bus. way. Start thinking Java. These capabilities include the following: about them for your ■■ Java Naming and Directory Interface provides location Refactor Monolith into next project. Start transparency and service discovery. Microservices ■■ Contexts and Dependency Injection (CDI) gives loose While this task is worthy of a sepa- with a pilot project, coupling and strong cohesion. rate article, here’s a quick overview benefit from that ■■ JAX-RS provides full support for REST. of what is entailed. first tryout, and then ■■ Java Message Service and CDI events enable the publish- Consider a trivial shopping cart subscribe model for asynchronous messaging. web application consisting of cata- grow from there. ■■ Native support is available for JSON data representation. log, shopping cart, and shipping Transactions within a microservice are easily supported by functionality. A typical monolithic Enterprise JavaBeans and @Transactional. Many platform- way to package such an application as-a-service vendors already offer Java EE support. would be to have all the web pages, classes, and configuration ■■ A modular application server, such as JBoss Enterprise files, for the entire functionality, together in a single WAR or Application Platform, allows you to bundle only the EAR file, which is deployed to a Java EE application server. required components, so you can keep the footprint size There is a single database for the entire application, and it is minimal. shared by all the classes. ■■ Each microservice can be deployed as a WAR file. Functional decomposition of this application would sepa- ■■ Extensive tooling simplifies Java EE development, which rate the web pages, classes, and configuration files for one lowers the bar for building such applications. domain, such as catalog, in a separate WAR file. One WAR file If there is a missing capability, it can be implemented as a is split up into three WAR files, each containing all the arti- CDI extension. facts required to serve its functionality. The database shared As mentioned earlier, a team is not limited to Java EE, and by the monolithic application is also refactored into three you can choose any stack of your choice. For example, Vert.x separate databases. Each WAR file publishes a well-defined is a simple, polyglot, and JVM-based framework that facili- interface, likely using REST. And a WAR file can be deployed tates the creation of lightweight applications and fat JARs in a separate application server and scaled independently. easily. No one framework is ideal for building your microser- vices; pick the one that you are most comfortable with. Is Java EE Well Suited for Microservices? Ready or not, microservices are coming your way. Start Microservices enable heterogeneity and polyglot stacks. This thinking about them for your next project. Start with a pilot is possible because the only requirement is a well-defined project, benefit from that first tryout, and grow from there. interface, and the implementation is a detail left to each team Happy microservicing! 73
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 Your Destination for Java Expertise
Written by leading Java experts, Oracle Press books offer the most defi nitive, complete, and up-to-date coverage of Java available.
Raspberry Pi with Java: Introducing JavaFX 8 Java: The Complete Reference, OCA Java SE 8 Programmer I Programming the Programming Ninth Edition Study Guide (Exam 1Z0-808) Internet of Things (IoT) Herbert Schildt Herbert Schildt Edward Finegan, Robert Liguori Stephen Chin, James Weaver Learn how to develop dynamic JavaFX Fully updated for Java SE 8, this Get complete coverage of all Use Raspberry Pi with Java to create GUI applications quickly and easily. definitive guide explains how to objectives for Exam 1Z0-808. innovative devices that power the develop, compile, debug, and run Electronic practice exam questions internet of things. Java programs. are included.
Available in print and as eBooks www.OraclePressBooks.com • @OraclePress //fix this / Quiz Yourself We all write code from within a subset of the full Java language. How well do we know that subset? Let’s see.
he questions in this quiz are taken from certifica- Question 2. Given this code fragment: Ttion test 1Z0-809: Oracle Certified Associate, Java SE 8 public abstract class Product { // line n1 Programmer II, Oracle Certified Java Programmer. The pur- String name; pose of this certification is to enable beginners to demon- Product(String name) {. // line n2 strate their knowledge of Java 8 concepts, somewhat above this.name = name; the fundamental level. } Naturally, these questions can have small unexpected traps public final void printProduct() { // line n3 System.out.println(name); that can snag even the attentive coder. But in this way, they } reflect situations that occur in real life in which we won- public void printLabel(); // line n4 der why code that looks right does not behave as expected. } Ready? (Answers appear in the “Answers” section immedi- ately after the questions.) Which line causes a compile-time error? a. line n1 Question 1. Given this code fragment: b. line n2 Map
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //fix this /
c. 1 instance are sorted according to the natural order of their keys. Option d. A NoSuchFileException is thrown at runtime. D is incorrect. The elements of the codes map are sorted in ascending order of its keys. Question 4. Now, let’s filter a collection using lambda expressions. Given this code fragment: Question 2. Option D is correct: line n4 is invalid. A method Stream
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //career / Part 3 More Ideas to Boost Your Developer Career Skills to develop, activities to explore
hink about the best developers you know—people you code? To solve problems and create solutions that can ben- Tadmire for the work they do. Maybe you follow them efit people. Many developers don’t even think about it, but on Twitter, watch their presentations, or read some of their we have a development environment available literally at our articles or blog posts. Have some of them made an impact on fingertips: the command-line interface (CLI). The CLI gives BRUNO SOUZA AND your life and career? Why—because they write amazing code? you the ability to control your whole environment. Menus and EDSON YANAGA Chances are that this is not the only thing they do to inspire icons of tools, the IDEs, and the operating systems give you BIO you to follow and admire their work. The truth is that a flour- easy access only to what is visible. The CLI gives you access ishing developer career involves much more than just writing to everything. great code. Do you think of the CLI as a development environment? This series of articles focuses on three areas that we think We do. You have to deal with the syntax and know the state- have equal weight in a developer’s career: code, community, ments to execute. There is data and state, and you can process and an open mind. Focusing on one while ignoring the others information. You even get unexpected results, and interpreter is a bad practice that limits personal and professional growth. errors. That sounds exactly like coding! The good news is that changing your mindset does not The CLI provides a way to code and create automated soft- require a huge effort. It is something you can do no mat- ware solutions. We can use it to create even more code: it ter what project you are working on—or what your employer boosts our productivity through automation. After all, this is thinks about it. It doesn’t take a lot of time, and it is really a how software enables our lives. lot simpler than most things you deal with in your daily job. To be effective, the CLI requires you to learn, experiment, The best way to steer something in the right direction is to and remember what is available and how to use it. Get profi- get it moving first. By taking small daily steps in the right cient with it. Experiment every day with new things you can areas, you can continuously push your career forward and do on the command line. And try to automate actions you achieve your goals. need to perform repeatedly. ACTION ITEM: Explore how many steps of your daily routine Code: Use the Command-Line Interface you can do through the CLI. We’ve already seen that to code better every day you need ACTION ITEM: Join some of those steps into scripts that auto- BRUNO SOUZA PHOTOGRAPH BY BOB ADLER/GETTY IMAGES to practice: code, code, and code. And what’s the purpose of mate parts of your work. 77
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //career /
ACTION ITEM: Play with tools such as sed, awk, and grep to Presenting talks and writing blog posts and articles are unleash some of the CLI’s power. acquired skills that you need to develop. By starting with BONUS ITEM: Find a tool you already use that has a good CLI small, easy steps, you will boost your confidence and ben- (such as Jenkins and AWS). Experiment to see how far can you efit your career. This is an attitude change that will last your go in using the CLI. whole life. ACTION ITEM: Present the slides of a presentation you watched Community: Speak at an Event to your coworkers. We all learn from content that other developers created— ACTION ITEM: Prepare a short talk that will be useful to your videos, webinars, blogs, talks. Usually these are the develop- friends. ers we look up to. The ability to communicate clearly is a ACTION ITEM: Turn those slides into a blog post or propose It isn’t difficult terrific asset for your career, as is the wisdom to focus on to present them to a local user group, university, or techni- to steer your and deliver pertinent and interesting information. cal school. Maybe you’ll decide to record your talk and post it Presenting ideas using slides, video, or text brings immedi- on YouTube. career in the right ate results. You’ll be astonished at how much you learn just BONUS ITEM: Experiment with getting this talk approved. direction. Keep by preparing your presentation. Research shows that teach- Submit it to a conference or tradeshow, even if the event is your mind open to ing something is the most effective way to learn. You’ll need one that you don’t expect to accept it—maybe an event in to study and research your topic to become a confident public another country. Add your blog post or your recorded presen- new possibilities, speaker. And by doing so, you become known as an expert on tation as supporting material. experiment with that particular subject. You’ll have the satisfaction of helping new ideas, and others, and also the pride of professional accomplishment. DevOps: Start Now Even with these benefits, presenting a talk is still intimi- Software development is all about creating something new. It engage with the dating. To conquer your fear, remind yourself that presenting is about looking to the future and shaping new functionalities community. is a big challenge for most people. Even seasoned speakers get out of thin air. That’s why great developers are open-minded. butterflies before walking on stage. Don’t get discouraged. They experiment. And some ideas or technologies really help: You can reduce the fear by reducing the challenge. Start they push the boundaries of our thinking. DevOps is one of small. Present something you learned last week to your those attitude-changing ideas. coworkers during a quick lunchtime meetup. Or, present As developers, we need to take responsibility for the soft- something you know well, such as a technology or a specific ware we build, and review our definition of “done.” Software tool, to students taking a computer science course. Later, is not truly done until the end user benefits from it. Software maybe you’ll decide to submit your talk to your local Java development should be all about delivering value to end user group. users. What good is code sitting idle in a repository some- A neat trick to remember: When people attend your talk, it where? There are too many reasons why we allow this: It isn’t is because they want to learn about your topic. You probably ready. It has bugs. It needs improving. It needs to perform know more about it than they do; otherwise, they would be better. These are recurring fears that can serve as excuses on doing something else. Remember that the value you bring to every project. your audience is your experience. DevOps is the idea that Developers and Operations (every- 78
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //career /
one, in fact) work together to deliver software. DevOps gets us to think differently. It makes delivering value to the users our top priority. When the whole company works together toward the goal of people using the software, we focus more on the benefits to our users and less on the fears that prevent us from doing it. We become better developers. DevOps is an all-encompassing skill. It requires us to improve everywhere—from our tools and collaboration to our code and tests. And it is easy to start. Think big, but start small. Change your attitude. Focus on automation and deliv- ery. Others will follow. ACTION ITEM: Automate something that you do manually, such as your build, your deployment, or one of your high-level tests and test suites. ACTION ITEM: Define something useful to measure, such as the number of bugs in the project, or how long it takes to deploy a new version. Start tracking this for the next few weeks. Add new metrics later. BONUS ITEM: Learn one automation tool that you currently don’t use, such as Jenkins, Ansible, Chef, or Selenium. Go beyond the tutorial: Run a small but real test to automate one thing in your project.
Pulling It All Together The skills described previously are easily combined. Using the CLI to automate tasks is a useful DevOps skill. Spending time automating your deployment will not only get you mov- ing going in the right direction, but it will also make your life easier. Consider delivering a brief presentation to your coworkers demonstrating what you did. You can then pass along this important skill by presenting the same talk to stu- dents in a nearby university. It isn’t difficult to steer your career in the right direction. Keep your mind open to new possibilities, and experiment with new ideas. Engage with the community in ways that are positive for you and others. And keep coding! 79
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015 //contact us /
Comments or those bundled with the JDK). Finally, +1.847.763.9635), who will do whatever We welcome your comments, correc algorithms, unusual but useful pro they can to help. tions, opinions on topics we’ve covered, gramming techniques, and most other and any other thoughts you feel impor topics that hard-core Java programmers Where? tant to share with us or our readers. would enjoy are of great interest to us, Comments and article proposals should Unless you specifically tell us that your too. Please contact us with your ideas at be sent to me, Andrew Binstock, at correspondence is private, we reserve [email protected] and we’ll give [email protected]. the right to publish it in our Letters to you our thoughts on the topic and send While it will have no influence on the Editor section. you our nifty writer guidelines, which our decision whether to publish your will give you more information on pre article or letter, cookies and edible treats Article Proposals paring an article. will be gratefully accepted by our staff We welcome article proposals on all at Java Magazine, Oracle Corporation, topics regarding Java and other JVM Customer Service 500 Oracle Parkway, MS OPL 3A, languages, as well as the JVM itself. We If you’re having trouble with your Redwood Shores, CA 94065, USA. also are interested in proposals for ar subscription, please contact the ticles on Java utilities (either open source folks at [email protected] (phone
80
ORACLE.COM/JAVAMAGAZINE //////////////////////////////// SEPTEMBER/OCTOBER 2015