Systematic Reuse Mythbuster #1 – Reusable Doesn’t Mean Perfection

December 26, 2011

One common criticism against systematic software reuse is the myth that it implies perfection – creating a reusable asset automatically conjures up visions of a perfect design, something that is done once and done right.  Many developers and managers confuse reusability with design purity. However, reusability is a quality attribute like maintainability, scalability, or availability in a software solution. It isn’t necessary or advisable to pursue a generic design approach or what one believes is highly reusable without the right context.

The key is to go back to the basics of good design: identify what varies and encapsulate it.

The myth that you can somehow create this masterpiece that is infinitely reusable and should never be touched is just that – it is a myth and is divorced from reality. Reusable doesn’t imply:

  • that you invest a lot in big up front design effort
  • you account for everything that will vary in the design – the critical factor is to understand the domain – well enough, deep enough, so you can identify the sub-set of variability that truly matters

In the same vein, reusablility strives for separating concerns that should be kept distinct. Ask repeatedly:

  • Are there multiple integration points accessing the core domain logic?
  • Is there a requirement to support more than one client and if so, how will multiple clients use the same interface?
  • What interfaces do your consumers need? is there a need to support more than one?
  • What are the common input parameters and what are those that vary across the consumer base?

These are the key questions that will lead the designer to anticipate the appropriate places where reuse is likely to happen.  Finally, it is important that we don’t build for unknown needs in the future – so the asset is likely to solve a particular problem, solve it well, solve it for more than one or two consumers, and finally has potential to be used beyond the original intent. At each step there are design decisions made, discarded, continuous refactoring, refinements to the domain model – if not re-definition altogether.

Don’t set out trying to get to the end state or you will run the risk of adding needless complexity and significant schedule risk.


Reusable Capabilities When Hosting Business Processes

November 7, 2011

Many teams are pursuing BPM and SOA based initiatives to automate, streamline, and standardize business processes. As more solutions start to embark on BPM-based solutions, there is a need for a common set of software components that aid in hosting and managing business processes. The following are capabilities that need to be present in such a solution:

  • Common messaging architecture & utilities for facilitating the development and maintenance of stateful business processes & stateless services.
  • Support business process orchestrations that join across multiple services (data services, business services, legacy services, etc.). This is essential for orchestrating complex 
  • Handle workflow and system business process events via a configuration driven Event Handler Service, enabling reuse of event handler processes
  • Provide  ability to reuse sub-processes across larger business processes.
  • Runtime metrics including reporting and the ability to perform diagnostic troubleshooting
  • Reusable schemas for request dispatching, event handling, generic transport listeners, metrics, and error handling
  • Supports synchronous and asynchronous request/reply & fire/forget message exchange patterns
  • Provides the ability to create reusable components for assembling new business processes
  • Standard client interfaces across multiple transports such as HTTP and EMS
  • Ability to query various data sources, rules engine, as well as write custom java code to integrate with existing functionality
  • Provides interface for executing administrative functions
  • Provides developer tools for WSDL generation, unit testing, deployment, & viewing metrics

Using Spring & Java Annotations to Inject Reusable Capabilities

January 19, 2011

Want to inject reusable functionality but don’t want your consumers to go through complex set of steps to implement? Using annotations, a reusable capability can be injected at runtime – your clients can take advantage of common, reusable capabilities while avoiding the need to implement boiler plate code. Consumers can also be allowed to declaratively specify/alter the reusable asset’s behavior using this approach.

Here is an example using Java and Spring framework to print a test message before invoking the target method.

Declare an annotation – a simple annotation with a boolean flag:

package example.annotation;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {
	 boolean log() default true;
}

Create a dynamic proxy – all this does is examines the boolean log method from the annotation and prints a test message:

package example.proxy;

import java.lang.reflect.*;
import example.annotation.Loggable;

public class ExampleDynamicProxy implements InvocationHandler {

	private Loggable loggable = null;
	private final Object targetObject;

	public ExampleDynamicProxy(Object target, Loggable loggable) {
		targetObject = target;
		this.loggable = loggable;
	}

	public Object invoke(Object target, Method method, Object[] arguments) throws Throwable {

		Object result = null;
		try {
			if (loggable.log()) {
			  System.out.println("message before invoking method...");
			}
			result = method.invoke(targetObject, arguments);
		} catch (InvocationTargetException ite) {
			throw ite.getTargetException();
		}
		return result;
	}
}

Create a spring bean post-processor – checks for annotation and creates a proxied version of bean:

package example.postprocessor;

import java.lang.reflect.Proxy;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

import example.annotation.Loggable;
import example.proxy.ExampleDynamicProxy;

