" It is better to have 100 functions operate on one data structure than to have 10 functions operate on 10 data structures. " - Alan Perlis (SICP Foreword)
Originally on towardssoftware.com
There is an eternal debate around Object Oriented software vs Functional software, and there likely will never be a conclusion, however, this is why I choose Functional when possible.
The API problem is defined as this - for every abstraction and service we create with software, all consumers will have to spend time learning the API. If you are familiar with concept of domain-specific language, or DSL, you can start to understand the trouble here. As nice as an API is, it introduces a new pattern to follow. But, most importantly, it introduces a new pattern to learn. I first heard the term DSL when I was learning Clojure and LISP. Both give you a magical ability (Google-"homoiconic") to create new languages extremely rapidly, but when you create a new language, you make a DSL. While powerful, it's something new that outsiders will have to learn when reading or modifying your code.
The modern web developer knows APIs well. Typically, APIs are used to gain massive leverage and scalability, without having to write much code, or maintain a complex service. As anyone who has used powerful APIs knows, its great once its working, but most of your time is spent looking over the documentation (which sucks most of the time). If you are lucky, you might get it on the first try, but more likely, you have to keep searching through docs, blogs, and stack overflow to find the essence of what you are looking for. The trouble and frustration comes when you've assumed this service is going to plug and play and easy to set up, but you've just spent two hours learning a DSL that you don't really care to learn.
We don't want to learn an API specific pattern, shape, or json language, BUT WE OBJECT ORIENTED PROGRAMmers spend years making complex APIs.
Let me explain - objects have an API in OOP, we don't call it an "API", but that's effectively what the object is. We use an object, we get a contract that says you can call get(), set(), toString(), foo(), bar(), etc. Not only do our objects have an API layer to access functions/methods, but they have an API to access data (I cannot deny functional programming has a data API, also but I will explain why it's better). Back to objects.
Let's look at a class in .NET Core: PolicySchemeHandler. The actual class doesn't matter for our purposes, but if you're interested, it does some authentication related stuff. Now, if you haven't already, please open up that link and tell me which method sounds the most useful. You may have gotten sidetracked by the long method names, or the descriptions that don't actually say what the method does, but rather where it inherits from (sweet, more hyperlinks to follow to figure out how to use this class). This is the API that you are going to spend at least a few minutes learning, if a lot more. It takes almost a minute just to read the class declaration (public class PolicySchemeHandler : Microsoft.AspNetCore.Authentication.SignInAuthenticationHandler) That's a mouth full!
What I argue, is that this is one class out of hundreds! that your application might need, each with its own interface full of methods. This should not be. Each class you introduce or create for your project brings with it many, many methods that are specific to THAT class alone. Maybe you made a nice interface that required you to implement the sleep() method for the Human, Dog, and Cat classes. Likely, you just typed very similar methods for each one.
So, how does Functional Programming help? I have been spoiled by Clojure, so my opinion will be somewhat colored by my experience with it. In Clojure, we use maps, seqs, vectors, lists, a few other primitive data structures to do all of what a class previously did for us. Something wonderful about this is that I can make 1 function that will accept all of the aforementioned data structures as a parameter and return the correct answer. No need to implement sleep() 3 times (or 100 times for that nasty app you get paid to work on). You implement it once, and it does the magic. You pass in a map with your own shape to represent a human, dog, or cat, and the function treats them all the same.
Would you rather have 1 sleep function for 100 different animal types, or 100 different animal classes with their own sleep method?
This is not a cherry-picked example, this is the norm. You can gain massive leverage by just treating all data as what it is: data! Instead of treating it like an object that is rigid and forces the burden of implementation detail on YOU.
Top comments (0)