C is for S.O.L.I.D.

In my last post, I dusted off my C skills  – it’s been a very long time – to demonstrate how we might have achieved encapsulation in C thirty years ago. (Indeed, this is how I was taught to do it by engineers who’d been working in C in the 1980s.)

That ticks one box for the software design principles I teach on the Codemanship course: modules should Tell, Don’t Ask.

What about the other design principles? Well, can we all agree that Simple Design applies in any programming language?

  • C code should work
  • C code should clearly communicate its intent
  • C code should not repeat itself (unless repeating itself makes it easier to understand)
  • C code should be composed out of the simplest parts

That leaves the S.O.L.I.D. principles from the course. Let’s go through them one letter at a time and see how (or if, or why) they could be applied in C.

 

Single Responsibility

Modules should only have one reason to change

In the example I used last time, we started with a carpet_quote module that “knew too much”. It calculated the area of a room based on the room’s dimensions, and it calculated a total price for a fitted carpet based on the carpet’s price per square metre, and whether we should round up to the nearest square metre.

What has calculating the total price got to do with how we calculate the area of the room? I can easily imagine wanting to change how we do either of those calculations independently of the other. For example, what about L-shaped rooms? What if we need to apply a discount for larger rooms? Arguably, these two pieces of logic belong in two separate modules. We split them up to help carpet_quote Tell, Don’t Ask, and here’s another good reason why we should have split them up.

 

Open Closed

Modules should be open to extension and closed to modification

In the refactored Tell, Don’t Ask version of the carpet quote example code, we ended up with carpet_quote using a room and a carpet module inside which the data and the details of the calculations were hidden. What if I wanted to extend this design to price carpets for circular rooms? carpet_quote binds directly to the current room.h header.

Whether or not I can swap in a different implementation without modifying carpet_quote.c will depend on what’s exposed in room.h.

There are two blockers here if we want the two kinds of room to co-exist in the same code: first, the “constructor” function new_room(). It’s signature would need to change for a circular room (e.g., new_room(float radius) ), and any modules importing room.h would be affected by that change.

What we need here is a clean separation of the abstractions of a room from the details of how the room is created.

So let’s define two implementations of room in separate modules, with their own constructor functions.

Note here that, because the Room struct is only implemented internally, we can implement it again in a circular_room.c file without any naming conflicts.

Rinse and repeat for a circular room.

So far, so good. But both of these modules can’t implement the area() function defined in room.h, or we get a naming conflict. How can we have two implementations of area() co-exist in a language that doesn’t explicitly support polymorphism?

The simplest solution is to use a function pointer in carpet_quote that matches the signature of area(), instead of directly invoking area().

Then rectangular_room and circular_room can have their own unique functions for calculating room area.

Now our client just needs to create the correct kind of Room and pass in the associated area calculation function.

This is, of course, nasty. We’re holding the client responsible for making this type safe. If we try to apply rectangular_area() to a circular room, we’ll get an error. How can we ensure that the right area function is applied to any room?

We’re in luck. If, in C, functions can be data, then structs can contain functions.

We can assign a reference to the appropriate area function inside each constructor.

Then we can re-write the quote() function to use the attached area() function.

Now the client doesn’t need to know anything about the area() function. It just decides what kind of room to create, as before.

This refactored design allows us to add new kinds of room (new kinds of dimensions) and new ways of calculating the area of carpet required without making any changes to the existing modules.

Yes: it’s hard work in C! But it can be done. It can be done in any programming language that supports function pointers.

 

Liskov Substitution

An instance of any type can be substituted with an instance of any of its subtypes.

This design principle is all about contracts. If we define an abstraction for calculating the area of carpet required for a room, the client will have expectations about how to use that function and what they should get from it that must hold regardless of which implementation is being used at runtime.

In practical terms, if we wrote a contract test for the area() function – e.g., when the deminsions are positive numbers the output should be a positive number greater than or equal to a “base dimension” – then every implementation of area() must pass that test.

 

Interface Segregation

Modules should present client-specific interfaces

Here we’re talking about what modules make visible to the client modules that use them. This is more important in a statically-typed language like C than it is in dynamically-typed languages like JavaScript. I guess the advice here is to make good use of .h files to control what clients see.

Taking carpet_quote.c as an example, it references room.h and carpet.h.

It needs to know about the type Room, and it needs to know a Room struct has an area() function. What’s exposed in room.h?

carpet_quote doesn’t need to know about dimensions. How could we refactor this so that carpet_quote is only exposed to what it uses? The honest answer is “not easily”. Once we’ve defined a Room struct with an area() function, we can’t redefine it to have additional features.

