Friday, August 07, 2015

C#: Program Entirely With Static Methods

OK, that’s a provocative title to get your attention. This post is really about how one can move to a more functional programming style and remove the need for much of the apparatus of object-oriented programming, including interfaces and classes. In this post, I’m going to take some typical object-oriented C# code and refactor it in a more functional style. I’ll show that the result is more concise and easier to test.

Over the past couple of years I’ve noticed that my C# coding style has changed drastically under the influence of functional programming. Gone are interfaces and instance classes to be replaced by static methods, higher-order functions and closures. It’s somewhat ironic since I spent many years as a cheerleader for object-oriented programming and I considered static methods a code smell.

I guess if I look at my programming career, it has the following progression:

Procedural –> Object-Oriented –> Functional

The OO phase now looks like something of a detour.

C# has all the essential features you need for functional programming – higher-order functions, closures, lambda expressions – that allow you to entirely ditch the OO programming model. This results in more concise, readable and maintainable code. It also has a huge impact on unit testing, allowing one to do away with complex mocking frameworks, and write far simpler tests.

Introducing our object oriented example

Let’s look at an example. First I’ll introduce a highly simplified OO example, a simple service that grabs some customer records from a data-store, creates some reports and then emails them. Then I’ll show the same code refactored in a more functional style using delegates and higher-order static methods.

Let’s look at the object-oriented example first:

Well written object-oriented code is compositional. Concrete classes depend on abstractions (interfaces). These interfaces are consumed as dependencies by classes that rely on them and are usually injected as constructor arguments. This is called Dependency Injection. It’s good practice to compose object instances in a single place in the application - the composition root - usually when the application starts up, or on a significant event, such as an HTTP request. The composition can be hand coded or handed off to an IoC container. The constructed graph is then executed by invoking a method on the root object. This often occurs via an application framework (such as MVC or WebApi) rather than being explicitly invoked by user code.

We are going to get some customer records, create some reports and then email them to our customers. So first we need three interfaces: a data access abstraction, a report building abstraction, and an emailing abstraction:

And here are the implementations. This is not a real program of course, I’ve just coded some dummy customers and the emailer simply writes to the console.

Now we have our service class that depends on the three abstractions and orchestrates the reporting process:

As you can see, we inject the dependencies as constructor arguments, store them in class properties, then invoke methods on them in the code in the RunCustomerReportBatch method. Some people like to store the dependencies in class fields instead. That’s a matter of choice.

Our composition root composes the ReportingService with its dependencies and then returns it for the program to invoke. Don’t forget this is a highly simplified example. Composition is usually far more complex:

To write a unit test for the reporting service we would typically use either hand-crafted mocks, or some kind of mocking framework. Here’s an example unit test using XUnit and Moq:

We first create mocks for ReportingService’s dependencies with the relevant methods stubbed, which we inject as constructor arguments. We then invoke ReportingService and verify that the emailer was invoked as expected.

So that’s our object-oriented example. It’s typical of much well constructed C# code that you will find in the wild. It’s the way I’ve been building software for many years now with much success.

However, this object-oriented code is verbose. About a third of it is simply OO stuff that we have to write repeatedly and mechanically rather than code that is actually solving our problem. This boilerplate includes: the class’ properties (or fields) to hold the dependencies; the assigning of constructor arguments to those properties; writing the class and constructor. We also need complex mocking frameworks simply to test this code. Surely that’s a smell that’s telling us something is wrong?

Enlightenment

Enlightenment begins when you realise that the dependencies and method arguments can actually just be seen as arguments that are applied at different times in the application’s lifecycle. Consider a class with a single method and a single dependency:

We could equally represent this as a static method with two arguments:

But how do we partially apply these arguments? How do we give ‘DoThing’ the IDependency argument at composition time and the ‘string arg’ at the point where it is required by the application logic? Simple: We use a closure. Anything taking a dependency on ‘DoThing’ will ask for an Action<string>, because that is the signature of the ‘Do’ method in our ‘Thing’ class. So in our composition root, we ‘close over’ our previously created IDependency instance in a lambda expression with the signature, Action<string>, that invokes our DoThing static method. Like this:

So the interface is replaced with the built-in Action<T> delegate, and the closure is effectively doing the job of our ‘Thing’ class, the interface’s implementation, but with far fewer lines of code.

Refactoring to functional

OK. Let’s go back to our example and change it to use this new insight. We don’t need the interface definitions. They are replaced by built in delegate types:

ICustomerData becomes Func<IEnumerable<Customer>>

IEmailer becomes Action<string, string>

