The real problem: improper separation of concerns.

I just read the following article: Stop Using Function Parameters Now.

It was an article which called for using a Javascript feature for passing parameters, which in a language like Swift could be done using default parameter assignments and named fields.

Here’s the example:

// Recieves a name and returns a greeting message
// Typescript
function greet(name: string): string {
    return `Hello, ${name}`; 
// Javascript
function greet(name) {
    return `Hello, ${name}`; 

The contract is simple — provided a name, the function will return a greeting message. A name is all we’ve got and all we need at the moment.

In a few months though, when the function is already used all over the code base, we find ourselves in a need of adding a last name to the greeting message.

We could, of course, just use the name parameter for the last name as well, but since we’re deeply aware of the differences between Internationalization and Localization we know that in some countries the last name can come first. We want our product to be the best fit for our users around the globe, so we want to support this use case.

Since the function is already used in many places across the code base we want to make sure it’s backwards compatible.

The article then goes on for a while talking about how messy this interface can be if you add every conceivable parameter (like first name, last name, honorific, surname) and how we can solve this by using a Javascript feature for passing arguments. It’s worth scanning the article to understand what the argument is.

Here’s the problem.

What is a name?

One of the things I appreciate about software development is that at some level you have to become a philosopher if you want to become a really great software developer. I don’t claim to be great, but I do find philosophy helps.

In this case, philosophical ideas around taxonomy, classification, and ontology–or how we know things.

So again, the question is “what is a name?”

Is a name a string? Is it the tuple (first name, middle name, last name)? What about people without middle names? Is it a unicode string? Does it have type attributes associated with marriage, degree, honorifics? Is there an optional “the Third, the Fourth, Junior” attributes?

When we start asking these questions, and start thinking of how to pass a name with all these attributes to our modified greeting function, we’ve lost our way completely.

The answer? A name is an attribute of a named thing. For our purposes in this application, a name is something we call a person.

This is why I really dislike the article linked at the top.

Because any time you find yourself looking at a function like greet above, and you find you’re trying to add additional attributes to handle different cases of what a ‘name’ is–rather than using some language trick to hide the parameters being passed (and notice how the body of greet later in his article is completely glossed over–“some implementation” indeed!)–instead you need to stop and ask yourself “should I be passing an object that encapsulates the property I need here?”

Because you know damned good and well it’s not just greet that needs the name. The name is being used everywhere else in your code–and I guarantee you some variation of the body of the function in greet is scattered throughout your source kit. Perhaps even in a few dozen places–cut-and-pasted from the original greet function, sometimes poorly maintained or even ignored as the requirements change.

This falls into the category of “separation of concerns.”

Consider the “model/view/controller” model of writing a user interface. You may not think of greet as fitting into this paradigm, but it most definitely does–as view code. That is, as a part of your application engaged in presenting a user interface to the user.

Sure, it’s not a table with multiple variables populated across several databases joined by a complex query. But it still is a user interface element–view code.

A user interface element which ideally takes a model representation, and which is invoked by controller code that calls greet when required by our business logic.

And your greet function has no business implementing what should be model code–that is, what should be code that determines the string representing the name of a model object “person”.

(As a note: any time you find yourself cutting and pasting code in your application in order to do the same thing, you’re dealing with a separation of concerns issue. The repeated code would probably be better off wrapped as a method, where it is expressed once, and instead of a half-dozen places where maintenance engineers will forget to fix them all if a bug surfaces.

Just as anytime you find yourself hacking a method like greet to process names, when the model should be processing the person’s name, I guarantee you, you’ll find copies of the body of greet scattered throughout your code. And all “object destructuring” is doing is giving us a way to hide our crimes.)

The solution?

It depends on your business logic, but in the past I’ve implemented the equivalent of:

// Swift
func greet(person: PersonRecord) -> String {
    return "Hello, \( person.informalName() )"

With the method “informalName” being a method which provides an ‘informal name’ for the person–in the case of an application I worked on, the concatenation of a first name (if present in the database) along with the first initial of the last name (again, if present). So for my name “Bill Woody” the function would return “Bill W.”

(No, I did not design the database’s first name/last name scheme; I have had several Korean and Vietnamese friends and I know damned good and well in some cultures the first name is the family name; the second is the given name. But that’s a rant for another day.)

Your requirements may be different.

But notice: determining what the proper name is is not the job of the controller code which calls greet, and formatting the proper name is not the job of the greet function. It is the job of the PersonRecord model, which understands what a person is, and how people in your system are named.

And because all of our name handling code is now in one place–in the PersonRecord method–rather than scattered throughout the source kit, as would be the case if we followed the original developer’s advise of not pausing and considering if what we’re doing is even the right answer, we can tackle and deal with “myths about names that programmers believe”.

All in one place.

Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s