January 6, 2015
Tip #32 – Fail the build when there is a test failure
Systematic reuse needs automated tests – lots of them. Ensure that your continuous builds don’t keep running when they encounter a failing test – this makes mistakes visible faster and easier to fix. If you are using Maven, you can use the surefire plugin configuration as shown below:
August 31, 2013
Tip #31 – Inject Common Reusable Capabilities via JUnit Rules
JUnit has an extremely useful extension mechanism – Rules. The @Rule annotation can help provide additional capabilities to your test methods. For example, ContiPerf provides annotations for performance testing. Similarly, you can provide reusable framework hooks for developers to use alongside their test methods.
Some examples where this can be applied – capturing test execution metrics and publishing to a API for offline trending/analysis or setting up plumbing components to facilitate in-memory db testing via H2db, or data folders, etc.
Implementing a JUnit rule is quite straight forward – here’s an article from David Gassner that provides a sample rule implementation.
September 16, 2012
Tip #30 – Enforce Consistent Dependencies via Maven Parent POM
Maven parent POM can be used as a consistent mechanism to define dependencies and dependency versions. The module that defines common set of entries can then be used in any arbitrary module – it doesn’t have to be restricted to a child module in a multi-module build. This is very useful when you want to enforce consistent set of dependencies across multiple projects that share either a core set of reusable libraries including 3rd party dependencies.
January 1, 2012
Tip #29 – Automate Documentation on Reusable Assets
Happy new year 2012 🙂
What is one key reason developers have a difficult time finding and evaluating existing assets? Lack of robust documentation including what the reusable asset isn’t meant to do. Though it is a critical success factor, maintaining documentation manually is a time consuming task and is the first item that gets left out when the development team is racing to meet a deadline. It will be useful to generate documentation on service clients or library client code snippets alongside the provider code. Automate documentation as much as possible – this will come in handy when fixing bugs, integrating new consumers, as well as integrating documentation within IDEs. Here are a few examples of doing this:
- Maven javadoc plugin for example can generate javadoc style HTML documentation for various java and web modules
- Maven site deploy can be used to publish generated artifacts to a remote host
- XSL stylesheets can be used to generate HTML documentation from XML schemas (XSDs) – this can be handy when exposing reusable services (e.g. using XS3P)
May 2, 2011
Distribute Configuration For Various Testing Needs
If a reusable component requires runtime configuration (properties, XML files etc.) alongside the binaries, make it easier for the asset’s consumer to integrate these artifacts in their tests. For instance, using maven assembly the configuration files can be packaged as a jar file and added in the test scope. This will make the configuration available in the classpath when executing unit tests in the module. The configuration can be packaged per environment and using the dependency classifier the appropriate artifact can be used. This approach works for integration and performance testing as well – for instance, performance tests might use a different set of values for the configuration artifacts since they execute in a dedicated environment.
November 6, 2010
Use Maven Assemblies for Packaging Configuration Artifacts
The maven assembly plugin can be used to generate separate artifacts for environment-specific configuration files. This is very useful to separate binaries (jar, war, etc.) from configuration (xml, properties files, etc.). This enables deployment of a binary across any environment. Reusable components are often used in several applications and processes and they often have configuration information. Your clients will want to customize the configuration for testing/altering behavior and it is critical that your build process separates binaries from configuration.
Here’s the snippet for adding the plugin in the POM file:
Here’s an example packaging a zip:
July 10, 2010
Tip #26 – Build Reusable Services
The following are useful tips when designing and implementing reusable services.
Expose only logical data attributes and “standardized” values to external consumers in the service contract. This will ensure that the data service has maximum flexibility to change physical system implementations underneath and the consumer will not be adversely impacted.
Reuse business object schemas across data service operations and while preparing WSDL documents. This will ensure logical data model alignment as well as consistent definition of business objects simplifying consumption and maintenance effort.
Expose event driven publication services for data propagation to downstream consumers using standard publication messages. This will greatly reduce (and potentially eliminate) the need for source specific messages and needless data transformations. Standard publication messages could be versioned and new consumers could be added via configuration on a messaging broker without requiring development effort.
Provide multiple flavors of services based on commonly used use cases for the data service. A light flavor of a service will be useful for clients who do not want to parse a large business object message returned by the full flavor.
Strive for abstraction of data source specific semantics in order to insulate the consumer from physical data source processing/logic. This practice applies to identifiers, data values, data structures, and data orchestration logic that could be coupled to a physical source if proper care isn’t taken.
Prefer reliable transports when invoking data services asynchronously. Although it is possible to simulate asynchronous processing using transport protocols such as HTTP it is not advisable to do so. In the event the data consumer becomes unavailable messages are lost.
April 14, 2010
Tip #25 – Leverage Code Coverage Tools
Code coverage tools help with defect detection and prevention as part of continuous integration. I emphasized the importance of automated tests with regard to resuable assets – code coverage is no less important.
Code coverage reporting provides a window into the health of your codebase.
- the depth of your automated tests – what percentage of code is being executed by the tests?
- are there unused blocks of code – including functions, even classes – that are not executed?
- they are invaluable in helping detect complex code – are some classes too bulky/ripe for refactoring? Code coverage will make these painfully obvious to the developer.
Code coverage thus not only helps you identify opportunities for better tests it also helps you eliminate dead/bloated code and rip apart code that is too complex. I wrote earlier post on developing reusable assets for use first – I recommend identifying extensions/flexibility on a as-needed basis for reusable asset evolution. Code coverage will point out areas for achieving this objective as well.
Getting started is very simply – ff you are using apache maven2 for instance in the java world, it is extremely simple to set these up and use them by adding a few entires to the pom.xml file. Below is the plugin declaration for Cobertura – for plugin’s full usage instructions go here.
You can run code coverage by simply executing: mvn cobertura:cobertura from the project root folder- this will generate instrumented java classes, execute automated unit tests, and produce a code and branch coverage report.
November 25, 2009
Tip #24 – Identify common behavior and encapsulate it
Looking for common behavior across classes is an effective way to reuse behavior. When you find yourself cutting and pasting code, take a step back and reflect on the common behavior that is being implemented. If the duplication is due to the same behavior realized in different ways, introduce a new interface. If multiple objects have the same functionality and can derive from a parent object, introduce an inheritance hierarchy.
This can be done in an iterative fashion as well – if you failed to recognize an interface initially that is okay. Look for opportunities to refactor existing code to introduce a new interface. For example, you can use the Eclipse IDE’s refactoring feature – extract interface – to create a new interface from an existing class.
Why is this important for systematic reuse? Because, by isolating and realizing common behavior you reduce the need for multiple components and classes to re-implement the same functionality. If two classes need the same piece of data, or if they both connect with the same external system, why would you want to code them separately?
Like this post? Subscribe to RSS feed or get blog updates via email.
November 11, 2009
Tip #23 – Design for migration within the product line
Graceful migration within a product line is an often overlooked design trait but is critical for effective systematic reuse. Your products get upgraded or downgraded within a product line. Think of when you switched phone plans from a single user to a family plan or when you signed up for viewing premium content on an online website. Your design needs to support this in a seamless fashion. The design could support some form of licensing, a policy manager that knows your valid subscriptions and entitlements, and a means to migrate or setup data for a different flavor of a product. You cannot lose customer data and preferences if they upgrade to a different plan or a product in a product line. Reusable assets have to store, access, and update relevant data as a new version is introduced or bug fixes are made.
Like this post? Subscribe to RSS feed or get blog updates via email.