Grokking Simplicity cover
welcome to this free extract from
an online version of the Manning book.
to read more
or

foreword

published book

Guy Steele

I’ve been writing programs for over 52 years now. I still find it exciting, because there are always new problems to tackle and new things to learn. My programming style has changed quite a bit over the decades, as I learn new algorithms, new programming languages, and new techniques for organizing my code.

When I first learned to program, in the 1960s, a well-accepted methodology was to draw a flowchart for the program before writing actual code. Every computation was represented by a rectangular box, every decision by a diamond, and every input/output operation by some other shape. The boxes were connected by arrows representing the flow of control from one box to another. Then writing the program was just a matter of writing code for the contents of each box in some order, and whenever an arrow pointed anywhere but the next box you were about to code, you would write a goto statement to indicate the necessary transfer of control. The problem was that flowcharts were two-dimensional but code was one-dimensional, so even if the structure of a flowchart looked nice and neat on paper, it could be hard to understand when written out as code. If you drew arrows on your code from each goto statement to its destination, the result often resembled a mound of spaghetti, and in those days we indeed talked about the difficulties of understanding and maintaining “spaghetti code.”

The first big influence on my programming style was the “structured programming” movement of the early 1970s. Looking back, I see two big ideas that came out of that community-wide discussion. Both of them are techniques for organizing control flow. The idea, which became famous, was that most control flow could be expressed in terms of a few simple patterns: sequential execution, multiway decisions such as if-then else and switch statements, and repetitive execution such as while loops and for loops. This was sometimes oversimplified into the slogan “No goto statements!”—but the important thing was the patterns, and if you used the patterns consistently you found that you rarely needed to use an actual goto statement. The second idea, less famous but no less important, was that sequential statements could be grouped into blocks that should be properly nested, and that a non-local transfer of control may jump to the end of a block or out of a block (think of break and continue) but should not jump into a block from outside.

When I first learned the ideas of structured programming, I did not have access to a structured programming language. But I found myself writing my Fortran code a little more carefully, organizing it according to the principles of structured programming. I even found myself writing low-level assembly language code as if I were a compiler translating from a structured programming language into machine instructions. I found that this discipline made my programs easier to write and to maintain. Yes, I was still writing goto statements or branch instructions, but almost always according to one of the standard patterns, and that made it much easier to see what was going on.

In the bad old days when I wrote Fortran code, all the variables needed in a program were declared right up front, all together in one place, followed by the executable code. (The COBOL language rigidly formalized this specific organization; variables were declared in the “data division” of a program, which began with the actual words “DATA DIVISION.” This was then followed by the code, which always began with the actual words “PROCEDURE DIVISION.”) Every variable could be referred to from any point in the code. That made it hard to figure out, for any specific variable, exactly how it might be accessed and modified.

The second big influence that changed my programming style was “object-oriented programming,” which for me encompasses a combination and culmination of early ideas about objects, classes, “information hiding,” and “abstract data types.” Again, looking back I see two big ideas that came out of this grand synthesis, and both have to do with organizing access to data. The first idea is that variables should be “encapsulated” or “contained” in some way, to make it easier to see that only certain parts of the code can read or write them. This can be as simple as declaring local variables within a block rather than at the top of the program, or as elaborate as declaring variables within a class (or module) so that only methods of that class (or procedures within the module) can access them. Classes or modules can be used to guarantee that sets of variables obey certain consistency properties, because methods or procedures can be coded to ensure that if one variable is updated, then related variables are also appropriately updated. The second idea is inheritance, meaning that one can define a more complicated object by extending simpler ones, adding new variables and methods, and perhaps overriding existing methods. This second idea is made possible because of the first one.

At the time that I learned about objects and abstract data types, I was writing a lot of Lisp code, and while Lisp itself is not a purely object-oriented language, it is pretty easy to use Lisp to implement data structures and to access those data structures only through approved methods (implemented as Lisp functions). If I paid attention to organizing my data, I got many of the benefits of object-oriented programming, even though I was coding in a language that did not enforce that discipline.

The third big influence on my programming style was “functional programming,” which is sometimes oversimplified into the slogan “No side effects!” But this is not realistic. Understood properly, functional programming provides techniques for organizing side effects so that they don’t occur just anywhereand that is the subject of this book.

Once again, there are actually two big ideas that work together. The first big idea is to distinguish computations, which have no effect on the outside world and produce the same result even when executed multiple times, from actions, which may produce different results each time they are executed and may have some side effect on the outside world, such as displaying text on a screen, or launching a rocket. A program is easier to understand if organized into standard patterns that make it easier to figure out which parts might have side effects and which parts are “merely computations.” The standard patterns may be divided into two subcategories: those typically used in single-threaded programs (sequential execution) and those typically used in multi-threaded programs (parallel execution).

The second big idea is a set of techniques for processing collections of data—arrays, lists, databases—“all at once” rather than item by item. These techniques are most effective when the items can be processed independently, free of side effects and their influence, so once again the second idea works better thanks to the first idea.

In 1995 I helped to write the first full specification for the Java programming language; the next year I helped to write the first standard for JavaScript (the ECMAScript standard). Both these languages were clearly object-oriented; indeed, in Java there is no such thing as a global variable—every variable must be declared within some class or method. And both those languages have no goto statement; the language designers concluded that the structured programming movement had succeeded, and goto was no longer needed. Nowadays millions of programmers get along just fine without goto statements and global variables.

But what about functional programming? There are some purely functional languages such as Haskell that are widely used. You can use Haskell to display text on a screen, or to launch a rocket, but the use of side effects within Haskell is subject to a very strict discipline. One consequence is that you can’t just drop a print statement anywhere you want in the middle of a Haskell program to see what’s going on.

On the other hand, Java, JavaScript, C++, Python, and so many others are not purely functional languages, but have adopted ideas from functional programming that make them much easier to use. And this is the punchline: once you understand the key principles for organizing side effects, these simple ideas can be used in any programming language. This book, Grokking Simplicity, shows you how to do that. It may seem long, but it’s an easy read, filled with practical examples and sidebars that explain the technical terms. I was drawn in, really enjoyed it, and learned a couple of new ideas that I am eager to apply in my own code. I hope you enjoy it, too!

Jessica Kerr

Jessitron, LLC

When I first learned programming, I loved it for its predictability. Each of my programs was simple: it was small, it ran on one machine, and it was easy for one person (me) to use. Loving software development is something different. Software is not small. It is not written by one person. It runs on many machines, in many processes. It accommodates different people, including people who don’t care how the software works.

Useful software doesn’t get to be simple.

What’s a programmer to do?

For sixty years, the techniques of functional programming have grown in the minds of computer scientists. Researchers like to make positive statements about what can never happen.

This last decade or two, developers have been adopting these techniques in business software. This is good timing, because it corresponds with the dominance of web applications: every app is a distributed system, downloaded to unknown computers, clicked on by unknown people. Functional programming is well suited. Whole categories of hard-to-find bugs can never happen.

But functional programming does not transfer peacefully from academia to business software. We are not using Haskell. We aren’t starting from scratch. We depend on runtimes and libraries outside our control. Our software interacts with many other systems; it is not enough to output an answer. It is a long way from FP-land to legacy business software.

Eric has undertaken this journey for us. He delved into functional programming, found its most helpful essences, and brought them to us where we are.

Gone are the strict typing, the “pure” languages, the category theory. Here instead we notice the code that interacts with the world, choose to leave data unchanged, and break code apart for better clarity. Instead of high-minded abstractions, here are degrees and levels of abstraction. Instead of eschewing state, here are ways to safely keep state.

Eric offers new ways to perceive our existing code. New diagrams, new smells, new heuristics. Yes, this came out of a journey into functional programming—yet, when he makes his ways of thinking explicit so that we can use them too, he creates something new. Something that will help all of us with our creations.

My simple programs were not useful to the world. Our useful software will never be simple. But we can make more of our code simpler than it was. And we can manage those crucial bits that interact with the world. Eric unwinds these contradictions for us.

This book will make you better at programming—and more, at software development.

sitemap

Unable to load book!

The book could not be loaded.

(try again in a couple of minutes)

manning.com homepage