November 3, 2013
Here are some tips when authoring web service clients:
- Decouple connectivity from request construction. This will isolate variations in input construction and the mechanics of service invocation cleanly separated. Additionally, the request construction might depend on the particular resource – e.g. they can be set of query string parameters or a more complex object structure.
- Connectivity logic should encapsulate the service URL and automatic-retry considerations. The client can automatically retry GET requests specified number of times if invocation encounters a connection timeout. It should also ensure response is OK (either via HTTP status codes or by examining appropriate response-specific data structures).
- Don’t swallow exceptions – the service might return a resource not found or an internal server error – the code that is using the client should be given the flexibility to deal with these exceptions appropriately – the client code shouldn’t assume or mask these exceptions. When in doubt, don’t suppress runtime exceptions.
- Decouple domain logic from service client – domain logic might dictate whether or not a service call needs to be made, or the nature of input resource data, etc. – this logic is more likely to change per the consuming application’s evolving requirements and shouldn’t be hosting service invocation code in the same class.
- Provide reusable API hooks for addressing cross-cutting concerns – such as response time capture and input and output messages – if you want to report response time trends when invoking a service you will not want to clutter this all over the consuming application’s codebase – the client can and should centralize these.
Remember the above is useful whether you are consuming a service or providing clients for your prospective service consumers.
November 2, 2013
Reading the book Code Simplicity by Max Kanat-Alexander. When you have to make lots of design improvement and implementation decisions it is important to keep our solutions simple. Reducing complexity is an important aspect of good code and particularly relevant to systematic software reuse – so hoping to learn new concepts from this book.
You might want to also check out Max’s interview on the rewards of simple code.
November 2, 2013
You can wait for that dream initiative or project to build a whole new set of reusable components that will magically make your teams more productive. The only issue is – it is highly likely that it will be just that – a dream. Instead of planning for systematic reuse, start executing on it by taking a few simple steps. Ask yourself the following questions:
1. Are you capitalizing on identifying and sharing common components with your department / team?
2. Is every project encouraged to continuously refactor and harmonize classes for reducing redundancies? If not, why not?
3. Do you have code that caters to common infrastructural concerns – logging, exception management, alerting, monitoring, metrics.? If yes, is their reuse mandated via common framework hooks that your developers are already using? If not, what is preventing adoption of these concerns into your development stack? Ask your developers and listen to their concerns – you will need to unearth and attack the root causes behind reuse barriers.
4. Do you utilize ad-hoc, informal pairing and code review sessions to identify and harmonize similar / duplicate / redundant classes? If you review code the first time before a project go-live, odds are you either will regret missed opportunities or bemoan the lack of time within your development cycle for making improvements. Key is to intervene early and often and front load your investments for systematic reuse
5. How do you ensure reafactoring to reuse opportunities are tracked? do you create improvement tickets and action them on a best-effort basis or are they managed as part of the product backlog of things that have to get done? If its the former, it will be difficult to make much progress. Creating and tracking tickets will will provide visibility – however, for you to make tangible progress in acting on them you need to partner with developers and development managers to action work on an ongoing basis.
These are just example questions to help you get your journey started and it should be abundantly clear that discipline and continuous alignment is key. If you don’t do anything else, just force your team to converge on a common implementation on key functionality. You will be surprised what discipline can deliver.
September 9, 2013
What is the one key aspect of making your APIs reusable? Simply put – reducing the barriers to adoption. It matters because your target audience – architects, developers, and project managers – are all trying to deliver value to their clients. Iteration after iteration. Here are specific strategies to reduce the adoption barriers:
- Make the public API as intention revealing as possible. Looking at the public interface it must be very clear and unambiguous what the purpose and scope is of the reusable capability.
- Provide Builder or abstract factory APIs to stitch together complex object graphs in a simple fashion. Make it very easy to wire up the default behaviour and provide hooks to replace specific bits of behaviour that is varying. For example – if saving to a file is a default, provide alternative implementations or an interface hook for your client to inject a custom one.
- Make it easy to integrate the capability with other complimentary APIs. These could be in-house, open-source, or vendor APIs – key is – if they are likely to co-exist in a solution, make it simple to wire them together. If your developers use Spring for dependency injection, make your components easy to work with when it. Ditto for in-house frameworks that your teams use heavily.
- For reusable assets that perform orchestration logic provide hooks for injecting custom logic before / after your API behaviour This will be useful for initializing / cleanup logic – specially with legacy components that may need a bespoke set of steps to start them or free up resources on shutdown.
- Provide Null and/or mocking friendly implementations for testability. Your clients need to test their code via automated tests and so do you as the provider – both these needs are met via testable providers. Make it easy for developers to use them with JUnit and make it hard for them to bypass the public APIs.
July 21, 2013
There are certain key interception points during the development process that can greatly increase the likelihood of systematic reuse. Some agile practices can really help:
- Estimating User Stories – constantly seek synergies and ways to connect new requirements with existing ones or those from other projects the team is working on. You know you are successful when the most junior member of the team is finding commonalities and points out areas to explore for systematic reuse. Very often however, reality is starkly different – similar, slightly varying functionality gets implemented over and over again across projects due to time constraints, lack of awareness, and implementation considerations – e.g. legacy system won’t be able to use this component” or “the existing system implementation is hard to refactor…”, etc
- Pair programming – the real strength with pairing is the variety in perspectives. One person can go for depth (identify a very efficient algorithm) and another can focus on breadth (identify existing components to reuse/extend or contribute current work). It is also convenient when pairing to switch perspectives and identify ways to improve the code by eliminating what is not necessary. Hard to expect one developer to be your systematic reuse superstar every time across every project.
- Code reviews – this is a rich area for reuse opportunities because of two key reasons – one, the idea is proven – it is in code and executing – not just vaporware. Equally important, it is a chance to re-look at the implementation with a detached perspective. Discover unspoken design assumptions, needless couplings, and free up code to be more extensible. Look for unnecessary 3rd party library dependencies, code quality violations that compromise layering (presentation code invoking database or data access logic having UI formatting logic, etc.), and constantly eliminate duplicate boiler-plate code. Remember – continuous alignment and not perfection is the intent here.
- Retrospective – when discussing what went well and what needs to improve – explicitly invest in learning the team’s challenges with systematic reuse. Listen for key signals from the dev team – do they have access to source code? how easy or difficult is the existing component library? what functional goal can be achieved faster if there was further investment in a reusable component?
June 16, 2013
It is natural to get comfortable, perhaps too comfortable, with the state of your codebase. After all, it works and is probably meeting tangible business needs. However, if your team has to get the full value out of it – the fair and ongoing return on investment – you have to constantly revisit assumptions about the software design and implementation.
Challenging assumptions has a number of benefits for systematic reuse. It opens up opportunities for refactoring assumptions that are no longer relevant / required (e.g. state information has to be saved for recovery). What if that capability is available in your enterprise through another component? Can you swap your implementation? If not, why not?
Similar opportunities exist on both technical and functional sides – the software is always accessed from the app’s web UI (assumption that might have led to code tightly coupled with presentation logic – business rules implemented alongside HTTP header parsing logic). How about assumptions regarding public APIs, nature/sequence of method invocations, client / calling platform, etc.
These assumptions must have made sense and would have been made for a sound reason at the time the codebase was conceived. Question is – are they still relevant? does the code need refactoring to get rid of native implementations or needs to be decoupled from logic that will make it more reusable? All these questions need careful and thoughtful consideration.
Have this discussion as part of your iteration retrospectives, team discussions, and informal conversations. You’ll be surprised about the quantity and quality of assumptions that are holding the codebase back.
May 13, 2013
Here are five questions to ask your teams to increase reuse effectiveness when evaluating a functional requirement:
- Is a requirement already met within the application or platform or is this the first time?
- If the capability already exists, does the current implementation provide the right extensibility? Often, existing code would need refactoring to meet a slightly varying set of requirements when compared to the original one. Take this as an opportunity to tease apart the abstractions necessary to capture the variations. What’s common and what’s truly different is the key aspect to figure out.
- Which other team or application has encountered this functional requirement before and how did they solve it? If you aren’t sure, ask around!
- Do we truly believe we are the first ones to stumble upon this need in the team/department/division/the firm? Try “laddering up” – as the Heath brothers call it in their latest book Decisive – incrementally and deliberately extract the key aspects of the problem you are trying to solve and look for places where solutions already exist.
- If you find existing code to meet your need – evaluate it with a critical eye towards non-functional needs. Is it performant enough to meet the needs of your use case? does it provide adequate extension points / hooks to integrate with the rest of your application? is it a library or a hosted service? If hosted, what is the resiliency and availability strategy?
Too often, there is a bias towards implementing from the ground up due to either lack of time (don’t want to find out if other implementations or existing solutions exist and if they do, would they fit) or lack of trust (don’t want to use this team’s software or codebase or don’t trust that the quality of the implementation).
These aren’t exhaustive – what other questions come to mind?