[erlang-questions] Avoiding boilerplate code when using gen_server

Torben Hoffmann torben.lehoff@REDACTED
Fri Mar 23 13:31:38 CET 2012



On 23/3/12 3:35 , Robert Virding wrote:
> Got in late here but some comments:
>
> - I feel it is very important to separate client- and server side. I 
> give quite a few courses and this concept can be difficult for many 
> people. Especially those who come from the OO side who view modules as 
> classes. So anything which hides this is bad. Yes, I know that they 
> will learn but why make it more difficult. Also I like things to be 
> explicit.
After hearing the arguments I am in agreement with this split.
>
> - I personally don't really see the problem here, but then I am old 
> school. Much of the boiler plate code is very short so specifying it 
> for a "tool" will actually not save much typing, I still have to give 
> the details and the code to be run in the server.
For me the biggest annoyance is that in most cases the code in your API 
function simply wraps the incoming arguments with some tag and that tag 
has to be matched with a clause in the handle_call function.
As far as I can see there is no way to enforce a match unless you start 
creating records for each message you want to send to the internal 
server... hmmm, maybe that is not so bad after all... I will toy a bit 
with that thought.

There is a bit of flexibility in the e2project since you do not have to 
write one big handle_call function - you may choose to have several 
handle_*  functions. It is a bit clearer, but there is no enforcement 
since the function you specify as handler is dispatched through the 
e2_service:call/2 function.
Looking at this again there seems to be no easy fix to this "hole" since 
there is a dispatching involved here. The only thing that gives you some 
warning is to start using records for the messages, but it seems at bit 
dramatic to do that.
Putting specs on the internal protocol will not help due to the dispatching.

>
> My personal (biased) opinion is that has more to do with what they are 
> used to rather than usefulness.
There is definitely some of that in this equation.

