56

Typing is not a programming bottleneck

 5 years ago
source link: https://www.tuicool.com/articles/hit/U7nmq2F
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Some developers seem to think that typing is a major bottleneck while programming. It's not.

I sometimes give programming advice to people. They approach me with a software design problem, and, to the best of my ability, I suggest a remedy. Despite my best intentions, my suggestions sometimes meet resistance. One common reaction is that my suggestion isn't idiomatic , but recently, another type of criticism seems to be on the rise.

The code that I suggest is too verbose. It involves too much typing.

I'll use this article to reflect on that criticism.

The purpose of code

Before we get into the details of the issue, I'd like to start with the big picture. What's the purpose of code?

I've discussed this extensively in my Clean Coders video on Humane Code . In short, the purpose of source code is to communicate the workings of a piece of software to the next programmer who comes along. This could easily include your future self.

Perhaps you disagree with that proposition. Perhaps you think that the purpose of source code is to produce working software. It's that, too, but that's not its only purpose. If that was the only purpose, you might as well write the software in machine code.

Why do we have high-level programming languages like C#, Java, JavaScript, Ruby, Python, F#, Visual Basic, Haskell, heck - even C++?

As far as I can tell, it's because programmers are all human, and humans have limited cognitive capacity. We can't keep track of hundreds, or thousands, of global variables, or the states of dozens of complex resources. We need tools that help us structure and understand complex systems so that they're broken down into (more) manageable chunks. High-level languages help us do that.

The purpose of source code is to be understood. You read source code much more that you write. I'm not aware of any scientific studies, but I think most programmers will agree that over the lifetime of a code base, any line of code will be read orders of magnitude more often that it's edited.

How many lines of code do you produce during a productive working day?

To be honest, I can't even answer that question myself. I've never measured it, since I consider it to be irrelevant. The Mythical Man-Month gives the number as 10 , but let's be generous and pretend it's ten times that. This clearly depends on lots of factors, such as the language in which you're writing, the state of the code base, and so on. You'd tend to write more lines in a pristine greenfield code base, whereas you'll write fewer lines of code in a complicated legacy code base.

How many characters is a line of code? Let's say it's 80 characters, because that's the maximum width code ought to have. I realise that many people write wider lines, but on the other hand, most developers (fortunately) use indentation, so as a counter-weight, code often has some blank space to the left as well. This is all back-of-the-envelope calculations anyway.

When I worked in a Microsoft product group, we typically planned that a productive, 'full' day of coding was five hours. Even on productive days, the rest was used in meetings, administration, breaks, and so on.

If you write code for five hours, and produce 100 lines of code, at 80 characters per line, that's 8,000 characters. Your IDE is likely to help you with statement completion and such, but for the sake of argument, let's pretend that you have to type it all in.

8,000 characters in five hours is 1,600 characters per hour, or 27 characters per minute.

I'm not a particularly fast typist, but I can type ten times faster than that.

Typing isn't a bottleneck.

Is more code worse?

I tend to get drawn into these discussions from time to time , but good programming has little to do with how fast you can produce lines of code.

To be clear, I entirely accept that statement completion, refactoring support, and such are, in general, benign features. While I spend most of my programming time thinking and reading, I also tend to write code in bursts. The average count of lines per hour may not be great, but that's because averages smooth out the hills and the valleys of my activity.

Still, increasingly frequent objection to some of my suggestions is that what I suggest implies 'too much' code. Recently, for example, I had to defend the merits of the Fluent Builder pattern that I suggest in myDI-Friendly Library article.

As another example, consider two alternatives for modelling a restaurant reservation. First, here's a terse option:

public class Reservation
{
    public DateTimeOffset Date { get; set; }
    public string Email { get; set; }
    public string Name { get; set; }
    public int Quantity { get; set; }
    public bool IsAccepted { get; set; }
}

Here's a longer alternative:

public sealed class Reservation
{
    public Reservation(
        DateTimeOffset date,
        string name,
        string email,
        int quantity) :
        this(date, name, email, quantity, false)
    {
    }
 