public class ExampleBeanPostProcessor implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object arg0, String arg1)
			throws BeansException {
		return arg0;
	}

	@Override
	public Object postProcessAfterInitialization(Object arg0, String arg1)
			throws BeansException {

		Class clz = arg0.getClass();
		Class[] interfaces = clz.getInterfaces();

		if (interfaces != null && interfaces.length == 1
                        && _interfaces[0].isAnnotationPresent(Loggable.class)) {

			Class _interface = interfaces[0];
			ClassLoader cl = arg0.getClass().getClassLoader();
			Loggable loggable = (Loggable)_interface.getAnnotation(Loggable.class);
			Object proxy= Proxy.newProxyInstance(cl, new Class[] {_interface}, new ExampleDynamicProxy(arg0,loggable));

                        return proxy;
		}
		return arg0;
	}
}

Annotate an example interface as Loggable – this model can be used to inject lot of other reusable capabilities (error handling, notifications to JMS destinations, or even perform data transformations):

package example.bean;

import example.annotation.Loggable;

@Loggable
public interface Example {
	public String getGreeting();
}

Finally, each consuming interface will have an implementation and has to be defined as a bean along with the post-processor during spring initialization. This is a trivial example but was meant to illustrate the injection of reusable behavior via java annotations.


Pursuing BPM? Avoid Reuse Inhibitors

December 20, 2010

Implementing business process re-engineering and/or automation involves several moving parts from a technology perspective – stateful business process data, interfaces for external systems/user interfaces to interact with process information, and rules that determine several aspects of process behavior.

Here are some practices to avoid/minimize when pursuing BPM projects:

  • Building monolithic process definitions – as the number of process definitions increase there will be opportunities to refactor and simplify orchestration logic. As projects start to build on existing processes, there will be an increasing need for modular process definitions that can be leveraged as part of larger process definitions.
  • Placing business rules that validate domain objects in the process orchestration graphs. This will effectively tightly couple rules and a specific process hurting the ability to reuse domain-specific rules across process definitions. Certain class of rules could change often and need to be managed as a separate artifact.
  • Invoking vendor specific services directly from the process definition. Over time this will result in coupling between a vendor implementation and multiple process definitions. This also applies to service capabilities hosted on legacy systems. Hence, the need to use a service mediation layer.
  • Defining key domain objects within the scope of a particular process definition. This will result in multiple definitions of domain objects across processes. Over time, this will increase maintenance effort, data transformation, and redundant definitions across processes and service interfaces.
  • Integrating clients directly to the vendor-specific business process API. This will result in multiple clients implementing boiler plate logic – better practice will be to service enable these processes and consolidate entry points into the BPM layer.

This isn’t an exhaustive list – intent is to to highlight the areas where tight coupling could occur in the business process layer.


Domain Analysis Key To Systematic Reuse

November 26, 2010

Domain analysis is a foundational capability required for effective systematic reuse. Why? There are a lot of applications your teams are working on and the common theme among them most likely is the fact that they are in the same problem domain. In order to truly bring down cost of new applications and services, it is critical that the domain is understood and modeled appropriately. Here are some specific strategies to make this idea operational:

  1. Account for domain analysis and modeling in your iteration planning. Domain analysis is necessary to understand the nuances and variation points that an application/service/process needs to realize. Discovering the right variations requires time and interactions with business stakeholders and subject matter experts.
  2. Aspire for a core set of business object definitions that can be shared across business processes and service interfaces. Without appropriate data governance, domain knowledge will either be inaccurate/incomplete or worse duplicated in an inconsistent fashion. As the number of customer interfaces increase for your services, the domain inconsistencies will lead to greater point-to-point integrations and complexity.
  3. Align overall architecture with domain variations. Your domain is rich and complex but probably varies in a known set of ways. Additionally, what varies isn’t uniform and the rate of change across these variations aren’t identical. This is significant because the variations in the domain need to be captured in your overall architecture. Products/applications in the domain need to share a common architecture – only then can components integrate and inter-operate and systematic reuse will take hold. Constantly evaluate the need for a new version of a core business entity and associated classes to manage the entity.
  4. Refactor constantly to get to intention revealing design and code. As Eric Evans illustrates in Domain Driven Design, intention revealing code is easier to understand and evolve.  It also makes it easier to address new business requirements – as the design/implementation are closely aligned with the business domain, the quality of communication (referred to as ubiquitous language) and the ability to change it both increase significantly.

This isn’t an exhaustive list – instead, it is meant to highlight the need for placing the domain in the middle of every design, architecture, and implementation decision your teams make.


Reusable Exception Handling for Services – Podcast Episode

November 13, 2010
Want to listen using iTunes?

Using iTunes?

podcast

New episode added to the Software Reuse Podcast Series on designing reusable exception handling for SOA efforts. It elaborates on using a simple set of components for handling exceptions, capturing relevant metadata, and determining notifications.

Like this post? Subscribe to RSS feed or get blog updates via email.


Bringing Events, Processes, and Services Together

November 6, 2010

