Because programming is a technical profession, we often approach it without thought to design. Code is for getting a computer to do what we need, why should design matter? The majority of the programming languages we use were built for the programmer and are transformed into something that is optimized for the computer. As a result, we need to write our code, not just for the compiler or interpreter, but for humans to read. To make code readable, I approach it as an art. When you treat code as art, it becomes quickly digestible and easy to extend. Creative code also reduces bugs because it is easier to understand what it is executing.
The problem with artful coding is that it is not easy to do. Oftentimes, it is hard enough to get the code to work in the first place, much less be creative! However, just like any art form, there are some basic techniques we can follow to write well designed code. I am still exploring the best ways to write beautiful code, but these steps are what I follow to bring a little art to my programming.
Start with a Unit Test
Test Driven Development is not universally liked, but I find it to be a very good practice. Not only does it ensure all your code is tested, it also forces you to think about how your code will be used before writing it. In these examples, let’s imagine we are writing an email client in PHP and we want to be creative in the client’s design. Let’s start with a unit test for sending an email:
<?php
class EmailClientTest extends \PHPUnit\Framework\TestCase
{
public function test_sending_an_email()
{
$client = new \Email\Client();
$emailMessage = new \Email\Message('Hello world!');
$result = $client->send('andrew@dev.to', $emailMessage);
$this->assertTrue($result);
}
}
Since we wrote the unit test first, we already know how we want the code to be shaped. We know we will have an Email
namespace with two classes representing the Client
and the Message
. We also know that we will have a send
method for the process of submitting the email message with the client. In the unit test, we also decided how the pieces of our code will be named, which brings us to my next point.
Use Grammar when Naming Variables and Methods
Programmers often joke that naming things is hard and it’s the truth! However, naming a piece of code is not just hard, it’s also very important. How code is named determines how quickly a developer can understand it, reducing bugs and development time. In the above example, we decided to put all of our code in the Email namespace which is very clear about what it contains. Next, we chose Client
to represent the object that sends messages and Message
for the email itself, both descriptive nouns. Finally, we call a send
method which is a verb commonly associated with email. Now, we see a good pattern: use nouns for class names and verbs for methods.
Keep Your Functions Small
It is tempting to put all the code for an operation in a single function. However, it’s really important to break it up into small chunks for readability and testability. Let’s use the send
method as an example.
<?php
namespace Email;
class Client
{
public function send(string $emailAddress, Message $message): bool
{
// Validate parameters
$validateEmail = filter_var($emailAddress, FILTER_VALIDATE_EMAIL);
$validateMessage = strlen($message->text()) < 1000;
if (!$validateEmail || !$validateMessage) {
return false;
}
// Communicate with email server
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://mail.example.com');
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, [
'to' => $emailAddress,
'text' => $message->text(),
]);
$result = curl_exec($curl);
curl_close($curl);
return $result;
}
}
This method is straightforward, but cluttered. It’s a little difficult to understand, so we added some comments so the reader knows what is happening. However, what if we created a new method instead of a comment?
<?php
namespace Email;
class Client
{
public function send(string $emailAddress, Message $message): bool
{
if (!$this->validateParameters($emailAddress, $message)) {
return false;
}
return $this->sendToMailServer([
'to' => $emailAddress,
'text' => $message->text(),
]);
}
private function validateParameters(string $emailAddress, Message $message): bool
{
$validateEmail = filter_var($emailAddress, FILTER_VALIDATE_EMAIL);
$validateMessage = strlen($message->text()) < 1000;
if (!$validateEmail || !$validateMessage) {
return false;
}
return true;
}
private function sendToMailServer(array $params): bool
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://mail.example.com');
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
$result = curl_exec($curl);
curl_close($curl);
return $result;
}
}
Our send
method is now much cleaner. The other functions perform a single task with less than 10 lines of code each, making them easy to read.
Use a Style Guide
Finally, I recommend using a style guide for your chosen programming language. For PHP, I like to use the PSR-2 FIG standard for my code. The FIG standard is widely recognized and used by popular PHP frameworks like Laravel and Symfony. Plus, the Symfony team has released a CLI utility that automagically reformats your code to follow PSR-2: PHP Coding Standards Fixer.
Conclusion
Designing code requires effort and practice, but reaps many rewards. It causes your code to be in smaller, more readable chunks and reduces bugs by bringing clarity and focus. To continue learning more, I recommend reading code that is well designed. The Laravel and Ruby on Rails codebases are both examples of clean code that is treated with an artful touch. Do some source diving in both to learn more!
Top comments (28)
For me it worked best if i treated the code i write not as something i write for a computer to execute. I treat code as a sort of documentation for other humans that might end up maintaining whatever i wrote.
In that regard, i value your first point a lot. A good suite of tests has proven to be invaluable (for me) when i had to add/refactore something in code i either didn't write or wrote more than 2 days ago - because i may or may not have any memories about that ;)
Regarding 1st paragraph: That is an great way to write your code. I'll try to do the same, but sometimes end up with long function names.
How do you handle this?
Are you for or against abbreviations?
When there is an 'and' or 'or' or something like this in the function name, i'll split it in two. Because obviously there are multiple concerns handled there.
If they are only long, i'm fine with that. Most of the time, one of my colleagues has a shorter suggestion in the review anyway :)
I'm not a huge fan of abbreviations - it hugely depends on the business domain and whether or not these abbreviations are kinda well known or not.
Unit tests are the best!
If you want to make your code even more beautiful:
would be:
(PHP is not my first language, so bear with me if there are missing brakets somewhere)
Magic number
I said, "more beautiful", not "perfect" :P
Exactly, prettiest is perfect. One semi colon and a constant away from perfection and we can close this thread. Haha sorry I know this isn't a peer review, old habits and all that.
Ah, yes! Semi colons... that thing. xD
This will not work in a real project, most likely you will have to provide a message on why exactly the invalidation failed.
One liners are always on my radar on "smelly code", they usually lead to nasty problems.
Good call! I’ve seen several recommendations for using is/has in Boolean variable names.
Well,
is
/has
is a convention. In Ruby it is common to use "question mark" instead.But, more importantly, I would not use an imperative verb to name this boolean variable.
Imperative would more appropriate for methods (or functions) that have side effects. In this case, you are using the variable to store the result of a computation.
Great tips! While I still advocate intent-commenting (won't go into that yet again here), I think these principles are superb! (+10 to style guides.)
Nice rule of thumb to go along with this: the "what" of your code should always be clear without comments.
I agree that comments are necessary, depending on the circumstance. Overall though, for standard CRUD operations, they can be unhelpful.
Not just beautiful code, but overall design that scales, performance wise and cognitive wise. For many developers' day to day, it is not in the logical aspect of programming that is difficult (least what I've seen), but it's in the creation and choice of design
Spot on! Obviously form should always follow function but form should always receive proper attention as it clarifies intent and helps create trim, efficient code. Thanks for the standards fixer link.
After some recent discussions with co-workers I sort of changed the way I wrote code, fewer comments and more writing code as a story. Make it understandable and readable the way it is, only commenting when you have something exotic or very detailed in the way the code works (which should be rare). Its helped me make things simpler and break things down more, I still find myself needing improvement but this was one I hadn't thought of and decided was needed.
I think we never stop learning to code better. I always feel like there are even better ways to write it. I would like to see even more opinions about beautiful code so we can all share ideas!
An interesting point of keeping the function small it's that you might be able to reuse that function later on. On another hand, I have experience that the complexity of the code sometimes increases by writing small functions, because of similar processing needs to happen on different functions that they are isolated from each other.
I think in the end there has to be a trade-off between performance vs. keeping the functions small.
There’s always a trade off, but I think in general coders are more inclined to make functions too big than to make too many functions.
Love the tips. For me, beautiful code is something you can look at and within a second understand the flow of the code. When it is structured correctly you don't have to know exactly what the code does to understand the flow.
That's just my definition anyhow. Thanks for sharing
I agree! Everyone hates going back to code that can take hours to understand what is happening. Beautiful Code is about reducing that time down to seconds and minutes.
It never hurts to write organized and clean code, even if its not open-source and its only a personal project
This for python
github.com/google/styleguide/blob/...