Work: Freelance programmer, trainer, writer, public speaker, consultant
Topics: object-oriented and Domain-Driven Design, architecture, refactoring, Test-Driven Development, pair/mob programming
Languages: PHP, Fortran
I am super-proud to tell you that I have finally published the print version of my book: "Legacy Code: First Aid Kit" 🎉 📕 🥲
I am super-proud to tell you that I have finally published the print version of my book: "Legacy Code: First Aid Kit" 🎉 📕 🥲
Almost everywhere in our code should we allow errors to bubble up to higher abstraction levels, until we get to the point that we'd like to terminate the program. How to do that properly?
Almost everywhere in our code should we allow errors to bubble up to higher abstraction levels, until we get to the point that we'd like to terminate the program. How to do that properly?
If we want guarantees that data in a DT is correct, we have to use a custom constructor. Such a constructor then needs another Either return type so it can return a validated instance or an error.
If we want guarantees that data in a DT is correct, we have to use a custom constructor. Such a constructor then needs another Either return type so it can return a validated instance or an error.
We redesign the error value so lower-level errors can be "wrapped" inside higher-level errors.
We redesign the error value so lower-level errors can be "wrapped" inside higher-level errors.
We consider a problem that involves parsing and find a solution to deal with errors: a parse function that returns an "Either" type, containing an error, or the expected result.
We consider a problem that involves parsing and find a solution to deal with errors: a parse function that returns an "Either" type, containing an error, or the expected result.
We look at an alternative solution for calculating the average of an empty list; only offer such a procedure for a non-empty list.
We look at an alternative solution for calculating the average of an empty list; only offer such a procedure for a non-empty list.
Instead of returning a success flag and use an intent(out) argument to return the actual function result, we implement an optional return value using an abstract derived type and two subtypes.
Instead of returning a success flag and use an intent(out) argument to return the actual function result, we implement an optional return value using an abstract derived type and two subtypes.
The first part in a series about dealing with errors: we explore some common approaches and what their downsides are.
The first part in a series about dealing with errors: we explore some common approaches and what their downsides are.
Having discussed filter and map which transform arrays into new arrays, we still need another function: reduce, which transforms arrays into single values.
Having discussed filter and map which transform arrays into new arrays, we still need another function: reduce, which transforms arrays into single values.
By introducing a list type we can bind the functional-style filter and map functions to a derived type, making it possible to "chain" multiple calls.
By introducing a list type we can bind the functional-style filter and map functions to a derived type, making it possible to "chain" multiple calls.
After discussing filter functions, now it's time to work no a map function.
After discussing filter functions, now it's time to work no a map function.
Fortran doesn't have good support for higher-order functions and closures, can we replicate them?
Fortran doesn't have good support for higher-order functions and closures, can we replicate them?
Fortran doesn't support generics, which would allow us to reuse the same filter function for arrays of different types of values. In this post we'll explore a work-around for this problem.
Fortran doesn't support generics, which would allow us to reuse the same filter function for arrays of different types of values. In this post we'll explore a work-around for this problem.
Having looked at Object-Oriented programming concepts in Fortran, we now dive into Functional programming concepts. We start with filtering arrays of integers.
Having looked at Object-Oriented programming concepts in Fortran, we now dive into Functional programming concepts. We start with filtering arrays of integers.
It's surprising how much there is to explore about enumeration types, but here we are with the final part: we further improve the design by making log level an abstract type, and all the concrete levels subtypes.
It's surprising how much there is to explore about enumeration types, but here we are with the final part: we further improve the design by making log level an abstract type, and all the concrete levels subtypes.
We increase type safety by narrowing the integer level argument to a derived type argument. A new factory type helps us separate responsibilities. Finally we compare levels using operator overloading.
We increase type safety by narrowing the integer level argument to a derived type argument. A new factory type helps us separate responsibilities. Finally we compare levels using operator overloading.
We are refactoring the integer parameters for the various log levels that we want to support. We want to accomplish type-safety and ease-of-use (pun intended).
We are refactoring the integer parameters for the various log levels that we want to support. We want to accomplish type-safety and ease-of-use (pun intended).
We splitt an existing module into smaller modules and put a façade module in front of the smaller ones, so users only have to deal with a simple programming interface. Finally we fix compilation cascade with a submodule.
We splitt an existing module into smaller modules and put a façade module in front of the smaller ones, so users only have to deal with a simple programming interface. Finally we fix compilation cascade with a submodule.
In this post we explore another way of composing abstractions, which is called decoration. We prefix existing log messages with a timestamp and implement optional delegation based on a configured log level.
In this post we explore another way of composing abstractions, which is called decoration. We prefix existing log messages with a timestamp and implement optional delegation based on a configured log level.
We are ready to build more features into the logging library, using different styles of composition. First we look at aggregation.
We are ready to build more features into the logging library, using different styles of composition. First we look at aggregation.
We define an abstract type with deferred procedures (in OO language: an interface) for the file logger. Introducing an abstract factory allows clients to decouple and shows us how polymorphism works.
We define an abstract type with deferred procedures (in OO language: an interface) for the file logger. Introducing an abstract factory allows clients to decouple and shows us how polymorphism works.
Derived types (DTs) can also be used for "service objects". We look at a safe refactoring from module state and subroutines to a DT with a data component and a type-bound procedure.
Derived types (DTs) can also be used for "service objects". We look at a safe refactoring from module state and subroutines to a DT with a data component and a type-bound procedure.
We make the data inside the derived type private (encapsulation), offer alternative ways for creating new instances (factory functions), and expose these alternatives as an abstract function.
We make the data inside the derived type private (encapsulation), offer alternative ways for creating new instances (factory functions), and expose these alternatives as an abstract function.