    private Reservation(
        DateTimeOffset date,
        string name,
        string email,
        int quantity,
        bool isAccepted)
    {
        Date = date;
        Name = name;
        Email = email;
        Quantity = quantity;
        IsAccepted = isAccepted;
    }
 
    public DateTimeOffset Date { get; }
    public string Name { get; }
    public string Email { get; }
    public int Quantity { get; }
    public bool IsAccepted { get; }
 
    public Reservation WithDate(DateTimeOffset newDate)
    {
        return new Reservation(newDate, Name, Email, Quantity, IsAccepted);
    }
 
    public Reservation WithName(string newName)
    {
        return new Reservation(Date, newName, Email, Quantity, IsAccepted);
    }
 
    public Reservation WithEmail(string newEmail)
    {
        return new Reservation(Date, Name, newEmail, Quantity, IsAccepted);
    }
 
    public Reservation WithQuantity(int newQuantity)
    {
        return new Reservation(Date, Name, Email, newQuantity, IsAccepted);
    }
 
    public Reservation Accept()
    {
        return new Reservation(Date, Name, Email, Quantity, true);
    }
 
    public override bool Equals(object obj)
    {
        if (!(obj is Reservation other))
            return false;
 
        return Equals(Date, other.Date)
            && Equals(Name, other.Name)
            && Equals(Email, other.Email)
            && Equals(Quantity, other.Quantity)
            && Equals(IsAccepted, other.IsAccepted);
    }
 
    public override int GetHashCode()
    {
        return
            Date.GetHashCode() ^
            Name.GetHashCode() ^
            Email.GetHashCode() ^
            Quantity.GetHashCode() ^
            IsAccepted.GetHashCode();
    }
}

Which alternative is better? The short version is eight lines of code, including the curly brackets. The longer version is 78 lines of code. That's ten times as much.

I prefer the longer version. While it takes longer to type, it comes with several benefits. The main benefit is that because it's immutable, it can have structural equality. This makes it trivial to compare objects, which, for example, is something you do all the time in unit test assertions. Another benefit is that such Value Objects make better domain models . The above Reservation Value Object only shows the slightest sign of emerging domain logic in the Accept method, but once you start modelling like this, such objects seem to attract more domain behaviour.

Maintenance burden

Perhaps you're now convinced that typing speed may not be the bottleneck, but you still feel that you don't like the verbose Reservation alternative. More code could be an increased maintenance burden.

Consider those With[...] methods, such as WithName , WithQuantity , and so on. Once you make objects immutable, such copy-and-update methods become indispensable. They enable you to change a single property of an object, while keeping all other values intact:

> var r = new Reservation(DateTimeOffset.Now, "Foo", "[email protected]", 3);
> r.WithQuantity(4)
Reservation { Date=[11.09.2018 19:19:29 +02:00],
              Email="[email protected]",
              IsAccepted=false,
              Name="Foo",
              Quantity=4 }

While convenient, such methods can increase the maintenance burden. If you realise that you need to change the name of one of the properties, you'll have to remember to also change the name of the copy-and-update method. For example, if you change Quantity to NumberOfGuests , you'll have to also remember to rename WithQuantity to WithNumberOfGuests .

I'm not sure that I'm ready to concede that this is a prohibitive strain on the sustainability of a code base, but I do grant that it's a nuisance. This is one of the many reasons that I prefer to use programming languages better equipped for such domain modelling. In F# , for example, a record type similar to the above immutable Reservation class would be a one-liner:

type Reservation =
    { Date : DateTimeOffset; Name : string; Email : string; Quantity : int; IsAccepted : bool }

Such a declarative approach to types produces an immutable record with the same capabilities as the 78 lines of C# code.

That's a different story, though. There's little correlation between the size of code, and how 'good' it is. Sometimes, less code is better; sometimes, more code is better.

I'll dispense with the usual Edsger Dijkstra and Bill Gates quotes on lines of code. The point that lines of code is a useless metric in software development has been made already. My point is a corollary. Apparently, it has to be explicitly stated: Programmer productivity has nothing to do with typing speed.

Unless you're disabled in some way, you can type fast enough to be a productive programmer. Typing isn't a programming bottleneck.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK