If Programming is an Art

Some of our best and brightest programmers classify programming as an art (Donald Knuth, Guido van Rossum, and Bjarne Stroustrup to name a few). Depending on who you ask, art is skill, craftsmanship, fine art like painting or sculpture, or perhaps solving problems despite walking blindly through the realm of the unknown. Donald Knuth says in Computer Programming as an Art:

Science is knowledge which we understand so well that we can teach it to a computer; and if we don't fully understand something, it is an art to deal with it.

Interesting... intriguing... but useful? When we hear this premise, programming is an art, what argument is it supporting? Or is it simply an observation devoid of practical value?

Beautiful code?

When the common programmer says programming is an art I believe they usually mean that they strive for beauty in their code. I also believe they are talking about the result, which is the code, not the process, which is the programming. I also define common programmers as programmers who are common in their field. They won't be writing any books and probably not speaking at any conferences but they're smart folks, have significant experience, and they get a lot done. I would put myself in this group.

I wrote beautiful code years ago. My code would have been tweaked repeatedly such that all its components seemed to be where they belonged by the end of my projects. In my gut it felt beautiful, but beautiful really just meant putting like things together. I arrived there without knowing why I was doing what I was doing, how it was good, and how it was bad. I was ignorant of just about every other meaningful attribute of my code.

My ability to compose such beauty created an internal illusion of my own expertise. What I did was working, wasn't it?

Beauty has no value in code

Try putting a monetary value on the beauty of code. How would you come up with such a number? Could you measure it without defining beauty in terms of things like extensibility, testability, readability, or other objectively measurable attributes? It would seem not. If art and beauty are simply imprecise terms for a conglomeration of these objective attributes, does it not detract from our discourse to use them at all?

Beauty is not one thing to all people. It is subjective and as such it is a terrible attribute for comparison. Is the Mona Lisa more beautiful than Jackass 3D? I don't know, I'm sick. Really sick.

Since beauty is subjective, anyone could claim that their code is beautiful and they'd be right and you'd also be right even if you disagreed. Jackass 3D is more beautiful than the Mona Lisa because I said so. It levels the playing field. Differences in coding practices become a matter of personal taste with no connection to real world consequences like expenditure of time and money. That is the true harm in this kind of thinking.

Maybe you write medical software so testability is extremely important. Maybe you write embedded software that will never be changed after its released so maybe you don't care about flexibility or extensibility. Maybe you need to ship your product in 3 days, or maybe 3 years. Maybe your team is junior HTML developers or maybe its programming gods who can flip bits with their minds. Different code attributes will have different business value depending on the changes (or lack there of) that your code will go through in its lifetime and the team that will see to those changes. This business knowledge should inform your coding practices, not some misguided quest for art.

Shit, I work with artists

My advice to those out there trying to make the case for less art and more of a practical approach to coding would be to:

  • Analyze the code, coding practices, and tools you use. What makes it hard to meet your business needs? Look at specific cases, because context matters. No silver bullets. No one size fits all. You want to solve a real problem, not sell a religion.
  • Avoid arguing minor details. For example, if you think its beneficial to make a big change to your system but you spend all your time arguing whether curly braces should be on the same line or the next line no one will listen to you. Choose your battles. Don't gain the reputation of the code nazi.
  • Read about how other people solve problems.

PCI DSS compliance and spaghetti code, Part 3

(Be sure to read Part 1 and Part 2 first!)

When writing new code I find its a good idea to start at your integration point and then write that client code, whether just by psuedo-coding or writing some test cases. For my payment gateway code I need code that takes user input, builds a request from that input, sends that request to the payment gateway, and gets a response back so we can act accordingly.

$factory = new RequestFactory(); 

$builder = $factory->buildSaleRequest(); // get sale builder

$builder->withCreditCard() // get credit card, so we can set it
    ->setCardType($_POST['cardType'])
    ->setCardNumber($_POST['cardNumber'])
    ->setExpirationDate($_POST['expirationDate']); 

$builder->withBillingAddress() // get address, so we can set it
    ->setCity($_POST['city'])
    ->setState($_POST['state']); 

$response = $builder->execute(); // send request to payment gateway

This seems pretty simple. I have objects to accept my user input which execute the request and get the response. Marvellous. Under the hood its slightly less simple if you aren't particularly familiar with the Factory pattern, Builder pattern, Gateway pattern, Composite pattern, and Visitor pattern.

Today I'll start at the surface with our creational patterns being used here, the Factory and Builder pattern.

Factory pattern

Factories, like all other creational patterns, create new objects. At first they are often understood as a way to make its consumer get different types of object, which is correct, but people fail to see that they are places to return differently configured objects (potentially of the same type) as well. Factories are the place to stowaway configuration information. In Factories the configuration can be centralized, rather than forcing the consumer code to have to repeat configuration each time. For example:

class CarFactory {
    public function create() {
        $car = new Car();
        if($this->config->useElectricCars()) {
            $car->setEngine(new ElectricEngine());
        } else {
            $car->setEngine(new EnvironmentDestroyingBeastEngine());
        }
        return $car;
    }
}