If we extracted Dimensions into it’s own .h file, we’d just have to include it here anyway. Importantly, the details of what Dimensions contains is hidden from carpet_quote, because we encapsulated the implementations inside rectangular_room.c and circular_room.c.

So 100% client-specific interfaces is tricky in C. But at least we can control what functions clients are exposed to through the use of header files, which gets us much of the way there. carpet_quote.c knows nothing about how rooms and carpets are created, knows nothing about what data they contain and doesn’t know about the room-specific functions for calculating areas.

 

Dependency Inversion

High-level modules should not depend on low-level modules. Both should depend on abstractions.

Abstractions shouldn’t depend on details. Details shoud depend on abstractions.

Putting it all together, we’ve achieved a kind of dependency inversion in the way that carpet_quote only depends on an abstract definition of a Room. The details of that room’s internal dimensions, and the way we calculate the area of carpet required to fill it, are hidden from carpet_quote. Room could be thought of as an abstract class in this sense, and implementations of are injected as an argument of the quote() function. (Or, as we did before, we can inject the area() function implementation directly. This is very similar to the way we achieved dependency inversion in functional JavaScript or Ruby in previous posts.)

The way to know if we have inverted dependencies is to examine the imports: what files does carpet_quote.c need to include?

Aside from its owner header file, it only imports the abstractions in room.h and carpet.h. This high-level modules doesn’t depend on low-level modules, nor does it depend on details.

When we use dependency injection to wire our collaborating modules together, the tendency is for the details – the dependencies on implementations – to bubble to the top of the call stack. Good modular architectures wear their implementation dependencies on the outside.

Examining the imports in main.c, this appears to be exactly what has happened.

We might then go through a similar process to abstract the way that carpet price are calculated. (I’ve left this for you to do.)

 

So there you have it. S.O.L.I.D. – for the most part – can be applied in C. And, back in the day, I routinely applied it when C++ was not an option. If you’ve got function pointers, you can SOLID.

 

You can view a complete copy of the finished code at https://github.com/jasongorman/solid_c

Tell, Don’t Ask in C

I’m preparing a keynote on “Timeless Design Principles”, with the aim of demonstrating how the principles I try to instil in developers on my Codemanship courses could have been applied just as readily 30 years ago or even 50 years ago in programming languages of the time.

In 1989, C ruled the world. A common misconception among inexperienced developers is that design principles like S.O.L.I.D. and Tell, Don’t Ask only apply to OO languages like C++.

Nothing could be further from the truth, though. Let’s start with Tell, Don’t Ask.

Consider this simple C function that calculates a quote for a fitted carpet:

The quote() function has to ask for the room’s dimensions, and then has to ask for the carpet’s price pr square metre and whether it should round up to the nearest square metre.

Although Room and Carpet aren’t classes, as far as I’m concerned this is still Feature Envy. Room and Carpet are completely unencapsulated. The carpet_quote module knows how the area of a room is calculated, and it knows how to calculate the price of the carpet in that room. If those details change, carpet_quote breaks. Or, more simply, carpet_quote knows too much.

A good first step to fixing that would be to move those two pieces of logic into their own functions.

Now our quote() function knows a lot less. But the carpet_quote module still knows it all. So the next step would be to move the area() and price() functions to the modules where the Room and Carpet structs are declared.

carpet_quote now knows less about the details, which are neatly encapsulated inside carpet and room.

The data is still accessible from the outside, though. So we’ve got a little more work to do to complete this refactoring. At the moment, the Room and Carpet structs are declared in completeness in the header files room.h and carpet.h, so any module can create and set their field values directly.

In our client code, we instantiate these “objects” directly, setting their field values externally. This gives me the screaming heebie-jeebies. (Every bit a smuch as “data classes in Python, or JSON objects in JavaScript.)

How can we hide the data of a Room and a Carpet inside their respective modules? Luckily, C gives a mechanism: partial declarations. We can partially declare a struct in a .h file, defining its type but omitting its data.

Then we can declare the struct with all its data fields in the .c file, so that they can only be accessed internally. Then we add a factory method – essentially a “constructor” – for that type.

Now the only way a client can get a handle on an instance of the struct is via its module, and it can’t access the data directly.

 

Refactoring To Higher-Order Functions

In my last post, I demonstrated how we might refactor a simple object oriented piece of code into a functional style with a JavaScript example. The focus of that example was about how to get from instance methods that access mutable fields to stateless functions that use immutable data structures.

