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!