We encapsulate the querying of the "config" object into this Factory method so we don't need to have other parts of the system be aware of this "config" or aware of any configuration of this object at all.

In the case of the payment gateway RequestFactory, we'll be grabbing the payment gateway credentials, which get used in each request, and passing them onto the Request object that gets returned for consumption. This way other code need not worry about where those come from. We've made that decision and we've encapsulated it in a Factory.

Builder pattern

Most people I've seen learning about the Builder pattern don't really get it for a while. This was true for myself as well. We know what it is basically - a class with a bunch of methods you can call to configure an object and then a method to return the newly created and configured object - but don't know when to use it. A quick look at the pattern summary talks about varying complex creation processes. Yea, it can do that, but you have good reason to create those Builders even if you need only one implementation now.

Here are a few indicators to help you know when its time to use a Builder.

Indicator #1: Wiring together collaborators in application code

Are you doing this in your application code? You've written a library to create cars and car parts and everywhere you use this library you're repeating this process...

$carPartFactory = new CarPartFactory();
$carFactory = new CarFactory();
$car = $carFactory->create();

$car->setEngine($carPartFactory->createElectricEngine())
    ->setWheels($carPartFactory->createGoodYearTires(4))
    ->setStereo($carPartFactory->createBadAssStereo());

You're creating more than one factory to wire together collaborators. Its Builder time, bitches.

$carBuilder = new CarBuilder();
$car = $carBuilder->addElectricEngine()
                  ->addGoodYearTires(4)
                  ->addBadAssStereo()
                  ->build();

Its easier to use, less duplication, easier to read, and if you ever need to vary that creation process its already in place.

Indicator #2: Factory method with optional parameters

Optional parameters are terrible. I think thats a whole post al by itself. For now, if you find yourself doing this...

public function create($first, $last, $middle = '', $prefix = '', $suffix = '')

...do this instead...

$builder->first($first)
          ->last($last)
          ->middle($middle);

Builders in Builders

Final note of the day on Builders. Object chaining can make usage pretty easy. We get use to returning $this in each method. Sometimes though we want the Builder to return another Builder which can configure its collaborator. In this case we return the Builder instead of $this, but its also good to have a method naming convention to let developers know instinctively which they'll get back.

Personally, and I think I picked this up from a book though I can't remember which one, I use "set" or "add", whichever reads best, when I'll be returning $this, and "with" when I'll be returning another Builder. Sometimes I might even have a "set/add" method and a "with" method for configuring the same option, where the "set/add" just uses default settings and the "with" method lets you dig in, but only if you want to.

// using "add"
$builder->addGoodYearTires();

// using "with"
$builder->withGoodYearTires() // returns TireBuilder
    ->setFancyRims()
    ->setSnowTires();

class CarBuilder {
    public function withGoodYearTires() {
        // keep reference to builder so we can get its "product"
        // and add it to the Car we're building
        $this->_tireBuilder = new TireBuilder();
        return $this->_tireBuilder;
    }
}

PCI DSS compliance and spaghetti code, Part 2

(Be sure to read Part 1 first!)

The first iteration of my Command objects could continue to use our existing payment gateway code, but this would not be acceptable by the end of this project. This old payment gateway code relied heavily on global state to get configuration options and it executed database queries. If that were allowed the database servers which our CDE web server accessed would also be subject to audit. On top of that this code was poorly structured and lacked much of the functionality needed to complete the project.

Completely replacing a fairly large chunk of code is often a bad choice, but we had a mound of reasons for making the move.

Structuring payment gateway code

I worked on this project in parallel with one other teammate, Xiao. While I was tearing through legacy code and building command objects Xiao, wrote all of the new payment gateway code I'm about to describe. I helped him with up-front architecture consulting, code review throughout the development process, and some pieces of refactoring.

Each payment gateway we needed to support had a name-value-pair API (such as PayPal's) or an XML API (such as Authorize.net's). The data used to create each request was usually a combination of several complex objects: merchant account information, name information, addresses, "payment profile" information, etc. These objects created a Composite pattern. We used a Visitor pattern to descend into the Composite and build our final object in the format in which it would be send to the payment gateway.

This might seem counterintuitive because the structure we area creating didn't match their API structure at all. For example, an API that used name-value pairs might include an address. This address wouldn't be a separate structure that, as a whole, is part of our name-value pairs. The address parts (city, state, zip, etc) would be individually mixed up with name, credit card number, expiration date, and so on, because the name-value pair structure is completely flat.

The benefit to having a composite structure with strong typing is that it makes it impossible to make an invalid request. Each structure, like the address, has a set of fields you can define. Every place an address can be added, its specified by type. Passing an object of the wrong type causes an error instantly - do not pass GO, do not collect \$200. This kind of defensiveness seems pretty important for a system as critical as this one (one that receives money).

Continue to Part 3!

« Page 2 / 4 »