Cheers,
Torben
>
> Robert
>
> ------------------------------------------------------------------------
>
>     As OP I take the liberty to do a top post and try to summarise a
>     few things at this point.
>
>     I am not alone when it comes to having an urge to remove some of
>     the boilerplate code. I guess we all want value for our money and
>     when we have to do something that does not provide that we want to
>     improve. If we did not have that craving we might as well be
>     coding enterprise Java applications using dozens of frameworks ;-)
>
>     I had a look at the e2project and it actually does remove some of
>     the boilerplate that I find the most iritating, namely the tagging
>     of messages from the API function to the handle_* function. It is
>     a lot clearer in e2project where you reference a function in the
>     e2_service:call - I like that a lot.
>
>     The approach with parse transforms has its merits, but I think
>     that the e2project can do away with most of the pains I have been
>     feeling, so I think I will leave out the semi-black magic of parse
>     transforms for now... it is a tool that should be used with
>     caution as other posters have mentioned.
>
>     The IDL approach I had in mind was nothing about CORBA - I should
>     never have mentioned CORBA in my original mail, there are too many
>     negative feelings associated to CORBA.
>     What I like about IDLs is that it allows you to spec your API in a
>     nice way and in many cases it will be possible to avoid writing
>     boilerplate code (either through code generation or using a parse
>     transform).
>
>     Given the good point made about separating the client and the
>     server side of things I think that what is needed is simply to
>     spec up the API function (who doesn't do that already?!?!) and
>     then try out e2project. The spec will give me a slap over my
>     fingers if I do not provide the function (I like that) and
>     e2project seems to minimise the tedious boilerplate stuff from
>     standard gen_server without limiting my ability to express what I
>     need.
>
>     A big thanks to all posters - I am glad I asked the question!
>
>     Cheers,
>     Torben
>
>     On 21/3/12 21:10 , Tim Watson wrote:
>
>         On 21 Mar 2012, at 19:22, Garrett Smith wrote:
>
>
>
>             This may come down to personal taste. I don't like having
>             to dig
>             around in parse transform code to understand what my
>             module looks
>             like.
>
>
>         Neither do I - that's why I simply run 'escript `evm
>         site`/parse_trans/ebin/parse_trans_pp.beam ebin/<target>.beam'
>         over the generated beam to see what it looks like at source
>         level. ;)
>
>             eunit is a great example. If you really love eunit, then
>             I'm not going
>             to convince you :)
>
>
>         Common test and PropEr do exactly the same thing. I'm not sure
>         what you're expected testing frameworks to do instead!?
>
>                     - Hiding the client-server distinction in Erlang
>                     is a terrible disservice
>
>
>                 I agree with this wholeheartedly, but don't see what
>                 it has to do with code generation.
>
>
>             If you consolidate both the client and server functions
>             into one
>             function, you've obfuscated an important distinction.
>
>
>         I never suggested doing that at all. Not that I mean to be
>         prickly, as we're all part of the same community and whatnot,
>         but nobody suggested separating both functions. What the OP
>         suggested was that you could define the interface
>         declaratively - e.g., without writing the code directly - and
>         that was what I was responding to. As I mentioned later on, in
>         this particular gen_server case I actually think your approach
>         is probably cleaner and more appropriate, but it's good to
>         separate these points and refine the discussion I think.
>
>                     IMO, e2 solves the problem of "too much boiler
>                     plate". It's really
>
>                     easy and requires zero magic.
>
>
>                     Here's a "gen_server" equivalent in e2:
>
>
>                     https://github.com/gar1t/e2v2/blob/master/examples/ping/src/ping_server.erl
>
>
>
>                 This is pretty cool though. :)
>
>
>                     You might object to the separation of "ping" and
>                     "handle_msg" -- it
>
>                     appears to be just one function, so why break it
>                     up into two pieces?
>
>
>                     The problem is that it's not one function -- it's
>                     definitely *two*
>
>                     very separate pieces of code.
>
>
>                 Absolutely and a good point!
>
>
>
>                     When you write a gen_server style module, you're
>                     writing code that
>
>                     support client-server interactions. You have, in
>                     the same module, code
>
>                     that is called by the "client" and code that is
>                     called by the
>
>                     "server". If you don't grok this, you're missing
>                     the entire point of
>
>                     this type of module.
>
>
>                     Code that hides this difference -- e.g. a parse
>                     transform that gloms
>
>                     the client and server functions into one -- is IMO
>                     a Really Bad Idea.
>
>
>
>                 I don't necessarily agree with this, as the parse
>                 transform can be applied to a -spec which is
>                 potentially as intention revealing as a hand written
>                 function. I do take your point about them being two
>                 separate functions and perhaps in this particular case
>                 (for gen_server) you are actually correct and having
>                 two hand coded parts is actually better. I don't buy
>                 'code-gen is bad' as a general argument (which perhaps
>                 you weren't going so far as to make anyway), and I do
>                 see your point in this instance.
>
>
>             I'm certainly not arguing against code generation. I think
>             Erlang's
>             parse transform scheme is *very* good -- flexible enough
>             to enable
>             elegant solutions but with enough complexity to scare off
>             casual "meta
>             programmers".
>
>             But -- I think there should be a very clear payoff for
>             using a parse
>             transform. I don't think the discussion here, which is
>             "boilerplate"
>             is a good application for that.
>
>
>         I think it depends on how much boilerplate you're looking at.
>         As an OCaml programmer I have seen a *lot* of work going into
>         removing boilerplate code, and the same in Haskell (although
>         there I am less experienced) and overall I think the payoff
>         you're describing is a value judgement based on the negative
>         impact of using code generation. Generated code is brittle -
>         there's no two ways about it. But it doesn't prevent you from
>         testing or documenting, nor does it have to make your code
>         opaque and difficult to understand, so long as it is not
>         overused - a sprinkle here and there rather than a bucket load.
>
>             A good example of a value-add parse transform IMO is
>             modlib, which
>             lets you create mods for inets httpd withou causing your
>             brain to
>             explode [1].
>
>                     As an example of how this client/server difference
>                     is important,
>
>                     consider form validation in a web app. There are
>                     two places you can
>
>                     run code to validate form input -- you can
>                     validate it in the browser
>
>                     using JavaScript, or you can send the form data to
>                     the server. Web
>
>                     developers may opt for browser validation to avoid
>                     the expense of
>
>                     sending data to the server -- or they might prefer
>                     it on the server.
>
>                     Either way, it's an important consideration.
>
>
>                     This same dynamic applies to gen_server style
>                     modules. If you stick
>
>                     with it, I think you'll appreciate the
>                     separateness of client and
>
>                     server facing code.
>
>
>                     As for the boilerplate, I couldn't agree with you
>                     more!
>
>
>                     Garrett
>
>
>                     P.S. I'm giving a talk on e2 at the SF Factory in
>                     a couple weeks,
>
>                     where I'll get into this in more details. Also,
>                     the e2 docs and github
>
>                     project are in slight disarray at the moment, but
>                     will be put in order
>
>                     this weekend!
>
>
>             [1] https://github.com/gar1t/modlib
>
>
>
>     --
>     http://www.linkedin.com/in/torbenhoffmann
>
>
>     _______________________________________________
>     erlang-questions mailing list
>     erlang-questions@REDACTED
>     http://erlang.org/mailman/listinfo/erlang-questions
>
>

-- 
http://www.linkedin.com/in/torbenhoffmann

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20120323/474f7122/attachment.htm>


More information about the erlang-questions mailing list