I wanted to follow that up with a slightly more sophisticated example to illustrate how we might refactor from an OO design that uses dependency injection to an FP design that uses higher-order functions.

Let’s do it in Ruby this time.

Here we have a class that writes customer data in a variety of formats – XML, HTML and andstrings – to a variety of output destinations – console, log file and NoSql database.

The serializers all present the same interface, with a write() method that accepts a customer parameter. A good first step might be to pass in lambda that invokes the serialize() method instead of invoking it on the serializer instance inside write().

So far, so ugly. Next we can make all our serialize() methods unique.

Then we can clean things up by turning these instance methods into standalone functions. e.g.

…allows us to re-write the client code more cleanly.

We can rinse and repeat for the output writers. Start by passing in lambdas that invoke their write() methods.

Then make each write() method unique.

Now, the next part is a little fiddlier. We want to turn these methods into standalone functions. For the console writer, it’s simple because write_console() is stateless, so we don’t have any fields to worry about.

But write_logfile() and write_nosql() access fields that are set in constructors. In the previous post, I illustrated how we can refactor from there. All the information those methods need can be passed in as arguments.

Now we can make them standalone functions.

And a final bit of tidying up: if we turn our write_logfile() and write_nosql() into closures, with the outer functions acepting all the messy extra parameters, we can simplify our client code.

Last, but not least, we get rid of the ResponseWriter class, making its write() method a standalone function.

 

 

 

 

 

Refactoring to Functions

While I’ve been porting the Codemanship Software Design Principles code examples to JavaScript – in both OO and FP styles – I’ve been thinking a lot about the relationship between those two programming styles.

Possibly the best way to illustrate might be to refactor an object oriented code example into a functional example that’s logically equivalent. This might also serve to illustrate how we might move from one style to the other in a disciplined way, without breaking the code.

This is the simple class I’m going to start with.

And these are its tests.

The first refactoring step might be to make each method of the class properly stateless (i.e., they don’t reference any fields).

To achieve this, we’ll have to add a parameter to each method that accepts an instance of BankAccount. Then we replace this with a reference to that parameter. This will work if the BankAccount we pass in is the exact same object this refers to.

So, in our tests, we pass in the BankAccount object we were invoking credit() and debit() on.

Now we can pull these instance methods out of BankAccount and turn them into global functions.

The tests can now invoke them directly.

One last piece of business: the BankAccount data object. We can replace it in two steps. First, let’s use a JSON version instead that matches the schema credit() and debit() expected. To make this the smallest change possible (so we don’t have to re-write those functions yet), let’s make them mutable.

Then we can re-write credit() and debit() to return mutated copies.

This will require us to re-write the tests to use the mutated copies.

So, there you have it: from OO to FP (well, functional-ish, maybe) for a simple class with no collaborators. In the next post, I’ll refactor some a code example that involves several related classes so we can examine the relationshi between dependency injection and high-order functions.

 

Tell, Don’t Ask in Functional Programming

In my last blog post, I illustrated how S.O.L.I.D. design principles can be applied to functional programming with five JavaScript examples.

There’s more to modular design than SOLID, though. For example, what about encapsulation?

As I continue to port the Java and C# examples for the Codemanship software design principles course, I’ve reached Tell, Don’t Ask. Take a look at the example code for calculating how much to charge for a new carpet.

Here’s the thing about functions: when they act on data structures (like JSON objects or tuples), the relationship between data and the logic that acts on that data inherently becomes unencapsulated. That’s just a fancy way of saying that carpet_quote.js knows too much. It knows how to calculate the area of a room based on the length and the width. It knows how to round up the area of a carpet if required. And it knows how to combine these things to get a price for that carpet in that room.

How could we encapsulate each of these jobs so that carpet_quote knows less? The answer may lie in closures.

We can encapsulate calculating the area of a room inside an outer function that takes the length and width as parameters.

And we can encapsulate the knowledge of calculating the price for that area of carpet inside an outer function that takes the price per square metre and whether or not to round up to the nearest square metre as parameters.

Then we can rewrite quote() as a higher-order function (just a fancy way of saying “inject the functions it uses”) that knows a lot less.

The data required is no longer exposed to carpet_quote. Instead, it’s passed to the outer functions of the closures in the client code – acting effectively as constructors. (Yes, closures are a lot like classes, dontcha think?)

Each module now only has one job, and has no direct implementation dependencies. And it makes the logic of calculating room areas and prices swappable. This design ticks all three boxes of good modular design:

  1. Each unit does one job
  2. Each hides its inner workings (especially its data)
  3. Their dependencies are swappable (by injection)

Let’s say we wanted to calculate the areas of more complex rooms (e.g., L-shaped, circular). In the refactored design we can extend the solution without having to rewrite carpet_quote. So this design is S.O.L.I.D., too.

 

If you’d like to have a crack at refactoring the JavaScript design princples examples, you can find the source code at https://github.com/jasongorman/JS_design_principles

Functional S.O.L.I.D. Explained In 5 Examples

I’m in the process of porting the Codemanship course materials to Python and JavaScript. After I did the S.O.L.I.D. examples from the Software Design Principles workshop in JS, I thought it might be useful to illustrate how these “object oriented” principles can be applied to a more functional style of programming.

Single Responsibility

“Classes should have one reason to change.”

The rationale behind the SRP is simple: editing classes risks breaking the code in them. Once code is tested and out there working, we’d ideally prefer to leave it that way. If a class contains code that changes at different times for different reasons, the risk is of breaking code that really didn’t need to change just because it’s in the same class as code that did. (There’s another, much more compelling reason for our classes – and methods and functions – to do only one job, which is explained on the course.)

But “class” is a red herring here. Really, it’s sources files. (Or modules.) Editing code in a source file risks breaking other code in the same file.

For example:

Here I can easily imagine wanting to change the XML output without changing the logic of a bank transfer. This module has two reasons to change. So we should split it up.

Open-Closed

“Classes should be open to extension and closed to modification”

Once a class is tested and released, modifying it risks breaking it – and any code that depends on it. A safer way to add functionality to an existing system is to extend the existing code without editing it.

This means our code needs to be designed in a way that makes extending easy. Now, this design principle arguably belongs more in the days of C++ and a few other statically-typed languages where, if you want a class to be open to extension, you have to design it a certain way (e.g., any methods you plan to override need to be declared as virtual. The love for pure interfaces for everything was born of this era.)

In the modern era of dynamic languages and duck typing, it’s very easy to swap one implementation with another – provided the client hasn’t directly referenced that implementation (which is what the D in SOLID is all about.)

Back in the day, we no doubt had inheritance in mind. But that has very much fallen out of favour in recent years, and now many developers prefer composition instead. A subclass that presents the same interface as a base class, and delegates method calls to an instance of the base class internally is logically the same as implementation inheritance.

The functional equivalent of that would be a function with the same signature as the “base” function that internaly delegates to it.

Imagine we wanted to extend a function for borrowing videos from a library so that we can prevent people from borrowing titles they’re too young to see:

All we have to do is create a new function that has an identical signature, that calls the original borrow() function.

Liskov Substitution

“An instance of a class can be substituted with an instance of any of its subclasses”

The example above solves the problem of syntactic swappability of a function with an extended version that has the same signature. But… it’s not quite as simple as just syntax in many cases of extension.

First of all, you may have noticed that the extended function relies on customers having an age, and videos having a rating. We didn’t just extend the function, we extended the data structure (in this case, the JSON object) the function accesses. Any client passing in the old data structure will cause an unhandled exception.

Also, the client could be in for a nasty surprise if the customer is too young for the video they’re borrowing, in the shape of an unexpected error. We’d have to rewrite the client code. Ths is how ripples start in our code that can spread from the module we changed/extended to the rest of the code, making even the smallest changes very expensive.

Ideally, we want to be able to extend the software without having to rewrite client code. And that means, in practice, that – as far as existing clients are concerned – the contracts for calling functions must still hold.

The original borrow() function has no precondition. Any customer can borrow any video. The extended version requires the customer be old enough. So there are scenarios for using borrow() the client thinks are valid that no longer are. (Imagine turning up to the airport with your ticket and your passport, and not being allowed to board the flight because, on your way to the airport, they added a requirement to bring the pilot a bunch of bananas.)

Consider this simple bank account module:

We’re asked to extend it so that customers can withdraw beyond the balance up to an agreed overdraft limit. In an FP style, this just means “overriding” the debit() function.

So far, soo good. This works syntactically. Anywhere clients expect the original debit function, we could substitute the new version. But have we broken the original contract?

One way to check would be to somehow run the original bank account tests against the new implementation. Right now, they look like this:

As they are, it’s not possible to swap in the new implementation because the tests directly reference the old one. What if we refactored the tests to look like this?

Now we can run the same tests with two different implementations of debit(), and two different versions of the account object. Now, I wonder what happens when I run these tests…

 

Interface Segregation

“Classes should present client-specific interfaces”

