Fortran 77 – Does It S.O.L.I.D.?

My journey through time to see how the software design principles I teach on Codemanship courses could have been applied in the past continues to 1979, 40 years ago. Although it was already 22 years old by then, Fortran was still one of the most popular languages – particularly in scientific and engineering computing.

The language had an upgrade in 1977, but was still recognisably the very procedural language that was first envisaged in 1957. I used Fortran 77 in my degree studies, and I last used it 27 years ago. How many of the design principles I recommend to developers could I have been applying in it?

Let’s start with the 4 principles of Simple Design:

  1. Should Fortran 77 code work? Well, I think so. Don’t you? In the early 1990s when I was writing code to do computational maths, I was a pretty naive programmer. I wrote no automated tests, and typically wrote all the code for a program – usually just 100-200 lines of it – before trying t to see if it gave the answers I expected. Can you automically test Fortran 77 code? Of course you can. If you can write code that calls code, you can write automated tests.
  2. Should Fortran 77 code clearly communicate its intent? Again, does anyone believe that readability doesn’t matter in Fortran 77? The language has all the mechanisms we need to endow our code with meaning – i.e., opportunities to name things.
  3. Should Fortran 77 code be free of duplication (unless that makes it harder to undersand)? The question is really one of language design: does Fortran 77 allow us to reuse code instead of repeating it? Yes, it does. Functions and subprocedures can encapsulate repeated code. And – in most implementations – code can be split into separate reusable “modules”. In the GNU77 version I used for this example, multiple “library” files can be separately compiled and linked to a main program, allowing for relatively easy reuse.
  4. Should Fortran 77 code be composed out of the simplest parts? It’s entirely possible to write Fortran 77 programs that are made out of functions and subprocedures that are very simple, if you choose to. Whether the language scales to very large composed programs of tens of thousands of lines of code is an interesting challenge. There are some limitations on naming in particular (Fortran 77 names aren’t case-sensitive, and cannot be qualified with namespaces or module names, so more thought is needed to prevent us running out of unique and meaningful names as we add more and more parts. But in 1979, this was less of a problem because of hardware limitations)

By and large, Simple Design is perfectly feasible in Fortran 77.

What about Tell, Don’t Ask? Let’s consider a familar example of a function that knows too much.

The dialect of Fortran 77 implemented for the GNU77 compiler doesn’t support data structures (other dialects, like the one I used at university running on Sun hardware did). So we have to pass in all of the data about the room and the carpet as individual parameters to calculate a quote. We are somewhat limited in what we can do as far as data encapsulation is concerned as a result.

If this was Fortran 90 or later (or Sun F77), we could have user-defined types for the room’s dimensions and the carpet’s pricing data, and we could encapsulate their creation in the same modules that access that data. In F90, we also have some control over visibility of module features. (See how similar language features enabled data encapsulation in C in a previous post.) So, if this was Fortran 90, things would be much easier.

In F77, we have a teeny bit of wiggle room to represent an “object” (e.g., a room) as a single entity that quote() doesn’t need to know the internal details of: we could represent the room’s dimensions as an array.

And our test client just passes in the room array.

It’s not so easy for the carpet pricing data. Fortran 77 arrays can only be of a single data type, so we can’t easily represent a real and boolean value in the same array without adding considerable complexity (e.g., a function for translating 0.0 an 1.0 into FALSE and TRUE). Is it worth it?

But it would be worth extracting a function in its own module for calculating the price of a carpet for an area of room, so that each module has a Single Responsibility.

So quote() can be simplied to:

Now, could we make these dependencies swappable? Well, surprisingly for this language, we can. Fortran 77 allows function references to be passed as parameters. So we could, for example, swap our area_of_room() function with a different implementation that has the same signature.

What if we also want to calculate the area of carpet required to fill a circular room?

If we add a function parameter to quote()…

…we can substitute this implementation by injection from the test program.

This is only possible if the data required by each implementation either doesn’t change – so the parameters stay the same – or can be encapsulated (e.g., in an array) as a single parameter. Fortran 77 has very little support for data encapsulation, and this limits the scope for swappability. So I give it 50% for swappability.

Finally, since Fortran 77 has no explicit concept of modules, interfaces and visibility, we can’t control what features are exposed to a client. We can control what features that client uses, of course. But in my G77 set-up, if I make any change to any module, all the modules that depend on it have to be recompiled, even if they don’t use the feature I changed.

So, to sum up: Fortran 77 ticks quite a few of my boxes and has some limited SOLID credentials, but it’s not quite there. Fortran 90 fixed some of these problems, with derived types, explicit modules and explicit interfaces, making it more like C in those respects.

I give Fortran 77 6.5/10 for ease of applying these design principles.

 

You can find the complete source code at https://github.com/jasongorman/fortran-77-SOLID

 

 

 

S.O.L.I.D. in 1969?

For a talk I’m preparing on “Timeless Design Principles”, I thought it would be fun to journey back through the decades and demonstrate how the design principles I teach on the Codemanship courses could have been applied with the technology available at the time.

I’ve already show how it’s possible in C, so that takes us back to the 1989 – 30 years ago. But what if we travel back another 20 years to 1969: could we have written SOLID code then?

The short answers is “Yes, but…” And I’ll get to the “but…” at the end. For now, suffice to say that programming languages did exist in the late 1960s that enable SOLID code. The first object oriented language is Simula 67.

Here’s our now-familiar carpet quote example in Simula 67.

This CarpetQuote class takes two constructor parameters for a Room and a Carpet. They are simple data classes (“records”).

What we’ve got here is a classic case of a method that does more than one thing, as well as Feature Envy for the fields of Room and Carpet. Let’s fix that by extracting methods for calculating room area and carpet price, and moving them to where the data is.

So now CarpetQuote knows nothing about the details of how these calculations are done, and is greatly simplified into a composed method.

So that the S in SOLID, and Tell, Don’t Ask ticked off our list of modular design principles. What about swappability (the O, L and D in SOLID)?

The designers of Simula 67 provided a simple mechanism for this. If we declare them as virtual in a base class.

And we can implement them in subclasses.

CarpetQuote binds to the abstract types Room and Carpet still, so if we wanted to – for example – swap in a circular room, it’s a doddle.

Our test client can now pass in whichever shape of room it chooses, with no need to change CarpetQuote.

So we’ve ticked the Tell, Don’t Ask box, and the S, O, L and D boxes. What about Interface Segregation? Well, Simula 67 offers very limited support to achieve client-specific interfaces. We can hide methods a client doesn’t need to see using base classes that only declare those methods, but it’s a one-interface-per-class deal as Simula 67 doesn’t support multiple inheritance.

Having said that, if our classes only do one job, then I suspect the need for multiple interfaces to support multiple clients would be quite limited.

On the whole, it’s good news for our design principles in Simula 67. Now for the bad news…

The observant among you may have noticed that all of these code gists have the same file name. As far as I’ve been able to learn, with very limited – and often conflicting – documentation for a language I don’t think more than a handful of people have used in decades, the GNU Cim Simula compiler only accepts a single .sim source file. So true modularity isn’t possible with the tools available today.

I suspect in 1967 that – with very limited computing power – Simula programs didn’t get so big that they necessarily needed to be split multiple source files. There is some limited support for a kind of modularity (classes inside classes or “packages”), but that seems to be in the same single file only.

With more time and bit of work, someone could probably knock up a simple inline #INCLUDE pre-processor that could pull in code from other files, but that’s beyond the scope of my mini-adventure.

This has been fun and educational, though. I’d read about Simula but never tried it. Throwing together this little program was hard work, but seeing a 52-yeear-old language resurrected on my Windows laptop was rewarding – like hearing the engine of a classic car revving into life after it’s been rusting in someone’s garage since the 1980s.

If you’d like to have a go at some Simula yourself, here are a few resources to get you started:

  • GNU Cim Simula compiler (on modern Windows, follow the instructions for Win NT) – generates C code and then compiles with GCC
  • Introduction to Simula 67 – warning: the code in this guide almost certainly was not actually run on a computer
  • Simula 67 grammar – you’re going to need this, because almost all the guides I found online are not correct Simula 67

And you can find the complete source listing here.

Without syntax-directed support in my editor, and with the often not-very-helpful guides and compiler error messages, this little exercise involved a certain amount of trial and error to figure out exactly what the syntax is. In that sense, it was quite a nostalgic trip down memory lane. This is how things were 30+ years ago: learning to code from printed listings and misleading documentation by trial and error. It’s also the reason why I never publish code that I haven’t seen compile and run correctly. Academics: I’m looking at you!

 

 

 

S.O.L.I.D. in Kotlin

My journey of demonstrating how S.O.L.I.D. design principles can be applied in a range of programming languages going back 50+ years gets bang up-to-date with an example in Kotlin.

Now, you could probably argue that Kotlin is a no-brainer where this is concerned. Anything I can do in Java I can do in Kotlin, if I choose to. Kotlin has classes, interfaces and constructors. We can make data private just as easily as in Java. But still, I hear objections from developers doing pure FP in Kotlin that either:

a. “OO” design principles don’t apply (which is why I’ve stopped calling them that – they’re modular design principles), or…

b. We don’t need to apply S.O.L.I.D. to functional programming, because FP is innately S.O.L.I.D. (Spoiler Alert: it isn’t.)

Whereas with older languages like C and Fortran 77, I’m working harder to get around some language limitations, with languages like Kotlin and Clojure, I’m having to work harder to get around cultural limitations. To be fair, this is not a new phenomenon. I can clearly recall programmers telling me – in the heydey of OOP in the mid-to-late 90s – that you didn’t need to think about things like modularity because OOP is innately modular. (Spoiler Alert: it wasn’t.) Give a C programmer C++ and they’ll write you procedural C++ code. And, as my previous post illustrated, give a C++ programmer C and they’ll find a way to create objects with it.

I define code that’s effectively modular by three key properties:

  • It’s made of discrete parts that do one job each
  • Those parts know as little as possible about each other
  • Those parts are easily swappable

There’s no programming language on Earth that forces us to write code that ticks all three boxes. You have to tick the boxes yourself by the design choices you make.

Granted, there are things we need from a programming language to enabe effective modularity:

  • The ability to break code up into discrete reusable units (i.e., modules)
  • The ability to control what client code can see of a module (or – in the case of Ruby, Python, JS etc – the ability to make that not matter with dynamic binding)
  • The ability to dynamically substitute a different implementation without re-writing the client code

These days, the vast majority of programming languages available to us score 3/3. There are some older languages that offer no mechanism for polymorphism, but you’re very probably not using one of them on a regular basis. You can even do it to a limited extent in Fortran 77. Any language that allows us to pass a function or procedure pointer/reference as a parameter is technically polymorphic.

Anyhoo, here we are in 2019, and the shiny new kid on the code block is JetBrain’s Kotlin. It’s a derivative of Java, with spiffy FP sensibilities. To an old Java hand like me, it takes no time at all to learn. Here’s the carpet quote example in Kotlin.

Again, the first problem that leaps out at me is that this function is doing more than one thing. It breaks the Single Responsibility principle. Let’s refactor each reason to change into its own function in its own module.

The next thing that’s bothering me is that our data classes Room and Carpet are unencapsulated. That’s always bugs me. In OO design, we say that data classes are a code smell. They hurt us in FP, too. A dependency’s a dependency. Let’s refactor our area() and price() functions into closures that hide the data from quote().

And yes, I would just as readily use a class instead of a closure. I’m not an FP purist.

This refactoring has killed two birds with one stone: we’re hiding the data from quote() and now we can easily swap in a different implementation for calculating room area and carpet price without changing quote().

For example, what about a circular room?

That ticks the O, the L and the D in S.O.L.I.D. – our dependencies are now easily swappable. So, so far, we’ve covered S.O.L.D. as well as Tell, Don’t Ask.

What about Interface Segregation? Well, unlike many languages that support FP, Kotlin also has direct support for classes that implement multiple client-specific interfaces. If we can do it in Java, we can do it in Kotlin.

Tick.

 

You can view the source files at https://github.com/jasongorman/kotlin_solid

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.