DEV Community

Cover image for Writing Beautiful Code
Andrew Davis
Andrew Davis

Posted on

Writing Beautiful Code

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
mrtnrdl profile image
Martin Riedel

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 ;)

Collapse
 
marcus profile image
Marcus M

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?

Collapse
 
mrtnrdl profile image
Martin Riedel

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.

Collapse
 
restoreddev profile image
Andrew Davis

Unit tests are the best!

Collapse
 
6temes profile image
Daniel

If you want to make your code even more beautiful:

$validateEmail = filter_var($emailAddress, FILTER_VALIDATE_EMAIL);
$validateMessage = strlen($message->text()) < 1000;

if (!$validateEmail || !$validateMessage) {
  return false;
}

return true;

would be:

$isEmailValid = filter_var($emailAddress, FILTER_VALIDATE_EMAIL);
$isMessageValid = strlen($message->text()) < 1000;

return $isEmailValid && $isMessageValid

(PHP is not my first language, so bear with me if there are missing brakets somewhere)

Collapse
 
bgadrian profile image
Adrian B.G.

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.

Collapse
 
adam_cyclones profile image
Adam Crockett 🌀

Magic number

Collapse
 
6temes profile image
Daniel

I said, "more beautiful", not "perfect" :P

Thread Thread
 
adam_cyclones profile image
Adam Crockett 🌀

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.

Thread Thread
 
6temes profile image
Daniel

Ah, yes! Semi colons... that thing. xD

Collapse
 
restoreddev profile image
Andrew Davis

Good call! I’ve seen several recommendations for using is/has in Boolean variable names.

Collapse
 
6temes profile image
Daniel • Edited

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.

Collapse
 
codemouse92 profile image
Jason C. McDonald • Edited

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.

Collapse
 
restoreddev profile image
Andrew Davis

I agree that comments are necessary, depending on the circumstance. Overall though, for standard CRUD operations, they can be unhelpful.

Collapse
 
btruhand profile image
Btara Truhandarien

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

Collapse
 
mfurmaniuk profile image
Michael

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.

Collapse
 
restoreddev profile image
Andrew Davis

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!

Collapse
 
sean profile image
TheAutismDada

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

Collapse
 
restoreddev profile image
Andrew Davis

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.

Collapse
 
itsdarrylnorris profile image
Darryl Norris

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.

Collapse
 
restoreddev profile image
Andrew Davis

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.

Collapse
 
twillied profile image
Tim Dwyer

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.

Collapse
 
plaoo profile image
Paolo Monni
Collapse
 
mohamedelidrissi profile image
Mohamed Elidrissi

It never hurts to write organized and clean code, even if its not open-source and its only a personal project

Collapse
 
zaratedev profile image
Jonathan Zarate

Hey there! awesome article.
Look my php cs fixer config file
gist.github.com/zaratedev/9220085c...

Collapse
 
tux0r profile image
tux0r • Edited

Note that filter_var(..., FILTER_VALIDATE_EMAIL) does most likely not cover Unicode/"emoji" domains, so you should not rely on that.

Collapse
 
restoreddev profile image
Andrew Davis

Thanks! I was just using it as an example.

Collapse
 
thebouv profile image
Anthony Bouvier

Obligatory XKCD: xkcd.com/844/