Facilitate Reuse Through Interfaces

March 10, 2013

Predicting and designing for systematic reuse is hard – in trying to design for future requirements, team often bake in accidental complexity. One effective way to avoid that trap is to separate your concerns via well designed interfaces. It is important to point out that although separating concerns is essential, which ones to prioritize and plan for is heavily dependent on your problem domain. Additionally, it is not pragmatic to provide for variability across all points in your design.

Here is an example of facilitating reuse via interfaces – the example class takes a ReportResult object and needs to format them into a variety of formats (XML, PDF, etc.). Although this is a simple example it is powerful – as new requirements for supporting additional formats arise it can gracefully be extended. Plus, more importantly, formats that aren’t required don’t have to be implemented until there is a real requirement.

public interface Formatter {
    public T format(ReportResult reportResult) ;
}

The above can be implemented using specific formatters as shown below:

public class XmlFormatter {
    public String format(ReportResult reportResult)  {
       //implement logic for XML formatting
    }
}

With the report generation and formatting separation in place, additional formatters can be implemented with ease – e.g. PdfFormatter, HtmlFormatter, or PlainTextFormatter, etc. This decouples formatting logic from report generation classes thus enabling reuse for the report generation functionality.


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.


Build for Use, then Refactor to Reuse

July 11, 2010

You want to build reusable assets in an agile manner – avoiding a significant design effort upfront and evolving behavior over time.  Why? Because building for reuse involves several steps: the right abstractions have to be identified, appropriate variations have to be modeled and accounted for, and the asset has to be generic enough for use beyond a single project.

This is hard to get right the first time – often, business requirements aren’t clear from the early on making it tricky to identify reusable assets. More importantly, reuse adds project risk – specifically risk to the timeline. Always ask yourself if it is worth making the extra investment – if you aren’t sure delay commitment.

Capture possible enhancements to your codebase via an issue tracking tool and you can always assign those enhancements to future iterations. When you implement a story and you see the opportunity for making something reusable, consciously align classes and interfaces for reuse. Refactor, refactor, and keep refactoring – because only with multiple iterations is your asset going to be increase it’s reuse potential. Remember – very often, the asset would not be used as-is. It will need changes – patches, enhancements, major redesign even – before it can be leveraged across projects.


5 Advantages of Using Interfaces for Designing Reusable Assets

April 24, 2010

Interfaces are fundamental to good design and more important when designing resuable assets. They provide several benefits:

  1. They model key behaviors that need to be supported – by designing interfaces, you are forced to partition a big chunk of functionality into a set of behaviors. The amount of detail in each interface varies but the very act to thinking through behaviors will provide a more loosely coupled design.
  2. Provides flexibility to change parts of a module/sub-system at anytime. This is specially relevant with projects where knowledge accumulates over time and domain understanding is unclear in during project inception. Interfaces help switch to a better implementation without adversely impacting the rest of the codebase (assuming, the contract stayed the same or only minimal changes were required).
  3. Explicitly support variability in an asset based on a defined set of behaviors. Interfaces are useful to encapsulate variations in a particular step (using Strategy), how different behaviors are combined (using pipe/filter) , or several steps in an overall algorithm (template method).
  4. With reusable assets, when you provide interfaces as contracts to your consumers – it gives you the freedom to change implementations and not break them. Note: this can be comforting but unless you ensure your consumers don’t instantiate concrete classes and don’t bypass integration-facing contracts there is no guarantee that they won’t break.
  5. Interfaces can potentially out live the implementation. This is related to #2 – as you learn new technologies, new ways to solving problems, interfaces give you the freedom to swap to a better implementation at any time. The interfaces that model domain concepts tend to be more stable as well – core business concepts don’t change overnight. However, business practices do change more frequently and the flexibility to combine and recombine concepts – conveniently captured using interfaces – is very powerful.

In a recently concluded project, I realized these benefits first-hand. The initial implementation of a search service was to go against the database directly. After a couple of iterations, we realized the need for a more effective and efficient solution – an indexed search engine. Even though the search module was used by several consumers the switch to a search engine based implementation was faster, more scalable, and most importantly, didn’t force consumers to make code changes.


Refactor Reusable Assets With Domain Understanding

April 18, 2010

There is always an element of additional complexity when building resuable assets – whether it is because of externalizing configuration, adding additional interfaces/classes to provide flexibility, or introduction of additional layers of abstraction (to name a few). There is also the increased cost of design, testing, and integration with reusable assets. The question isn’t whether reusable assets are more or less complex – a more pragmatic question would be:

is the additional complexity absolutely essential and worth the cost?

This is a straightforward question to answer if you have visibility into what is coming up in the near future. If this isn’t the case – which is “most of the time” – the question becomes a trickier one. One way to address this issue is to introduce domain-relevant abstractions.