When working on implementing business process automation solutions, the team needs to bring together several related concepts: chief among them are events, process instances, and service capabilities. I like to think of them in the context of an overall enterprise architecture being aligned with individual solutions and projects. Bringing these concepts together holistically has several benefits:

  • Better alignment between BPM & SOA initiatives (wrote earlier about the risks of not doing so)
  • Consistent interfaces for event producers and consumers (e.g. clients who initiate changes to data or alter a process will be able to reuse a standardized set of messages)
  • Simpler solution architecture – aligning data models across event processing and services will reduce data transformation needs. It will greatly reduce the need for data mapping and complex adapters.

Events can be internal or external and can impact business processes in several ways. An external event could initiate a business process (thereby a new process instance is created), or alter an existing process (execution is moved from some kind of wait state or an existing instance could be terminated). These events could be data, state, or a combination of the two impacting a business process. The business process instance might take an alternate path or spawn a new instance of another process as appropriate.

Process instances themselves can be implemented by leveraging several service capabilities. These service capabilities need to share a consistent set of domain-relevant interfaces. The process instances can then be loosely coupled with services thus enabling the service implementations to evolve over time. As state changes happen in a process instance, outbound events can be generated – these are publications or notifications that are of interest to potentially multiple consumers. Service capabilities can be leveraged for not just creating/changing data but also when encapsulating business rules for decision steps, as well as for publishing messages to downstream systems/processes.


Service Enable Business Processes

October 9, 2010

Business processes hosted in a BPM container (whether running in-process or as an external engine) need to be exposed to consumers in your enterprise. Here’s where your SOA efforts can come in handy – these business processes can be exposed as services via interfaces provided in the service mediation layer. Doing so decouples the vendor specific business process interfaces from enterprise consumers and allows for additional horizontal capabilities to be hooked in (metrics capture, monitoring, authentication, authorization etc.).

So what can these services do? Here’s a very simplified diagram of how these services fit in:

These services are commonly referred to as Task Services and they encapsulate operations on business processes.  Common domain-relevant schemas can be leveraged from other services efforts – facilitating consistency and reduce data transformations between the business and services layers.


5 Reasons for Building Tactical Services

October 7, 2010

Tactical services introduce higher than necessary coupling between service providers and consumers and have brittle contracts that forcing service implementation changes on consumers. They do not reuse standard schemas and datatypes increasing data transformation and integration costs and could tightly couple service business logic and transport-specific logic.

In short, tactical services inhibit reusability, increase maintenance costs and reduce the overall effectiveness of service oriented architecture (SOA) efforts.

So, why do teams end up with tactical services? Here are five reasons:

  1. Lack of time to design proper service interfaces – service contracts are rushed to clients exposing needless internal details, introducing redundant business object definitions, and providing inconsistent behavior
  2. Lack of a conceptual data model – if there isn’t a conceptual data model, capturing key domain concepts and their relationships – it is natural that multiple service operations start to define concepts in their unique way.
  3. Insufficient coordination between teams building service capabilities within the domain – when teams don’t talk to each other, many opportunities to reuse schemas, service semantics, behavior, and utilities are lost. As the number of teams increase, there is a greater need for service governance and alignment across projects.
  4. Lack of coherent strategy tying business process management, business events, and messaging within the context of service development. Business processes could be service enabled and standard business schemas can be used to notify interested consumers. However,without an overall strategy – teams will look at these independently thereby increasing implementation costs and missing opportunities for greater alignment.
  5. Insufficient technical leadership – when confronting multiple projects that are either occurring within a short time window or back to back, it is critical to demonstrate leadership. Why? there needs to be strong voice evangelizing use of business facing services, loosely coupled interfaces, and mediating service requests.

Leverage the Service Refactoring Pattern

September 6, 2010

The Service Refactoring pattern facilitates changes in service logic and/or underlying service implementation while preserving existing consumer contracts.

The Service Refactoring pattern allows the service provider to change the service implementation while preserving existing service contracts. This allows the provider the flexibility to honor existing consumers while taking advantage of streamlined service logic and/or better technologies. If this idea sounds familiar, it is based on the refactoring principles and techniques advocated by Martin Fowler in the object oriented design paradigm and aims to achieve the same result for services in a SOA context. This pattern requires the development of an adapter – that will translate messages conforming to the existing contract into the refactored contract and vice versa.

This pattern:

  • Allows for phased migration of consumers who use existing contract to a new one
  • Allows the provider to upgrade/enhance service behavior in phases. The refactoring can be accomplished via multiple steps and don’t all have to be bundled in a single release
  • Eliminates the need for consumers to change code to take advantage of refactored service
  • Allows new consumers to bind to the enhanced service contract and allows for new and existing consumers to co-exist
  • Potentially enhance performance, availability, and scalability as new consumers come on board

There is a need for strong and coordinated service governance to make sure that consumers are aware of the refactoring effort, retest to validate the behavior, and ultimately provide sign-off for the service capability to be turned on in a production environment. At a minimum, this pattern needs to make sure that existing consumers conduct regression testing to guarantee that the refactored service doesn’t necessitate code changes.


Follow

Get every new post delivered to your Inbox.