IReportBuilder becomes Func<Customer, Report>

The classes are replaced with static methods:

Our ReportingService is also replaced with a single static method that takes its dependencies as delegate arguments:

Composition looks like this:

This is functionally equivalent to the object-oriented code above, but it has 57 lines of code as opposed to 95; exactly 60% of the original code.

There’s also a marked simplification of the unit test:

The requirement for a complex mocking framework vanishes. Instead we merely have to set up simple lambda expressions for our stubs. Expectations can be validated with closed over local variables. It’s much easier to read and maintain.

Moving to a functional style of programming is certainly a huge departure from most C# code that you find in the wild and can initially look a little odd to the uninitiated. But it has many benefits, making your code more concise and easier to test and reason about. C# is, surprisingly, a perfectly adequate functional programming language, so don’t despair if for practical reasons you can’t use F#.

The complete code example for this post is on GitHub here: https://github.com/mikehadlow/FunctionalDemo

47 comments:

  1. I've been noticing this sort of thing myself but couldn't quite see how to get rid of the interfaces. Great to see example code and know that it can actually work!

    I found Mark Seeman's description of replacing interfaces with functions interesting too:

    ...one of the consequences of SOLID is that you should favour Role Interfaces over Header Interfaces, and as I've previously explained, the logical conclusion is that all interfaces should only have a single member.

    When interfaces only have a single member, the interface declaration itself tends to mostly be in the way - the only thing that matters is the operation. In C#, you could just use a delegate instead, and even Java has lambdas now.

    ...

    In my experience, you can model everything with single-member interfaces, which also implies that you can model everything with functions.


    ReplyDelete
  2. Totally agree with you but there's something I see as a problem, and let me do a little strechy analogy here, moving from OOP to Functional feels like moving from Typescript back to JavaScript, I'll explain in just one second:

    IEmailer becomes Action

    problem with this is: IEmailer and its method Send(string toAddress, string body); are very, extremely, explicit about what they mean and do, we all agree here

    whereas Action is completely meaningless other than it's a function that received 2 string parameters and returns void. What parameters, what do they mean?

    I'm sure we all can imagine different, simple ways of solving this issue with trivial language features, but they don't exist yet, in C# at least.

    ReplyDelete
  3. @Ricardo I guess it might help to use value objects to make it Action<EmailAddress, HtmlString>, though that is a lot of work in C#, compared to F#.

    ReplyDelete
  4. Exactly, that's why I said to solve it properly it's a language feature still to be developed, so I'm not sure moving to a functional style in C# is a good idea, yet.

    ReplyDelete
  5. IEmailer is just a typedef (essentially) for an interface about a function that takes some strings and sends an email. There are functional equivalents of that, renaming to reduce a developer's cognitive load. I'm not sure what it would be in C# (I'd be surprised if there wasn't an equivalent way), but in Haskell it would look something like:

    type Address = String
    type Body = String

    type Emailer = Address -> Body -> Email

    Where here Emailer is the type that represents a function that takes an Address and a Body and returns an Email. I could probably have chosen the names better, but hopefully you get the idea.

    ReplyDelete
  6. There isn't a succint way in C# (as James also pointed out), hence my comment.

    ReplyDelete
  7. Ah fair enough, I didn't see that. The closest I found was this: http://stackoverflow.com/questions/31025246/equivalent-of-typedef-in-c-sharp-for-action-and-or-func

    But it seems comparatively clunky.

    ReplyDelete
  8. I like this. I don't think technicalities pose a stumbling block to anyone trying to adopt this style. I take @Ricardo's point. I would say that you would aim to minimize the occasions when you have to resort to the action. Typically it would be when performing operations that have side effects. Ideally you want to keep those at the edges of the application. The core can be built in functional style where each function takes some input and yields some result. The stumbling block would be the recognition of the advantages of the style. This is harder to prove and I think this is one of the reasons functional programming in general hasn't become mainstream outside certain circles. People can easily counter the fact that the code base has shrunk by 40%. Personally I favour this style and I would try it in C#. Ultimately as others have said F# should be at least considered if we're targeting .NET. I'm currently learning F# and Haskell and I'm loving it. I'm beginning to think that people are wired differently. As Mark Seeman (and also stated here) certain constructs seem to get in the way of what you are trying to express. I value clarity, simplicity, less moving parts, referential transparency, idempotency, declarative style which I think you get from a more functional style.

    ReplyDelete
  9. Okay. I've just had a thought and I've found this http://bit.ly/1MSjnFd on StackOverflow. Essentially we could improve this by having alias for your function specifications. It's a bit left-field but perfectly valid. In some ways it still exposes C# as object oriented and functions tagging along in the trailer :-). So you could say

    using Emailer = Action;
    using CustomerRetriever = Func>;

    Perhaps poor naming convention but you can see that there is a path back to the goodness of types and the expressiveness and compile time guarantees they offer.

    ReplyDelete
  10. I don't think that's a good option, 2 different aliases won't work I believe.
    That SO reference also proves my point. There's too much ceremony in trying to port this functional behavior in C#, the language just doesn't support it yet (if it ever will).

    ReplyDelete
  11. Sadly the blog engine completely messed up the code. But if you follow the stackoverflow link you'll see what I was getting at.

    ReplyDelete
  12. @Ricardo Rodrigues: Exactly. I think it is at the point where the level of ceremony and cumbersomeness becomes unbearable that people consider a functional first or even a "pure" functional language ;-)

    ReplyDelete
  13. having said that a lot has been achieved with imperative and object oriented programming. It'll probably be with us for a while. All roads lead to Rome as someone said :-). Perhaps its more about the journey.

    ReplyDelete
  14. It's an interesting idea. I wonder how it will scale, though, to a real-world application of significant complexity. Also, I have to disagree on test simplification. You could actually construct the unit test almost exactly the same way with Moq, with no extra complexity or lines of code.

    ReplyDelete
  15. On the naming thing, how about using a parameter object instead of ths string primitives as arguments? I think then you bascially have a command and handler pattern?

    public class SendEmailCommand { public string EmailAddress; public string Body; }

    Action handleSendEmail = (SendEmailCommand) => { ... }

    (Obviously you could use properties with protected setters and constructor, but this was easier to format!)


    ReplyDelete
  16. This comment has been removed by the author.

    ReplyDelete
  17. Sorry, some trouble with formatting - that should be:

    Action<SendEmailCommand> handleSendEmail = command => { ... }

    I should also correct my spelling of Mark Seemann :)

    ReplyDelete
  18. If you go that style you could switch to F# - it's that you're missing stuff you need in more complex scenarios. Stateful functions? Currying instead of ctors. Just think about the fact that Action and Function are two distinct types. You are also missing algebraic data types. What you have now is a language with some functional elements, basically a subset of the whole language.

    ReplyDelete
  19. Delegates.

    Action can be replaced with:

    public delegate void Emailer(string email, string body);

    Still, I think the oo version is easier to reason about.

    ReplyDelete
    Replies
    1. This is exactly how I do it. I use my own delegates. This also means that I can still use a container where it's appropriate.

      This is such an idiosyncratic style of programming and such a departure from the awful practice whereby devs create an most one-to-one interface -> "service" approach dogmatically.

      I've found I have to marry the two because if nobody can understand or appreciate the nuances of this different approach then the codes value is undermined regardless of the advantages it brings.

      Delete
  20. HUGE amount of ceremony.
    I think you're missing the point. It's doable, agreed, yes.
    Idiomatic C#? No
    Practical in C# ? Neither
    Will it ever be? With F# being out there, don't think so.
    Do you want to use it? Yes (learn F#) PS: myself included

    ReplyDelete
  21. I'd be interested to hear why all your interfaces (and classes) only have one method, and whether cohesion ends up suffering? I have worked on similar codebases and find the classes too small and disconnected, with dependencies difficult to follow and code difficult to track down, not to mention unit tests all need reshuffling every time the dependency graph changes, and algorithms being split over multiple classes and functions even to do something simple.

    Personally I would consider moving in the other direction - not to start using static methods, but look at consolidating the classes towards better cohesion and encapsulation. I recently changed 6 classes into 2, and the code was much cleaner. (A provider, a factory, a factory-factory, a repository...)

    Another thing I've noticed is that I actually have remarkable trouble refactoring such "micro-class" codebases - in my experience it seems to be much easier / more natural to break up a large class than reassemble many small ones.

    ReplyDelete
  22. If one's not doing it right it's fairly easy to achieve duplication but small interfaces doesn't mean low cohesion at all, exactly the opposite! It does one thing and it's very portable.

    When it does too many things, then you break cohesion (violating the ISP), because you end up with a swiss knife interface, like IQueryable for example.

    ReplyDelete
  23. Did you do any performance profiling you can share? I'm interested in the runtime behavior of such conversions; lots of discussion of functional variants either ignore performance or the functional version is slower due to increased (hidden) looping and memory related to functional collection related thinking.

    I've enjoyed the recent tech du jour focus on functional languages, but I also am suspicious there's a reason why they have been around forever (i.e. Lisp in 1958) but always just a niche. Performance seems to be one thing keeping it there.

    ReplyDelete
  24. I was going to complain about how bad and pointless the interfaces were in your starting code but then realized it's a great example of real world. Totally pointless interfaces that offer nothing and don't need to exist.


    @Ricardo Rodrigues the purpose of TypeScript isn't to make javascript less functional the purpose is to fix the insanity of how bad it is at handling contracts. It also adds meta programming (which some/all is being absorbed by ES6 because of the major lacking of it in JS)

    ReplyDelete
  25. If you had an INotifier with an email implementation and something else, a truly needed encapsulation for data storage (other than a database? EF itself already is an abstraction), and more than one type of reporting services, I'd go with all the interface and all.

    To be very straight to the point: I see a lot of code with interfaces that are realized by only one type of object and it's useless. Many people code with the "what if" syndrome and that's waste of time.

    I would guess Mike's point here is simplicity. I liked the article.

    ReplyDelete
    Replies
    1. * "what if": what if this needs to change in the future.

      Delete
  26. This comment has been removed by the author.

    ReplyDelete
  27. Nice article, I like the point.

    This is a journey I've been on for a long time. Initially, bastardizing an OO language to work functionally feels like a nice thing to do.

    And then you realize that you are writing little functions everywhere to glue things together (like your compose function).

    So, you write a library of little combinators, such as the ones given in the answer to http://stackoverflow.com/questions/5264060/does-c-sharp-support-function-composition.

    You then realize that you could combine things so much better if you had partial application. And then you write some more little combinators.

    So much boiler-plate. When will it end?

    Then one day, the new person joins the team and they immediately spew as they see the crazy. You slowly open your eyes and realize that you can't put lipstick on a pig; C# ain't functional.

    My point is you can't turn a language into something it's not. C# is a great language, but it lacks some vital pieces to be an effective functional language (partial application is probably the biggest for me, but there's many more). Functional-esque C# is just a gateway drug to a functional language.

    ReplyDelete
  28. I don't agree with the "complex mocking framework" part. There's no added complexity to the first test as in additional abstraction layers, messy conditional logic or dirty technical tricks. Of course the mocking framework brings new vocabulary to the equation, but the semantics of "setting up" a context for the system under test and "verifying" stuff are naturally lurking in the test between the lines anyway, you might as well make them explicit.

    So to me the two implementations are equally readable, with the OO version maybe a little more intention-revealing thanks to "Verify( a method was called...)" and "Setup". But sure, you could be exactly as expressive in the functional version with some well-named helper functions.

    Anyway, a very good article about the functional approach to dependencies and testing.

    ReplyDelete
  29. @Thomas Eyde

    Using named delegates to make it explicit what a Function is for can be harmful to your career - I recently received the following feedback from an offline coding test I had to submit when going for a contract (which I didn't get).

    "When using Funcs<> from 3.5 I would expect not to use delages cira 2.0 mixing these sort of stuff is a red flag for me. would expect to use Actions instead of delegates"

    Sigh.

    ReplyDelete
  30. This comment has been removed by the author.

    ReplyDelete
  31. @Harry McIntyre

    Their loss. I often use explicit delegates to remove ambiguity. i.e:

    public delegate DateTimeOffset Now();

    instead of: Func

    I think there is something to be said about the clarity? Not just for people either. You can register that with you container and inject date time, or substitute easily in a test.

    ReplyDelete
  32. I like the approach even though it might lead to big overloads of constructors, specially when the injected dependencies were quite considerably in size (methods).

    Thanks for sharing :)

    ReplyDelete
  33. Anonymous8:15 pm

    Looks interesting. Can you please do a followup post where your interfaces have say 3-4 methods each? I'm not really sure how your approach scale, hence why I'd like your take on a more realistic situation.

    ReplyDelete
  34. @Anonymous, when you're thinking functionally like this your interfaces all tend to end up with one method anyway: http://blog.ploeh.dk/2014/03/10/solid-the-next-step-is-functional/

    ReplyDelete
  35. Anonymous7:38 pm

    @James, seriously? You group code in classes and interfaces in OOP, you group code in modules in FP. Please don't bring forward the rantings of a mad man in the discussion - or accept that code that does something (accessing db (fetch/store), going to external providers etc. will end up with 8+ dependencies with that kind of thinking. And carrying around 8+ function pointer arguments will make your code brittle and confusing to say the least.

    ReplyDelete
  36. Interfaces having one method doesn't stop you grouping your code into classes or modules :) "rantings of a mad man" seems a little presumptive!

    ReplyDelete
  37. What is Abstract Data type?

    ReplyDelete
  38. Just found this post and have to agree. Over the past few years I have been moving more into the functional space with C#. As for does it scale, I can answer yes. I work on a project that is about a decade old so parts are in all flavors of C# from V2 onward. Most of the new stuff has been functional and it is cleaner, more consice and far easier to refactor because of it.

    The more I use functional the more I believe OO is a dead end and a productivity time suck. It simply does not give the fluidity of code that functional provides.

    Just look at your old code, if you have interfaces that have one method the question should be why, just a bunch of pointless noise. An interface, a class and possibly IOC registration and resolution.

    People used to worry about readonly dictionaries in C# but I just pass around a Func which is the lookup and also means you are not even tied to a dictionary.

    Functional, because you break everything down more, gives more building block with finer granularity and closures provide far more power and flexibility that classes can.

    So the current project has 500000 lines of C# and I can work faster and move faster in the functional stuff than I can in the OO

    ReplyDelete
  39. Anonymous1:01 am

    My career has followed a similar trajectory. I was all on board with OO in C#, until one day the fancy features of F# aroused my curiosity. I spent many months diving head first into that language in my off time, and I found that I didn't care half so much about its fancy features as I did the style and paradigm of the language. Following that, my C# code has never been the same.

    I was recently asked to join a new, multi-division project, and I brought my functional style with me. I was expecting some push back, but much to my surprise, I have been showered with praise. Brilliant, masterpiece, top gun coder, etc are all being tossed around. No, functional programming is brilliant, and one can do some genuinely brilliant things with it. I just use the stuff.

    There are a couple dinosaurs in the project, but rest assured that I will convert them. The level of code reduction, readability, and stability gained is so immense--the productivity so enhanced--they will not be able to resist forever. And to any dinosaurs out there reading this comment, you will be assimilated. Resistance is futile.

    ReplyDelete
  40. Interesting. How does this play in a real world mvc app, using a container like StructureMap or AutoFac?

    ReplyDelete
  41. Anonymous1:13 pm

    @Ricardo (http://mikehadlow.blogspot.de/2015/08/c-program-entirely-with-static-methods.html?showComment=1438960380464#c1143071256575253270)

    I'd use delegates for that. They are like interfaces, but for methods, and c# can match them easily to lambda expressions or static methods.

    ReplyDelete
  42. C# 7 Named tuples can solve the Action problem.

    class Program
    {
    static void Main()
    {
    RunCustomerReportBatch(SendEmail);

    Console.ReadKey();
    }
    public static void SendEmail((string toAddress, string body) emailFields)
    {
    // pretend to send an email here
    Console.Out.WriteLine("Sent Email to: {0}, Body: '{1}'", emailFields.toAddress, emailFields.body);
    }

    public static void RunCustomerReportBatch(Action<(string toAddress, string body)> sendEmail)
    {
    //....code omitted for breviety

    sendEmail(("Recipient@test.com", "Test Report Body"));
    }
    }

    ReplyDelete
  43. Action and func are just templates for delegates. A delegate is effectively a method signature and analogous to an interface with a single method. So i'd be inclined to agree with using delegates over action/function as it is more expressive. This article is thought provoking which is great and static methods should offer performance improvements to some extent but f# immutable types offers thread safety which hasn't even entered this discussion. Great article.

    ReplyDelete
  44. Anonymous2:37 pm

    Nice write up. Far easier to maintain Functional and Procedural code vs OOP. The advantages of OOP have been exaggerated for years. Let's face facts regarding time, money, manpower, budgets. The code is built once and maintained for years. Good Code all ways ends up being about about EASE of maintenance. Functional and Procedural coding is making a comeback for good reason.

    ReplyDelete
  45. This is very helpful because I find myself slowly converging on the same pattern. I often write classes with one or two dependencies, and they tend to be small and stateless. The dependencies themselves also often have one method. (I've recently leaned toward injecting delegates instead of interfaces, partially for that reason.) So the pattern you demonstrated of replacing the class with a method and replacing the injected dependency with an argument is perfect.

    Going a step further, when I inject a dependency I tend to use only one method. So the next logical step is for the method to take a delegate as an argument instead of an interface or class.

    One thing I like about this approach is that it makes it more difficult for someone to clutter the code. They can't sneak in new class dependencies by adding new members to existing interfaces.

    ReplyDelete

Note: only a member of this blog may post a comment.