<br><br><div class="gmail_quote">On Fri, Aug 9, 2013 at 9:41 AM, H.C. v. Stockhausen <span dir="ltr"><<a href="mailto:hc@vst.io" target="_blank">hc@vst.io</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hello,<br>
<br>
I need a DB backend for my application but I'd like to be able to swap<br>
it out for different DBs if I choose so later on.<br>
<br>
I would like to code against an interface and tell the application<br>
what specific backend to use through config rather than code changes.<br>
<br>
Is there a pattern for doing that? Hot code upgrades and multi-node<br>
are not a real concern at this time - mostly, since I have no<br>
experience yet with either - however if doing it right means taking<br>
that into account too I'd also like to learn more about that.<br>
<br>
I am thinking of defining a custom behaviour ("my_crud" perhaps), then<br>
to implement it for various DBs and to also let a config driven<br>
adapter implement it that I then use to throughout the code to talk to<br>
the DB layer.<br>
<br>
For example, using Mnesia and AWS DynamoDB:<br>
<br>
- my_crud.erl (behaviour)<br>
- my_db_mnesia.erl (implements behaviour)<br>
- my_db_dynamo.erl (implements behaviour)<br>
- my_db.erl (configurable adapter that also implements behaviour)<br>
- my.config<br>
<br>
my_db:insert(Key, Value).<br>
<br>
Is that a reasonable approach that makes proper use of Erlang and<br>
behaviours or is this just not how one should do it?<br></blockquote><div><br></div><div>Yes - this is fine</div><div><br></div><div>But ...</div><div><br></div><div>Firstly, this might be overkill. One of the real reasons for the import declaration was to be able to</div>
<div>flip the back-end implementation while providing a common interface library:</div><div><br></div><div>So we'd write:</div><div><br></div><div> -module(xxx).</div><div> -import(my_mnesia_backend, [insert/2, lookup/1, ...])</div>
<div><br></div><div> foo(X) -></div><div> insert(X, ...)</div><div> </div><div> and so on.</div><div><br></div><div> To change the backend you just change the name of the module in the import declaration</div>
<div><br></div><div> That was the idea - but in practice very few libraries are written with compatible back-ends</div><div><br></div><div>The second problem with doing this is that it turns out to be extremely difficult to make a common</div>
<div>front-end - this is essentially the least common denominator of the all the services offered by the</div><div>individual databases.</div><div><br></div><div>There are often very good reasons why databases are different - they offer different services.</div>
<div><br></div><div>I recently considered making a common front-end for dets and basho's bitcask - this seems reasonable</div><div>both are disk based key-value crash tolerant stores, so this seemed like a good idea, I'd be able to use one store and then flip to the other if circumstances changed.</div>
<div><br></div><div>The problem is that dets and bitcask are rather different - they *have* to be, otherwise why would the basho guys write bitcask. ets and dets play nicely together (ets:from_dets :-) - ets keys and values are terms. bitcask keys and values are binaries. Which will the common interface have? - if you choose (say) terms</div>
<div>you'll bias the interface in favour of dets.</div><div><br></div><div>So now we have a problem - two interfaces can be *functionally* equivalent (ie offer the same interface in terms of types) but the non-functional properties of the interface might be completely different.</div>
<div><br></div><div>For example database1 might be optimised for fast reads/slow writes. Database2 might be optimised for fast writes.</div><div><br></div><div>It seems to me that the non-functional parts of a system are the bits that are difficult to get right -</div>
<div>making things (fault- tolerant, scalable, upgradable, ... etc.) is far more difficult than getting types</div><div>and interfaces right.</div><div><br></div><div>There are two approaches to making a system with a database: </div>
<div><br></div><div>1) Choose the database first - make your mind up</div><div>2) Implement everything</div><div><br></div><div>or</div><div><br></div><div>1) Make an abstraction layer</div><div>2) Write application and interface layers</div>
<div>3) configure and decide on database later</div><div><br></div><div>The hope is that by choosing the second approach, you save work since if you chose the wrong</div><div>database you can just change the backend later.</div>
<div><br></div><div>The problem here is that the non-functional behaviour of the backend you choose causes feature</div><div>creep in the front end. If the backend has fast reads and slow writes, the front-end software will endup having a design that reflects this.</div>
<div><br></div><div>The question you now have to ask is the generalisation and extra interface libraries worth the extra</div><div>effort?</div><div><br></div><div>I often start by trying to generalise dissimilar things and make them similar - but get to a point</div>
<div>where the generalisation and interfacing becomes the main problem and not solving the original problem.</div><div><br></div><div>That was a bit long and rambling ...</div><div><br></div><div>So the answer is "Yes you can do this, and it *might* be a good idea" to see if it *is* a good idea, you'll</div>
<div>have to implement things three times (with two data bases) (ie solution with database A alone and no abstraction layer) (database B with no abstraction layer) (A and B with a common abstraction layer)</div><div><br></div>
<div>Often the abstraction layer becomes at least as complex as the thing being abstracted- at which point</div><div>you wish you'd chosen a simpler career like being a brain surgeon or astronaut.</div><div><br></div>
<div>Cheers</div><div><br></div><div>/Joe </div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Thank you for any help & best regards,<br>
Hans<br>
_______________________________________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org">erlang-questions@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
</blockquote></div><br>