Kiwi Ingenuity

Thoughts from another perspective

Don’t get too Func-y

There have been a few posts appearing this week which themed on encouraging the reader to start using the Func and Action delegates.

It started with Ian Randall (@kiwipom) suggesting to Give your code just a little Func-y love. This was followed by Ivan Towlson (@ppog_penguin) scripting Make my Func the higher-order Func, quickly followed by Func-ier and Func-ier which wanted to improve on the separation of concern.

I thought I would add my view and say to the readers – “Don’t do it!” At least not with the example given. It’s difficult to understand and convoluted!

@itsgrego posted a tweet this week bringing our attention to Why you shouldn’t comment (or Document) code. I would think the majority of us would agree with the contents of that article. I do!

So code should be easy to read, and I would encourage you to write your code like this.

        public IEnumerable GetOrders(int customerId)
        {
            string cacheKey = string.Format("OrdersForCustomer{0}", customerId);
            IEnumerable result = _cacheService.Retrieve<IEnumerable>(cacheKey);
            if (result == null)
            {
                result = _ordersRepository.GetForCustomer(customerId);
                _cacheService.Add(cacheKey, result);
            }
            return result;
        }

Yes it’s the same as Ian’s starting point and it takes up 6 lines, but isn’t it so much easier to read and you understood exactly what the coders intention is. Come back to this code some years down the track and you will understand at first glance what the coders intention is. It’s self documented and there is separation of concern.

Delegates

I must state here and now that “I love delegates” and I would encourage you all to be using them consistently throughout your projects. When you see yourself writing repetitive code (or copy / pasting) then stop and ask yourself about delegates?

I’ll take the example above and explain how I would incorporate that code in a delegate. In the real world there is more to the process about retrieving and storing data than can be described in 6 lines of code. One area of concern is error handling. If you have been wrapping your Methods in try / catch blocks then you know about repetitive code and copy and pasting.

So I’m going to change my example above to what I would consider a real world example.

        public IEnumerable GetOrders(int customerId)
        {
            return FetchMethod(delegate()
            {
                string cacheKey = string.Format("OrdersForCustomer{0}", customerId);
                IEnumerable result = _cacheService.Retrieve<IEnumerable>(cacheKey);
                if (result == null)
                {
                    result = _ordersRepository.GetForCustomer(customerId);
                    _cacheService.Add(cacheKey, result);
                }
                return result;
            });
        }

        private TResult FetchMethod(Func fetchOperation)
        {
            try
            {
                return fetchOperation();
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }
            return default(TResult);
        }

In the example above I have wrapped my GetOrder code into a delegate. I then send that delegate to a function I have written to take care of my error handling.

From now on each time I have to make a call and need to handle any exception I will use this new function. Thank-you Func-y!

Comments (1) -

  • Ivan

    7/5/2013 12:02:50 AM | Reply

    To some extent, this is clearly a difference of degree: you find Func-ing out repetitive exception handling is readable, but Func-ing out repetitive cache management is not readable.  That's fair enough, but entirely subjective.  Different people are comfortable with extracting out different things.

    For myself, I find Ian's code *easier* to read than yours, because Ian's code clearly separates out "this is how I want to cache this stuff" from "this is how I retrieve this stuff," whereas in your code the two are interwoven -- I need to read the whole method and unpick the retrieval code from the caching code.  You say that with your code "you will understand at first glance what the coders intention is," but I disagree: at first glance, I find it much *harder* to understand your code than Ian's!  There is so much more of it and it is so much more intertwined!

    You clearly disagree: you find the step by step imperative code easier to understand, presumably because you can trace it through from top to bottom.  Fair enough.  But that's not the only way to read and understand code, and others will find the functional, declarative approach easier to understand -- even when they come back to it months later!

    And thanks for posting this feedback -- always good to be reminded that there are different perspectives!

Loading