In the previous post of this series I wrote about the importance of knowing your problem domain, understanding the requirements and defining the tests to be passed.
I am grateful for all the positive feedback I got, but a number of readers felt that it was too long and hard to absorb. So I am going to abandon my initial idea of writing one post per design rule.
By slicing my thoughts and interpretation of Beck’s design rules into smaller chunks and subtopics I also get the possibility to explore the rules more deeply, which I am looking forward to.
Today I dive into Kent Beck’s second rule for simple software design as expressed by Martin Fowler: “Reveals intention”.
That phrase is short, on point, and easy to remember. It is, however, worth taking a look at what the people involved in developing these rules wrote when they discussed the ideas on the original C2 wiki-page:
“The next most important thing [after passing the tests – ed. Note] is that the code is as easy to understand as possible, therefore we need to ensure that it expresses every idea that we need to express clearly”
— Jason Yip
It’s important to remember that we don’t write code for machines. If we did, we could (and should) write binary code. Since we write code to be understood and maintained by other people, we don’t, because we humans are not naturally able to get the meaning of huge blocks of 0 and 1.
Any code we write serves two purposes:
- Make the machine behave in the way we want
- Tell the reader what we expect that behaviour to be
While the first purpose seems obvious, we often forget about the second one, which is although equally important if we aim for low maintenance cost and long-term success.
So how can we make our code readable and understandable? What are the possibilities we have, particularly in database development?
Expressive Naming
“There are only two hard things in Computer Science: cache invalidation and naming things.”
— Phil Karlton
Naming is a key element of readable source code and that’s the reason why it’s seen as a tough task by many developers throughout all experience levels. The names of tables, views, variables and methods are the primary point of interaction people have with your code, and can either help or hinder understanding of that code.
Ideally, your code should be able to tell its own story, largely without comments.
If you read your code, does it flow? Does it make sense? If not, is the problem with the names or the structure? Do you find yourself stumbling over how things are named?
Things that DO and things that ARE
Steven Feuerstein came up with this powerful thought I want to pick up: to be able to tell our story we have to distinguish between things that do and things that are.
Things that ARE:
- Tables
- Views
- Columns
- Variables
- Types
- Records
- Objects
Things that DO:
- Procedures
- Functions
- Triggers
- Jobs
There is even a third category, I’d call it the things that ORGANIZE:
- Packages (in Oracle)
- Schemas (in SQL Server, not to confuse with Schemas in Oracle)
- Classes (in many object-oriented languages)
- Namespaces (also in many other languages)
These can be used to give more context and reveal something general about their content.
Get practical and let the code talk
Let’s hop into some examples how naming can greatly improve readability:
Suboptimal approach
create table soldier_grp ( id int not null primary key, name varchar2(256) ); [...] create table planet_x_sold_grp ( sold_grp_id integer primary key, planet_id integer not null, ... );
Readable approach
create table soldier_groups ( id int not null primary key, name varchar2(256) ); [...] create table planet_garrison ( soldier_group_id integer primary key, planet_id integer not null, ... );
We used shortcuts sparingly. Shortcuts need a lot of context – the more you use them, the more (probably very specific) knowledge you require the future reader and maintainer of your code to know.
We also used terms related to the business domain (“planet_garrison” instead of the technical “planet_x_sold_grp”) and provided a lot of context and meaning.
Suboptimal approach
create or replace package planet_util as procedure update_grp_planet( a simple_integer, b simple_integer ); function get_planet( a simple_integer ) return planets.id%type; end;
Readable approach
create or replace package soldier_group_action as procedure move_to( i_group_id simple_integer, i_planet_id simple_integer ); function current_planet_id( i_group_id simple_integer ) return planets.id%type; end;
There are several things which improve the readability of the second approach:
- The package gives meaningful context. In the first example it is even misleading because it concentrates on the planet instead of the soldier group.
- We concentrate more on the what (“move_to”) than of the how (“update_grp_planet”) in the second approach. This reveals the intention rather then the technique, which is far less interesting for both, the reader and the potential user of the method.
- We removed as much “unnecessary” information from the names as possible and utilized the specifics of the language’s syntax:
The function to return the current planet is not “get_planet” – PLSQL always expects an assignment target for the return value of a function so we already know it’s a function from the syntax.
By looking at the code which calls our methods, we can also notice how much more readable our public API becomes with these changes:
Suboptimal approach
begin planet_util.update_grp_planet( 1, 1 ); dbms_output.put_line( 'Current planet: ' || to_char(planet_util.get_planet( 1 )) ); end;
Readable approach
begin soldier_group_action.move_to( i_group_id => 1, i_planet_id => 1 ); dbms_output.put_line( 'Current planet: ' || to_char(soldier_group_action.current_planet_id( 1 )) ); end;
We can also see how the use of parameter-notation provides additional information if we name our parameters properly.
Let’s look into one more example:
Suboptimal approach
create or replace view soldier_groups_1 as select ... --inner-join on planets ; create or replace view soldier_groups_2 as select ... --outer-join on planets
Readable approach
create or replace view soldier_groups_stationed as select ... --inner-join on planets ; create or replace view soldier_groups_all as select ... --outer-join on planets
By refusing to use digits as difference we added more of the what to the name and made it very clear to the reader what the difference between the two views is.
I provide a full example of both approaches at Oracle’s LiveSQL:
Suboptimal vs. Readable
General advice
Do you think the second approach was more readable? Could you read and understand it more easily?
If so, great, read on! If not I’d love to enter a conversation with you, don’t hestitate to use the comment possibility or reach out for me via twitter or e-mail!
Finally, I offer some general suggestions to help you excel at naming:
- Whatever you do, be consistent. If you prefix your parameters with “i”, do it everywhere. If you call your table “planets”, use that term throughout your database application and don’t start to refer to them as “celestial bodies”.
- Be careful not to use the same term for different things: “force” in a Jedi/Sith context is something completely different than “force” in a racing simulation
- The Trivadis AG published a great set of naming conventions for PL/SQL and SQL
- Kevlin Henney has a lot to say on the topic of naming
- Read other people’s code. Apply the same rules as when you read your own. What works and what doesn’t?
Mindful naming
The world we live in is biased. I guess it’s an integral part of our human nature – and so is software development. Software might seem non-sexual, non-racial, non-biased from the first glance, but software is written by humans and therefore reflects their struggles, aspirations and prejudices.
You don’t want a developer to feel uncomfortable or perhaps even insulted when they read through your code.
For example, I avoid using “master/slave” terminology in my software. Those terms are simply too loaded to be useful. Instead, I go with “parent/child” or “primary/replica”.
Of course, it can be tricky even realizing that something you’ve written might offend someone else. But you can at least follow these two rules:
- If you hear a little voice in your head expressing concern, listen to that voice and change what you are doing.
- If you want to improve your ability to realize what might offend someone else, listen to people who are affected.
There’s a Twitter-Thread by @mzbat where she was asked to change a slide in her deck about “black hat hackers” and “white hat hackers”. It’s a great thread with many thoughtful answers, but what deeply impressed me was her conclusion (POC = people of color):
I don’t know what the answer is, but I do know that I’m not qualified to tell a POC what is or isn’t racially insensitive. If one child of color in the audience would’ve been hurt by a cowboy analogy they didn’t understand, that’s one too many. Peace & Love y’all. ❤️
— socially distant, mask wearing bat (@mzbat) May 12, 2018
If we all could just act that empathetic and compassionate it would certainly make our world a much better place.
0 Comments