Instead of guessing what should and shouldn’t be an abstraction – work with domain experts and uncover true domain-relevant concepts. For example: Let’s say you decide to build a reusable library for providing customer data. Say this is used to populate a financial statement that shows a customer’s net worth (i.e. financial assets). Initially your software might have used the checking account balance to report this value. Why? Because, that was the only kind of account that was used to calculate this value. In the initial version the team might have thought ‘net worth’ was a data attribute – a number that is derived from the checking account balance. Over time, as domain understanding deepens, ‘net worth’ might become – not just a single account’s balance but a whole host of other things (e.g. accounts where the customer is a joint account holder including not only checking accounts but also savings, brokerage, etc.). ‘Net worth’ might still be a single number but it would have evolved to encompass a different meaning than just a single account’s balance. Not to mention business rules that have to be applied based on a plethora of account and client characteristics and quickly this would evolve into something more complex.

At the time of the initial release your team might not have this knowledge – and that is perfectly okay! Key is to evolve the codebase along with your increased understanding of the domain. Will net worth be it’s own class or interface in the initial version? If you don’t have even the preliminary understanding, why introduce needless complexity? wouldn’t it be better to refactor to reuse rather than build for reuse with an imperfect understanding?


Refactoring to Reuse #4

November 13, 2009

#4 Separate Message Construction from Message Delivery

There are a variety of scenarios where you will build a message and deliver it to a destination. The message itself could be free-form text, delimited/fixed-length text, XML, or some other format. The destination itself could be a system, service, application, a server, or a human user or group of users (in the case of email). If you decouple message construction from its destination, that will drive in reuse of both of these assets. For example, you can take a message and send it via email or send to a message queue. In the same vein, you can potentially use the same code that sends email to send a newsletter message and a reminder message.

To illustrate this idea, take a look at this code fragment:

MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO,
new InternetAddress("someone@xyz.com"));
message.setSubject("Hello there...");

FileReader fr = new FileReader("some-template.html");
StringBuffer sb = new StringBuffer();
BufferedReader reader = new BufferedReader(fr);
String line = reader.readLine();
while (line != null) {
     sb.append(line);
     line = reader.readLine();
}
reader.close();

message.setText(sb.toString());
// Send message
Transport tr = session.getTransport("smtp");
tr.connect("host-name", "user", "some-password");
message.saveChanges();
tr.sendMessage(message, message.getAllRecipients());
tr.close();

There is a file that is read from the file system and a data buffer is being constructed. The data is then used to send an email. However, this class isn’t very reusable because of the tight coupling between message construction and delivery logic.

Now examine, a newer version that has modularized this code – Publisher sends the message using an EmailConfiguration and TemplateBuilder constructs the message using an instance of Template.

Publisher publisher = new Publisher();
EmailConfiguration eConfig = new EmailConfiguration();
publisher.setConfiguration(eConfig);
TemplateBuilder builder = new TemplateBuilder();
Template template = builder.build();
publisher.publishMessage(template);

Now, Publisher, EmailConfiguration, Template, and TemplateBuilder are all candidate assets that are available for other classes to reuse. If you have other types of configurations, they can be included as well and bound polymorphically. This concept can be further extended based on the quantity and quality of variations. For instance, the message construction can be realized using a common interface with multiple implementations. The message itself might have standard and personalized content.

You may move to a more modular version iteratively. Which version do you think facilitates reuse, faster integration, and higher productivity? This new design will make it easier to test message construction independently from publisher.
Like this post? Subscribe to RSS feed or get blog updates via email.

tweet this add to del.icio.us post to facebook

MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO,
new InternetAddress("someone@xyz.com"));
message.setSubject("Hello there...");

FileReader fr = new FileReader("some-template.html");
StringBuffer sb = new StringBuffer();
BufferedReader reader = new BufferedReader(fr);
String line = reader.readLine();
while (line != null) {
     sb.append(line);
     line = reader.readLine();
}
reader.close();

message.setText(sb.toString());
// Send message
Transport tr = session.getTransport("smtp");
tr.connect("host-name", "user", "some-password");
message.saveChanges();
tr.sendMessage(message, message.getAllRecipients());
tr.close();

Create interfaces from a product line context

October 20, 2009

If you ask developers about interfaces they typically build you will hear some form of create, read, update, and delete (CRUD). CRUD-type interfaces are simple to understand and are intuitive. They tend to be used heavily in the data access layer operating on your various data entities. At a high level these interfaces seem to meet your product line needs. This may not always be the case though! Why do I say this? The interfaces you create for a product line depends on the variations you need to support and manage. Variations will require interfaces that vary in granularity. Some operations might operate on a data entity while others might operate on an aggregate. Still others might operate at a subset of a data entity. For example, say you develop solutions for the banking product line where in you have an online portal, mobile bank, and branch services. All these products in your product line might support money transfer. Online portal might display a complete set of from and to accounts while mobile might display only a primary account. Branch might provide only accounts eligible when initiated by a branch. To address the variations you have to go beyond just getting the right set of accounts and have a reusable asset use a mechanism to access and execute business rules.

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

tweet this add to del.icio.us post to facebook


%d bloggers like this: