Jonathan Boccara's blog

What 70 people came up with on expressive code

Published February 6, 2017 - 7 Comments

What 70 people had to say about expressive code in a meetup of software craftmanship

Last week held the monthly meetup of Software Craftsmanship in my area. The organizer, Stéphane Bagnier, proposed a very original and interesting schedule for the evening. After a short series of brief and spontaneous presentations, any attendee could propose a topic he found worth spending time talking about, and then everyone got to vote. The 2 topics receiving the most votes were selected to be the topics for the rest of the evening.

I proposed the topic of expressive code and it ended up winning over the votes, and the other one that got selected was about how to be productive as a software developer. I reckon over 70 people participated to the expressive coding debate. And these 70 people are not just random people. They are the kind of person that go to meetups, which means they invest time into learning and getting better at software development. And pretty much every one in the room had something to share on the topic of expressive code. What an incredible night.

The evening was so enriching that I felt I had to share what came out of it, so that more people can benefit. After all, it’s not every day that you have an interesting conversation with 70 good people about your favorite topic.

If you’re in the area I strongly recommend you attend the meetup of Software Craftmanship. Every single person expressed he was very satisfied at the end of the evening and went away with something he had learned. And whilst I’m at it, if you’re in the area you can also come by to the C++ meetup, where I’ll be talking in the February session.

Knowing the librairies of your language

The first topic we delved into was the importance of documenting ourselves about what existed in the standard (or almost standard) libraries of your language. For C++ this would be the standard library, Boost, the future features of the language, and potentially reading technical specifications (although those might be more difficult to read).

There are two benefits from knowing what the language and standard libraries have to offer.

The first one is that these are as many tools in your developer toolbox. Knowing them prevents you from reinventing the wheel, and provide wheels of high quality and extensively tested. The more of them you know, the easier it becomes for you to express your intentions in code (or to understand other people’s intentions when they use them).

If it were just that, you could rely on code review from experienced co-workers to mutualize knowledge and find the best solution as a group. But there is another benefit to know what libraries offer: you build over time a mental reprensentation of what can be abstracted in code. Every standard library feature is another abstraction, that gives you another example of how to build your own. Therefore this volume of knowledge helps you become more creative in your code, by inspiring yourself from (good) existing solutions. Typically knowing all STL algorithms helps a lot in rolling out your own. More on this in a future post.

You may ask yourself: how can I possibly know all the features my language offers? For C++ this is certainly a hell of a lot. I believe there is no magic here, and this comes down to hard work (but spread over time to make it manageable) and picking the right resources. Obviously you don’t have to know all features of all libraries to see the effects of this, but the more you’ve seen, the more equiped you are.

Here are a collection of C++ resources to that make easy learning about:

Good naming

Unsurprisingly enough, careful naming came up often in the topic of creating expressive code. It was seen as a crucial feature of good code.

People that had experience with DDD recommended showing business concepts through the names used in the code.

Naming was seen as a make-or-break characteristic of the code, because you generally have to trust a name (even though you can still peek into the implementation code behind it from times to times). So incorrect names or misleading ones can send you off to a wrong direction and make you spend enormous amounts of time while tracking a bug. In this regard, misleading names are even more detrimental than unclear ones.

Naming conventions in companies were briefly discussed too. The advantages of naming convention is removing some useless language/formatting barrier when reading code from somebody else in your company, and increasing the chances that you will easily spot it when you implement a funtion that has already been done by someone else. However someone pointed out that you’re forced to re-learn a set of conventions every time you get into a new company, and that some of them are of questionable quality.

But there is a lot more to say about good naming.

Comments

The polemic topic of comment came up in the discussion. Should we put comments to clarify our intentions in code, or should we rather rework on the code to make it clear enough so that it doesn’t need to be commented? The majority in the room were arguing for the second solution: don’t put comments as their need indicates you should rather improve the quality of the corresponding code.

Moreover, as mentionned above with misleading names, misleading comments can send you off to the wrong direction, being more detrimental than having no comments at all. Indeed, nothing guarantees that comments evolve in sync with code: a comment that was valid at some point may become incorrect when code evolves, if it is not maintained.

Somebody pointed out an interesting use case for putting in comments though: when they are several code designs that all look correct and readable, but you were forced to choose one in particular because of reasons that are not apparent in the code (implementation issue in code you depend on, performance, …). This way you will save time to the next person that would have tried to refactor your code into one of these other designs.

Using Algebraic Data Types (ADT)

ADT are a concept coming from functional programming that lets you define types as being something OR something else, when we traditionnally defines structures as being something AND something else.

For example: a Person has a first name AND a last name AND an address. But he can also have a telephone OR an email (say he doesn’t have both). Then you need to be able to precisely express this in code, otherwise you will be dragging around a piece of information that doesn’t make sense.

In C++ this can be achieved with std::variant.

An other idiom used in functional programming that helps with code clarity is pattern matching (although I’m not sure how this can be emulated in C++ as of today).

Writing tests to clarify what the code intends to do

Somebody told how his manager viewed tests as a waste of time, particularly for legacy code that was already in place.

This spurred an interesting debate about how tests were an investment rather than a waste of time, and people shared their stories. Someone told us how he had to invest 3 weeks into a heavy refactoring that let him write comprehensive tests over previously unintelligible code, that utimately turned out to be profitable because they let the business people ask for more functionalities to be added, where everyone thought no evolution was reasonably expectable because of the initial lack of control on the code.

Finally somebody remarked that tests, once written, were there all the time. Contrary to humans tests never sleep and they never go on holidays. They constantly check that your code is still working. And most of them (like unit tests) do them way faster that anyone would do manually.

Fighting the primitive obsession

Primitive obsession is an anti-pattern that consists of using primitive types (like int, double, std::string…) to represent information that have more semantics that being just an int for example.

One solution to avoid primitive obsession is using strong types. People from a Java background noted that the JIT mechanism let the virtual maching make performance optimizations that relieved the programmer to worry about wasting performance by adding strong type mechanics.

But we noted that although strong types were natively present in some functional languages like Haskell (with the newtype construct), they were lacking in languages widely used in the industry, such as C++, Java or C#.

How long should a function be?

It was cleary accepted that excessive length in terms of lines of code in a function was detrimental for readability.  In his book Clean Code, Bob Martin recommends that “Functions should hardly ever be 20 lines long”.

Two solutions were proposed to reduce the size of a function:

  • Making sure it has only one responsibility, and break it down in several functions otherwise. Understand the different steps in the story the function is telling, and take them out into several sub-functions. This ties up with respecting levels of abstraction.
  • Writing unit tests, as it forces the code to be split up into units, which are parts that make more functional sense.

Having smaller functions encourages code reuse, because small functions perfom targeted tasks that can are common to several needs.

See you there

This is pretty much everything that I noted that came out of the debate, that lasted just over an hour. We had set a limited time to talk about each topic because we wanted to cover as many of them as possible, but there were still plenty of interesting ones that were suggested and that we didn’t have the time to tackle.

Each of the above topics and those that weren’t covered would deserve more attention, and some of them are appropriate for future posts. In the meantime stay tuned, and for those who can, I will see you there.

Related articles:

References:

 

Don't want to miss out ? Follow:   twitterlinkedinrss
Share this post!Facebooktwitterlinkedin

Comments are closed