<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Honest to a Segfault &#187; Encapsulation</title>
	<atom:link href="http://blog.cdleary.com/tag/encapsulation/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.cdleary.com</link>
	<description>__author__ = &#039;Chris Leary&#039;</description>
	<lastBuildDate>Sun, 05 Sep 2010 20:41:11 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Eliminating web service dependencies with a language-specific abstraction barrier</title>
		<link>http://blog.cdleary.com/2009/04/eliminating-web-service-dependencies-with-a-language-specific-abstraction-barrier/</link>
		<comments>http://blog.cdleary.com/2009/04/eliminating-web-service-dependencies-with-a-language-specific-abstraction-barrier/#comments</comments>
		<pubDate>Thu, 09 Apr 2009 16:00:36 +0000</pubDate>
		<dc:creator>cdleary</dc:creator>
				<category><![CDATA[Best Practices]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[The Web]]></category>
		<category><![CDATA[Thoughts]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Data Structures]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[Encapsulation]]></category>
		<category><![CDATA[Gentlemen's Privacy]]></category>
		<category><![CDATA[Indirection]]></category>
		<category><![CDATA[Pragmatic Programming]]></category>
		<category><![CDATA[Problem Domain]]></category>
		<category><![CDATA[Web Services]]></category>
		<category><![CDATA[WSDL]]></category>

		<guid isPermaLink="false">http://blog.cdleary.com/?p=473</guid>
		<description><![CDATA[Hyperbolic analogy: Saying, "You shouldn't need to wrap the web service interface, because it already provides an API," is like saying, "You shouldn't need different programming languages, because they're all Turing complete." [...]]]></description>
			<content:encoded><![CDATA[<p>Hyperbolic analogy: Saying, &#8220;You shouldn&#8217;t need to wrap the web service interface, because it already provides an API,&#8221; is like saying, &#8220;You shouldn&#8217;t need different programming languages, because they&#8217;re all Turing complete.&#8221;</p>
<p>Web services tend to deliver <em>raw data</em> payloads from a flat interface and thus lack the usability of native language APIs. Inevitably, <strong>when you program RPC-like interfaces for no language in particular, you incur incompatibilities for every <em>particular</em> language&#8217;s best practices, idioms, and data models</strong>. <tt>[*]</tt> The issue of appropriately representing exceptions and/or error codes in RPC-like services is a notorious example of this.</p>
<p>There are additional specification mechanisms like <a href="http://en.wikipedia.org/wiki/Web_Services_Description_Language#Example_WSDL_file">WSDL</a> <tt>[@]</tt> that allow us to make the payloads more object-like. Additional structure is indicated through the use of user-defined &#8220;complex types,&#8221; but this only gets you part of the way to a usable API for any given language. In Python, it&#8217;s a lot more sensible to perform an operation like in the following abstraction:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> internal_tracker.<span style="color: black;">service</span> <span style="color: #ff7700;font-weight:bold;">import</span> InternalTracker
bug_serivce = InternalTracker<span style="color: black;">&#40;</span>username=<span style="color: #dc143c;">getpass</span>.<span style="color: black;">getuser</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>,
    password=<span style="color: #dc143c;">getpass</span>.<span style="color: #dc143c;">getpass</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
bug = bug_service.<span style="color: black;">get_bug</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">123456</span><span style="color: black;">&#41;</span>
bug.<span style="color: black;">actionable</span>.<span style="color: black;">add</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Chris Leary'</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># may raise ReadOnlyException</span>
comment = Comment<span style="color: black;">&#40;</span>text=<span style="color: #483d8b;">'Adding self to actionable'</span><span style="color: black;">&#41;</span>
bug.<span style="color: black;">arbs</span>.<span style="color: black;">add_comment</span><span style="color: black;">&#40;</span>comment<span style="color: black;">&#41;</span>
bug.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># may raise instanceof ServiceWriteException</span></pre></div></div>

<p>Than to use an external web service API solution directly (despite using the excellent <a href='https://fedorahosted.org/suds/'>Suds library</a>):</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Boilerplate</span>
client = suds.<span style="color: black;">client</span>.<span style="color: black;">Client</span><span style="color: black;">&#40;</span>wsdl=wsdl_uri<span style="color: black;">&#41;</span>
security = suds.<span style="color: black;">wsse</span>.<span style="color: black;">Security</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
security.<span style="color: black;">tokens</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>UsernameToken<span style="color: black;">&#40;</span><span style="color: #dc143c;">getpass</span>.<span style="color: black;">getuser</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>,
    <span style="color: #dc143c;">getpass</span>.<span style="color: #dc143c;">getpass</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
client.<span style="color: black;">set_options</span><span style="color: black;">&#40;</span>wsse=security<span style="color: black;">&#41;</span>
internal_tracker_service = client.<span style="color: black;">service</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Usage</span>
service_bug = internal_tracker_service.<span style="color: black;">GetBug</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">123456</span><span style="color: black;">&#41;</span>
service_bug.<span style="color: black;">actionable</span> += <span style="color: #483d8b;">', Chris Leary'</span>
<span style="color: #808080; font-style: italic;"># Do we check the response for all WebFault exceptions?</span>
<span style="color: #808080; font-style: italic;"># (Do we check for and handle all the possible transport issues?)</span>
internal_tracker_service.<span style="color: black;">UpdateBug</span><span style="color: black;">&#40;</span>service_bug<span style="color: black;">&#41;</span>
Comment = internal_tracker_service.<span style="color: black;">factory</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'Comment'</span><span style="color: black;">&#93;</span>
comment = Comment<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
comment.<span style="color: black;">BugId</span> = service_bug.<span style="color: black;">Id</span>
comment.<span style="color: black;">Text</span> = <span style="color: #483d8b;">'Adding self to actionable'</span>
<span style="color: #808080; font-style: italic;"># Again, what should we check?</span>
internal_tracker_service.<span style="color: black;">AddComment</span><span style="color: black;">&#40;</span>comment<span style="color: black;">&#41;</span></pre></div></div>

<h3>Why is it good to have the layer of indirection?</h3>
<p>Lemma 1: The former example <strong>actually reads like Python code</strong>. It raises problem-domain-relevant exceptions, uses keyword arguments appropriately, follows language naming conventions, and uses sensible language-specific data types that may be poorly represented in the web service. For example, <tt>actionable</tt> may be a big comma-delimited string according to the service, whereas it should clearly be modeled as a set of (unique) names, using Python&#8217;s <tt>set</tt> data type. Another example is <tt>BigInteger</tt>s being poorly represented as strings in order to keep the API language-neutral.</p>
<p>Lemma 2: The layer <strong>represents an extremely maintainable abstraction barrier</strong> between the client and the backing service. Should a team using the abstraction decide it&#8217;s prudent to switch to, say, Bugzilla, I would have no trouble writing a port for the backing service in which all client code would continue to work. Another example is a scenario in which we determine that the transport is unreliable for some reason, so decide all requests should be retried three times instead of one. <tt>[!]</tt> How many places will I need to make changes? How many client code bases do I potentially need to keep track of?</p>
<h3>Why is it risky to use the web service interface?</h3>
<p>If the web service API represents the problem domain correctly with constructs that make sense for your language, it&#8217;s fine to use directly. (As long as you&#8217;re confident you won&#8217;t have transport-layer issues.) If you&#8217;re near-certain that the backing service <em>will not change</em>, and/or you&#8217;re willing to risk all the client code that will depend on that API directly being instantaneously broken, it&#8217;s fine. The trouble occurs when one of these is not the case.</p>
<p>Let&#8217;s say that the backing service <em>does</em> change to Bugzilla. Chances are that <strong>hacking in adapter classes for the new service would be a horrible upgrade experience</strong> that entails:</p>
<ol>
<li>Repeated discovery of <a href="http://www.joelonsoftware.com/articles/LeakyAbstractions.html">leaky abstractions</a>,</li>
<li>Greater propensity to bugs, <tt>[^]</tt> and
<li>More difficult maintenance going forward.
</ol>
<p>Client code that is tightly coupled to the service API would force a rewrite in order to avoid these issues.</p>
<p><a href="http://www.pragprog.com/">Pragmatic Programming</a> says to <em>rely on reliable things</em>, which is a rule that any reasonable person will agree with. <tt>[&amp;]</tt> The abstraction barrier is reliable in its loose coupling (direct modeling of the problem domain), whereas direct use of the web service API could force a reliance on quirky external service facts, perhaps deep into client code.</p>
<h3>Is there room for compromise?</h3>
<p>This is the point in the discussion where we think something along the lines of, &#8220;Well, I can just fix the quirky things with a bunch of shims between my code and the service itself.&#8221; At that point, I contend, you&#8217;re really just implementing a half-baked version of the language-specific API. It&#8217;s better to make the abstractions appropriate for the target language and problem domain the <em>first time</em> around than by incrementally adding shims and hoping client code didn&#8217;t use the underlying quirks before you got to them. Heck, if the web service is extremely well suited to your language, you&#8217;ll end up <a href="http://en.wikipedia.org/wiki/Proxy_pattern">proxying</a> most of the time anyway, and the development will be relatively effortless. <tt>[$]</tt></p>
<h3>What about speed of deployment?</h3>
<p><em>If we have language-specific APIs, won&#8217;t there be additional delay waiting for it to update when additional capabilities are added to the backing service?</em></p>
<p>First of all, if the new capability is not within the problem domain of the library, it should be a separate API. This is the <a href='http://en.wikipedia.org/wiki/Single_responsibility_principle'>single responsibility principle</a> applied to interfaces &#8212; you should be programming to an interface abstraction. Just because a backing service has a hodgepodge of responsibilities doesn&#8217;t mean that our language-specific API should as well. In fact, it probably shouldn&#8217;t. Let&#8217;s assume it <em>is</em> in the problem domain.</p>
<p>If the functionality is sane and ready for use in the target language, it should be really simple for the library owner to extend the language-specific API. In fact, if you&#8217;re using the proxy pattern, you may not have to do anything at all. Let&#8217;s assume that the functionality is <em>quirky</em> and you&#8217;re blocked waiting for the library owner to update with the language-specific shim, because it&#8217;s non-trivial.</p>
<p>Now our solution tends to vary based on the language. Languages like Python have what&#8217;s known as &#8220;gentlemen&#8217;s privacy&#8221;, based on the notion of a <a href='http://en.wikipedia.org/wiki/Gentlemen%27s_agreement'>gentlemen&#8217;s agreement</a>. Privacy constraints are not enforced at compile-time and/or run-time, so you can just reach through the abstraction barrier if you believe you know what you&#8217;re doing. Yes, you&#8217;re making an informed decision to violate encapsulation. Cases like this are exactly when it comes in handy.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">assert</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>bug_service, <span style="color: #483d8b;">'super_new_method_we_need'</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># HACK: Violate abstraction -- we need this new capability right now</span>
<span style="color: #808080; font-style: italic;"># and Billy-Bo, the library owner, is swamped!</span>
suds_client = bug_service._suds_client
result = suds_client.<span style="color: black;">SuperNewMethodWeNeed</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
target_result = de_quirkify<span style="color: black;">&#40;</span>result<span style="color: black;">&#41;</span></pre></div></div>

<p>As you can see, we end up implementing the method <tt>de_quirkify</tt> to de-quirk the quirky web service result into a more language-specific data model &#8212; it&#8217;s bad form to make the code dependent on the web service&#8217;s quirky output form. We then submit our code for this method to the library owner and suggest that they use it as a basis for their implementation, so that a) they can get it done faster, and b) we can seamlessly factor the hack out.</p>
<p>For privacy-enforcing languages, you would need to expose a public API for getting at the private service, then tell people not to use it unless they know what they&#8217;re doing. As you can tell, you pretty much wind up with gentlemen&#8217;s privacy on that interface, anyway.</p>
<h3>Footnotes</h3>
<p><tt>[*]</tt> In EE we call this kind of phenomenon an <a href="http://en.wikipedia.org/wiki/Impedance_mismatch">impedance mismatch</a>, which results in power loss.<br />
<tt>[@]</tt> And many others, with <a href="http://xmlsucks.org/but_you_have_to_use_it_anyway/">few successful ones</a>.<br />
<tt>[!]</tt> Or maybe we want to switch from HTTP transport to SMTP. Yes, this is actually possible. :-)<br />
<tt>[^]</tt> In duplicating exact web service behaviors &#8212; you have to be backwards compatible with whichever behaviors the existing client code relies on.<br />
<tt>[&amp;]</tt> It&#8217;s a syntactic tautology. The caveat is that reasonable people will almost certainly quibble over the classification of <em>what&#8217;s</em> reliable.<br />
<tt>[$]</tt> At least in Python or other languages with a good degree of dynamism, it will.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cdleary.com/2009/04/eliminating-web-service-dependencies-with-a-language-specific-abstraction-barrier/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