Back in the days when C++ ruled the world, if I changed a class’s interface (e.g., renamed a method), all the code that referenced that class had to be recompiled, re-tested and re-deployed. Unavoidable if those clients use that renamed method, but totally avoidable if they don’t, by extracting interfaces that only include the methods they actually do use.

In FP, there are no interfaces. Or, rather, every funtion can be thought of as an interface with only one method. Add to that dynamic binding, and the problem goes away. So, arguably, a discussion about Interface Segregation is moot.

But in the heat of battle, as functions evolve and move between modules, and dependencies change, it’s entirely possible for one module to end up directly referencing functions and modules they no longer use. The effect is the same.

Although this module only uses the rating() function from book.js, it references two other exported functions. If I were to, say, move summarize() to a different module, this code breaks.

So, in FP, we might re-frame Interface Segregation as:

“Modules should only reference things from other modules they actually use”

Dependency Inversion

“High-level modules should not depend on low-level modules. Both should depend on abstractions.

Abstractions should not depend on details. Details should depend on abstractions.”

This is a rather hifalutin way of saying that dependencies between modules should be swappable.

Consider this example:

This is a poor design. How do we add new kinds of output format without modifying this write() function? That breaks the Open-Closed principle. OO languages give us a simple mechanism for making choices without the nastiness of enums and conditionals: polymorphism.

FP gives us exactly the same mechanism. Two functions with the same signatures can be invoked by the same client, without the client knowing which implementation it’s using. From the outside, they look exactly the same.

If we refactor write() to remove direct references to the implementations, and inject the output function from the outside, we can make that dependency easily swappable and our design easily extensible.

Now the client decides which output function to use:

Notice that all the implementation references are at the top of our call stack now. This is the effect that composing functions (and objects in OOP) by dependency injection tends to have.

Dependency Inversion (and dependency injection that enables it) is as much a foundation of good, extensible FP as it is of good OOP. You may have noticed how many, many staples of the FP paradigm – e.g., map(), filter() and reduce() – work by allowing us to pass in functions that are invoked inside without having to anything about the function being called other than its signature.

 

So there you have it: S.O.L.I.D. applied to functional JavaScript in five examples. If you want to take a more detailed look at the example code and try the refactorings for yourself, it’s all on https://github.com/jasongorman/JS_design_principles

And if you’d like Software Design Principles training and coaching for your team, you know where to find me.

 

S.O.L.I.D. JavaScript – OO Version

A little while back I wrote a post on the old blog about how we could apply the same design principles – near enough – to functional programming as we might to object oriented programming, using JavaScript examples.

That encouraged a couple of people to get in touch saying “But we don’t do FP in JavaScript!”, and suggesting therefore that – strangely – these principles don’t apply to them. The mind boggles.

But, for completeness, here’s how I might apply S.O.L.I.D. principles to OO JavaScript code. To make things backwards compatible, I’ve not used the class syntax of later versions of JS.

First of all, the big tomale: swappable dependencies (Dependency Inversion).

Consider this snippet of code for a simplistic shopping basket:

The problem here is what happens if we want to change the way we process payments? Maybe we don’t want to use PayPal any more, for example. Or what if we don’t want to use a real payment processor in a unit test? In this design, we’d have to change the Basket class. That breaks the Open-Closed Principle of SOLID (classes should be open to extension, but closed for modification.)

If we inject the payment processor, then it becomes easy to swap the implementation for whatever purpose (in this example, to stub the processor for a test.)

And there we have it: three fifths of SOLID is about making dependencies swappable – Open-Closed, Liskov Substitution and Dependency Inversion. (or “OLD”, if you like.)

And can we agree classes should have a Single Responsibility? That’s not really an OO principle. The same’s true of functions and modules and microservices and any other discrete unit of executable code.

Finally, the Interface Segregation Principle: classes should present client-specific interfaces. That is, interfaces should only include the methods a client uses. With duck typing, it doesn’t really matter of a class presents methods a client doesn’t use. This is true whether we’re talking about methods of classes, or functions in modules.

It might help to make the code easier to understand of we document protocols by explicitly defining pure abstract classes that describe what methods any implementation would need to support. But it’s not necessary for our code to compile and run.

But, as with the functional examples I used, there is a case for saying that modules shouldn’t reference implementations they’re not using. Let’s suppose that after I refactored my Basket to use dependency injection, I forgot to remove the import for PayPalPayments:

It’s important to remember to clean up your imports regularly to avoid situations where changes to things we don’t use could break our code.

So, the sum up: the same principles apply in JavaScript regardless of whether you’re doing FP or OOP.

No excuses!