Component Configuration – a design conversation

A recent conversation led me to want to write down a design train of thought. Perhaps some might might find it interesting. And others could point out flaws or better principles that I missed along the way.

Background
A requirement existed for a component to expose a client interface to a web API that is also being written. This client component then could get reused by different applications consuming the web API.

As the web API and client component are both developed by the same developers, it would be desirable to stand up different instances of the web API- such as staging and production – and to have different instances of the application consuming the component to talk to those different web API instances to test staging or consume the production installation.

The design question

Where do we define the URL that the component should talk to?

Do we encapsulate the knowledge about the URL(s) in the component?
Or do we pass the URL to call to the component?

What if the component knows about about the URL directly?
The application then just calls the component and the component just talks to the right url and magic happens. That is pretty awesome! I love the fact that my consuming applications don’t need to care. But…

But I now have unexpected coupling to the application’s deployment strategy
What does that mean for deployment? When I deploy the application to development, staging, UAT or production there might be different URLs that the component needs to call. Those URLs might be different depending on the environments defined for the application – or the application consuming the component. Hmmm… that means that my deployment needs to know about my component to set up the URL for the component. Or my component needs to know about my deployment environments in order to select the right URL. That really doesn’t feel great. Knowledge of my different deployment environments are bleeding into my simple component. Yes, I could possibly minimise it by using a convention, but it is feeling a lot less clean now. I’m not a fan of this anymore.

What if my application tells the component what the URL is?
My application deployment already has to deal with setting different values depending on the environment. I think I’d rather extend those existing working mechanisms rather than start Yet Another Way of handling different environments and coupling my component to the deployment mechanisms of each application that consumes it. And I don’t want to couple every component to all the consuming applications deployment scenarios. That wouldn’t feel great.

Hmmm… so I feel like the application managing the URL endpoint that the component calls is cleaner for now.

But I did like the ease of use of the original suggestion. I wonder if I could still achieve that.

Another design question

How does the component get to know the URL?

set_url
One option is something like:

 Component.set_url( ‘www.url.org’ );
 the_things = Component.fetch_all_the_things

This looks nice and simple. But, what is to stop the consumer from not calling set_url? What do we do then? And also – could we get back to the original simple scenario of just doing

 the_things = Component.fetch_all_the_things

Ah – but we could make it a static URL and call set_url on application start up. That way we don’t have to worry about not calling it as it will have been called at initialisation.

But what happens if we do get into our code with the URL not set? What should happen then?

Temporal Coupling
We have some implicit temporal coupling between the setting of the URL and the calling of the component. I’ve made it even worse by “fixing” it by moving the set_url call into the application start up in order to achieve my simple component call.

I’m not sure I like the temporal coupling. I could live with it. But surely there is a better way? One in which I am less likely to get into trouble with down the road?

Pass the configuration information always

Another idea to solve the temporal coupling is to do something like

 the_things = Component.fetch_all_the_things( ‘www.url.org’ )

Or

 client = Component.new( ‘www.url.org’ )
 the_things = client.fetch_all_the_things

Both of these solve the problem. But now I need pass the URL every time I want to do my simple component call that I’ve been chasing. But I have removed the temporal coupling problem. And replaced it with a configuration problem as whenever I use the component I need to be able to get the URL and pass it to the component. Hmmm… is there a way to make this simple for the client.

I feel like this is a better solution. If I use the second option above

 client = Component.new( ‘www.url.org’ )
 the_things = client.fetch_all_the_things

I have a creation problem – how can I make the creation of the client object simple so that my callers could not need to worry about URLs?

What about a Factory?

What about a factory class or method that returns Component.new( ‘www.url.org’ ). All creational logic to select the correct URL for production or staging can be handled here. It could also cache the creation of the component in a singleton if needed.

Then our caller becomes

 client = ComponentFactory.GetComponent
 the_things = client.fetch_all_the_things

This is still 2 lines of code. But it is 2 lines of code that expresses the intent pretty well and doesn’t require the caller to concern itself with the URL at all. And the factory that I would need to write for my application would also be very simple. It would need to know how to find the correct URL and then create the component object created with the URL. I am pretty happy with this. It feels simple for the callers. And I can keep the URL to point to in the application. And the component can simply talk to that URL keeping it simple.

Could we do better?
Could we make it one line? We could maybe use the proxy pattern and simply hide all the interactions completely. But then we may be doing all the work that the component was supposed to be doing for us in the application as well as we’d need a proxy for each wrapped API call. That feels like I’d create even more application code in order to make it simpler for the application to call the API. But by writing that application code I’ve increase the complexity of the application.

Conclusion
This isn’t the only implementation, but based on the requirements it feels like a reasonable one. If for instance there could only ever be 1 end point that we talked to for a third party connection then maybe encapsulating that in the component could be a good idea. But then testability might continue to drive the design to want to be in a factory inside the component instead of simply embedded in the code somewhere next the the API call that calls it.

I feel like this is a reasonable flow of thoughts leading to a simple, thought out solution. Hopefully others find it useful. And if you have other values / principles that come to bear that would have lead to another solution – let me know – I’d love to hear them.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s