Peanut Butter is Real Programming
Steven Lipton
CIO Scientific Device Laboratory, Author and Speaker on creativity, iOS, watchOS, and SAP Business One
If you think programming is a job like any other, I’d like to offer you a peanut butter sandwich. I’m not going to give you one, but something as seemingly simple as a peanut butter and jelly sandwich when looked at from the view of an IT project may blow your mind. Application development and Information Technology is a mindset more than a skill. I've never come up with a good way to describe what I do and the challenges of this profession before, until very recently.
In the comments for another article I wrote, someone referred me to a extremely funny YouTube video about exactly this, though it would not seem it at first.
If you don’t have time to watch, the story is this: a dad asks his the kids to write the directions for a peanut butter and jelly sandwich. For each set of instructions he gets, the dad explicitly follows their directions. Hilarity and failure ensues as the kids see what happens to their directions, which fail to be explicit. According to the comments on the video this is an exercise from a Harvard Computer Science class, but it intrigued me how far the analogy worked beyond coding a sandwich.
Coding
If you tried to do the exercise of writing down a peanut butter sandwich like the kids you'd might start like this:
Get bread bag
Open bread bag
For 2 times
Remove bread slice
If plate has a bread slice,
move 1 bread width next to current bread
Place bread slice on plate
Get peanut butter jar
Open peanut butter jar.
Get Knife
Grab from handle
Move to work area
Spread Peanut butter
Place knife blade down into open peanut butter jar
Move knife forward and up
Remove knife from jar
Move knife over bread
Rotate knife with peanut butter side down
Put knife to bread.
Move on bread
Remove knife from bread.
I'll stop there. You'd then go through the process of getting the jelly on and then placing the two pieces of bread together, but you get the idea. If you’ve watched the video, you know that the steps above will fail. You'd need to to be extremely detailed to get a workable solution, and this still isn’t detailed enough. Of course that’s what a coder or programmer would need to do -- make the most explicit description possible. Any ambiguity will lead to failure - Almost.
That’s the coding everyone talks about. You must be very explicit. Not only do you need to be explicit, you need to use the proper language to describe things. For the sandwich we have English to describe the process, which has too many ways to describe the ingredients and tools to be useful. In application development these are programming languages. Different environments use different languages, but all limit descriptions to useful information. Sometimes a choice of language is a matter of preference, sometimes platforms require a language. They can look and act very different from one another for the same action. For example, these four code snippets compute the number 8 and place it in storage, in five different languages.
const int a = (2+4)-7+3*3;
SELECT (2+4)-7+(3*3) as ‘a’
let a = (2+4)-7+(3*3)
2 4 + 7 - 3 dup * +
Even when we want them to have the same meaning, just as in natural languages, they cannot be identical. The last snippet can change values, while the first and second will remain constants. The third is actually two languages. Depending on the language, the result is different. In Swift the result is a constant, in BASIC a variable.
Knowing only one of these gives you only one way of looking at the computations. Knowing all five gets deeper into what is going on with the computations, at very different speeds. Knowing all five gives you the power to work on several different platforms and write a home controller with C++ in the the first or create a Profit and Loss statement with SQL in the second. With the third, your can write an Excel Macro as BASIC or an iPhone app in Swift. The fourth, which is FORTH, controls Boeing 777 aircraft wings and the Cassini space probe. While each could be used for the other’s application, a language works best as the tool for its own job. Most developers know more than one language, and know the differences in coding each.
All of these languages require explicit instructions. They also remove us from many of the tiny mundane operations to get there. We can imagine a language which works best with food and food functions that makes the sandwich easier to make. It has a series of functions that are commands in English
let get spread cut
open heat cool add
layer mix putBack close
flip squeeze pour
There may be more, but we’ll stick with those for now. I’ll also have a few words to modify those functions and some math operators:
from with as on
by if else begin
end + / -
* constructor object
I can write my sandwich like this:
get breadBag from Cupboard as BreadBag with kind white
get peanutButterJar from Cupboard as PBJar with brand dippy
open peanutButterJar
open breadBag
get breadSlice1 from breadBag as BreadSlice
layer breadSlice1 on Counter
get breadSlice2 from breadBag as BreadSlice
layer breadSlice2 on Counter
get knife from drawer as Knife
get peanutButter from peanutButterJar with knife
spread peanutButter on breadSlice1 with knife
clean knife
get jelly from Cupboard as JellyTube with flavor strawberry
open jelly
squeeze jelly on breadSlice2
layer breadSlice2 on breadSlice1 by flip
This code describes making a sandwich. All of the details of how to put a knife in a jar correctly and get our peanut butter are no longer our problem: the languages has a set of instructions on how to deal with that. Most computer languages are like this code above. The details are hidden from the developer, letting the developers get to the problem they are trying to solve.
One way of hiding those details is to create objects. BreadBag, BreadSlice, Cupboard, Knife, PBJar and JellyTube are all objects. Each object has its own way of doing things hidden in the code for the object, often referred to as methods. Each object also has properties, the bread has a kind, the Peanut butter jar has a brand and the jelly a flavor.
Notice I got the bread and peanut butter first and the jelly much later. I could have gotten all the ingredients at the same time and gotten them ready. This brings up an important part of programming: there is never one solution. Programmer preferences, user requirements, efficiency in code, scalability and style might make decisions that give the same results, but with different code.
Sometimes, those decisions are user or management mandated, such as cutting a sandwich into triangles or rectangles. You may have someone who only eats a sandwich cut into triangles. This is why program requirements are so important in a planning stage. It informs the programmers the best way to do something.
Hacks
Speaking of cutting, we have a problem. How do you cut the sandwich in half? In the code above I can’t do this
cut pbSandwich with knife at pbSandwich with width / 2
because I have no object named pbSandwich. I can't just cut one piece of bread, or can I? I could try
cut breadSlice2 with knife at breadSlice2 with width / 2
Won’t cut my sandwich completely, but this might.
cut breadSlice1 with knife at breadSlice1 with width / 2
Because the breadSlice1 is the bottom slice, the knife has to go through the top slice, cutting both.
This is an example of a hack. While the word hack has gained popularity as something good and constructive, they are very, very bad things in programming. Hacks are shortcuts taken in code that break the rules of style, make it difficult to communicate the code, and very often rely on system functions that may not always be true.
The knife object ignores it is cutting the second bread slice, but it could also complain with a fatal error, the computer equivalent of a temper tantrum. It could complain that the breadSlice2 is in the way and it wont cut.
If I told you to cut the bottom slice, wouldn't you have a bit of a brain lock? That’s the problem with hacks. They are extremely unreliable in every way, and should be avoided. However they do make it into code, and that’s been known to cause lots of problems.
User Functions and Objects
If we don’t use the hack, what could we do? We could make a new object called PBSandwich, then cut a PBSandwich. A PBSandwich would have a special method called a constructor which would make the sandwich. This object would also have properties: the kind of bread we use, the jelly flavor and the peanut butter brand. I can define the object and the properties in the object like this:
object PBSandwich begin
let jellyFlavor be strawberry as JellyFlavor
let pbBrand be dippy as PBBrand
let breadKind be white as BreadKind
object end
I used default values for these properties, and told the system that they were objects of JellyFlavor, PBBrand and BreadKind. Any sandwich made with the PBSandwich object will be a Sandwich on white bread with dippy peanut butter and strawberry jelly.
I add the constructor to the object to make the sandwich, giving us our final code
object PBSandwich begin
let jellyFlavor be strawberry as JellyFlavor
let pbBrand be dippy as PBBrand
let breadKind be white as BreadKind
constructor begin
get breadBag from Cupboard as BreadBag with kind breadKind
get peanutButterJar from Cupboard as PBJar with brand pbBrand
open peanutButterJar
open breadBag
get breadSlice1 from breadBag as BreadSlice
layer breadSlice1 on Counter
get breadSlice2 from breadBag as BreadSlice
layer breadSlice2 on Counter
get knife from drawer as Knife
get peanutButter from peanutButterJar with knife
spread peanutButter on breadSlice1 with knife
get jelly from Cupboard as JellyTube with flavor jellyFlavor
open jelly
squeeze jelly on breadSlice2
layer breadSlice2 on breadSlice1 by flip
constructor end
object end
Now I can make and cut my sandwich like this
get pbSandwich as PBSandwich
cut pbSandwich with knife at pbsandwich with width / 2
This tells the system to cut the sandwich at hand the width of the sandwich, except…the system has no idea what the width of a sandwich is, and crashes. I can get the width of a sandwich from the width of a slice of bread. There is a width property in the BreadSlice object, so I can get the width of the slice of bread, but which slice? Do I use slice 1 or 2? Do I use the bigger slice? Do I average the slices? As a developer I have to make a decision. I’ll add another property
let width be 0 as Size
I’ll go with the bigger slice solution. I'll add some code if one bread slice is bigger than the other, set the width to the bigger slice.
if breadSlice1 with width greaterThan breadSlice2 with width begin
width from breadSlice1 with width
else
width from breadSlice2 with width
if end
Now this code will work:
get pbSandwich as PBSandwich
cut pbSandwich with knife at pbSandwich with width / 2
And Yaaay!!! were done, You’ve coded a sandwich. Well… not quite.
User Requirements
You deliver your sandwich and your user starts crying up a storm. He wanted wheat bread, strawberry jam and cut diagonally. Your code does not easily do that, and since you didn't ask up front, you have to not only make a new sandwich but change the code.
There’s two more strategies that developer needs to do. The first is ask for specific directions. Usually that conversation goes like this:
You: What do you want in your sandwich?
User: I don’t know.
You try again, limiting the choices:
You: Do you want raspberry or strawberry jelly on your sandwich?
User: I don’t know.
With your patience waning, You try one more time.
You: Do you want raspberry or Strawberry jelly on your sandwich?
User: I don’t know. What Kelly is having.
Kelly is the user down the block who happens to be The User’s friend. You can do the research to get what Kelly is having or you can go to guessing since the user seems not to care about what’s in the sandwich, then wait for the complaints to come in and change the sandwich.
Either way, there's something you should do: change the code so any sandwich can be made with any type of jelly, bread and peanut butter. The first line of the constructor would look like this:
constructor with jellyFlavor pbBrand breadKind begin
This code changes contains arguments that change the properties when you make a sandwich. Now you can make a sandwich with any combination of ingredients.
get pbSandwich as PBSandwich with raspberry spiffyChunk wheat
cut pbSandwich with knife at pbSandwich with width / 2 rotate 45.0
That makes changing requirements from the user very easy.
Debugging
If you run our sandwich application once, it will work. Many coders stop here and say their job is done. Run twice and results get strange. You might get that sandwich. You might get no sandwich. You might get two slices of bread. You might get errors like this
warning: cupboard found empty
fatal: cupboard found empty
This is a bug, an error in our program. I have jars and bread, so how can the cupboard be found empty? Ask a different question: How does the system handle jars once they have been used? Does the system close and put away jars? Does it leave them on the counter? Are there infinite jars in the cupboard? Are there two containers of some foods and one of others? You as a developer would need to know that, since behavior from the application might be different depending on the answers to those questions. There’s one more question: does those answers depend on whose house you make the sandwich?
The bug is that once jars are used, they are left open on the counter, making it impossible for the system to grab them out of the cupboard. Finding that bug would require tracing the process and finding the false assumption about where the jars are. There might be different ways to handle that error or to interpret the code based on the error. Depending on the directions in the objects, you might have different behaviors for get in the objects we're using. The bread slice might ignore the lack of of a bread bag in the cupboard, and just get the bread if the bag is on the table. The peanut butter might complain about the lack of a jar in the cupboard with a warning and do nothing, and the jelly complains so much it shuts down the whole application with a fatal error.
You as a developer need to come up with a solution. I said you might have different behaviors in different houses. Some kitchens might have some system that puts everything away when done, some don’t. Some will give an error message when it does clean up:
warning: Why can’t you clean up? It brings bugs!!!!
Often its best to just put everything away your self. You code to close the jars, tubes and bags, then place them back into the cupboard.
close breadBag
putBack breadBag
close jelly
putBack jelly
close peanutButterJar
putBack peanutButterJar
Running Out of Jelly
This solves one bug, but after using your program for a while you’ll get strange results again: your jelly is empty. Is there another tube in the cupboard? Do you have to stop the program and crash or do you pause and get more jelly? Or do you jump over that one step and complete the others while getting the jelly?
There’s lots of solutions to this problem. One solution is to check the supplies of jelly at the beginning of the operation. If you have a low amount, check if you have another tube. If there is not another tube, start another program, let’s call it TeenWithCar that goes to get the extra tube. If the tube is empty, dispose of the first tube and use the new tube. There’s still some problems to solve with this solution.
System Resource Changes
TeenWithCar comes back with a jar instead of a tube of raspberry jam. Our whole application depends on using a tube of jelly and not a jar. The app crashes since this is not a jar.
fatal: type ‘JamJar’ is not type ‘JellyTube’
You have to recode for this and use a jar. You might add logic to check if it is a jar or tube so this doesn't happen again.
System Problems
Timing is everything. Remember this step:
layer breadSlice2 on breadSlice1 by flip
Flips the bread so the jelly side is down. That assumes the the bread flip is fast enough to keep the jelly on the bread. If too slow it slips off. How do you deal with slow flips?
Similarly, if the TeenWithCar fails to get the jelly or jam back to the cupboard fast enough and you make several sandwiches, you might still run out of jelly. It might not be TeenWithCar’s fault: traffic might be heavy or the grocery store is very busy.
The timing scale of making a sandwich may not be the same time scale as some other operations, like getting extra supplies. The sandwich takes five minutes while it may take an hour to get extra jam from the store. How does that affect the program, and how do you get things moving smoothly and seamlessly?
The Point of All This
For most people who have been in IT or application development, you’ve figured out I described just the tip of the iceberg of issues we deal with when developing applications. Coding a peanut butter sandwich is hard, but that's only one step in the process. Getting program requirements, planning, coding, debugging, documenting, maintaining, and supporting are all steps. If you’ve never programmed before or just started coding, this is what professional programmers live with — lots of problems, problems which do not go away, require constant changes, and will always leave someone screaming at you and your work. It’s not uncommon for the same compilers on two different operating systems to act differently, nor is it uncommon for hardware sensors, server and Internet resources to take far too long to get data back to the application. Different versions of languages handle closing or putting things away differently. Users and management have no idea what they want as an application, and cannot tell you. Users will find ways to crash or corrupt the system you never dreamed of — then scream at you about it. The compiler developers change the language on you, some like Apple’s Swift do it once or twice a month, changing jars and tubes almost randomly, then totally mess everything up every June with a new version for chocolate hazelnut spread and bananas. For those in database programming, one day your database looks one way, a month later it loses two fields and gains three. This is the day to day existence of developers, programmers, and the IT people who have to maintain all this.
The real issues in computing is not knowing one language to code. It answers a lot more critical questions. How do computer languages work and work differently from each other? How do systems move data from one place to another? How do users interact with systems and what do users really want? How do you scale a function efficiently? Just knowing Java, Swift or SQL is not enough. I’ve read those ultra hard quizzes asking about obscure features of some language given during interviews. If I was ever given one of those on a job interview, I 'd probably ask for the docs. If I could't look up the answers, I'd leave the interview. First of all I’m guaranteed to fail the test — I let my documentation library keep all that organized for me. I look any of those questions up, then prototype to understand it and make sure it works. Secondly, that’s the sign of a bad shop for me, one likely to fire me at the next compiler update for being obsolete or one that has no clue what the real talents are of developers. If someone would give me a thought experiment like this one, to develop a compiler specification for making peanut butter sandwiches*, I’d stay and be intrigued at the position.
Programming is some of the hardest problem solving there is. Programming's rigorous removal and prevention of bugs has bled into other industries: Much of quality control and lean iteration methods come from programming. Systems with very strict quality standards like medical devices or aerospace adopted many of the tools we use to prevent or eliminate bugs. While other industries can take or leave the intensity of the problem solving, programming must do it for every social media app, game, financial report, dashboard and medical device controller.
This brings me back to the core theme I’ve been trying to get across over the last few weeks in my posts. Problem solving needs a huge knowledge base, one that requires one to always be learning, and learning skills for continuous learning. Knowing how to look up answers in documentation, and being able to read the documentation is a key skill. Being able to prototype, to play, with code to understand and learn how functions really work after looking at a documentation reference is another skill. Being ready to change and learn at any second, and being able to look at the same problems from many different angles is important. How much of our culture and workforce have the ability? I champion teaching programming skills in school, because those skills no matter what one does will be beneficial. I am a big advocate of apprenticeships, since many skills seem to be badly taught or cannot be taught in classrooms, and the environment where they are used in context facilitates learning. I don't think most people are cut out to be programmers. It requires intense brain power. You really have to enjoy that intensity of thinking in a way littered with problems if you are going to be good at it. When you are not thinking, you are learning. Who really wants to do that?
Think about that when making your next peanut butter sandwich.
Steve Lipton is the mind behind makeapppie.com for learning iOS programming. Besides Chief Information Officer at Scientific Device Laboratory, he is the author of several books on iOS programming and development. He is also a LinkedIn Learning author. His latest courses are SAP Business One Essential Training and iOS and watchOS Development:Notifications. He also is the author and host of iOS Development Tips Weekly.
#AlwaysBeLearning
*I want to put a comment for all those compiler developers out there. This theoretical language gives me shivers thinking of how to write the compiler. That constructor would be a nightmare by itself with the implicit initialization of properties, and the with modifier signifying a parameter list just gives me a headache to think about parsing nested functions in parameters. My point was explaining computer languages without getting into the issues of one that already exists for the uninitiated. In an interview, based on my first question “who will be using this language?” I would write it very differently. I based it on people who would not know some of the C-based conventions like semicolons, curly braces for blocks, parameters/arguments in parentheses and dot notation that permeate most modern languages and scripts. If the answer was conventional programmers, this would have those symbols and probably would look a lot like Swift, Java or C++. As it is, its a bad combination of a strongly typed older language like a reverse Objective-C, with some LISP, Pascal, and hints of COBOL. I was seriously thinking of adding DIVISIONs like COBOL, but I don't believe in cruel and unusual punishment, and it did nothing to prove my point.
Founder & CEO at Keyideas
7 年As technology advances, many simpler languages have come into place such as Swift instead of Object C for iOS. These languages are simpler but mind it they are simpler in comparison only. Developers whether be an app or a website, the demanding future always has something new in the kitty. It's only the urge to take up new challenges and deliver more future-ready products that keep developers going on & on!
Senior Electronics Engineer at Chess Dynamics
7 年Excellent read: I remember doing the same sort of thing when teaching (I was the 'robot' - they had to control me to walk across the room). I managed to avoid serious injury by complaining the instruction was invalid on quite a few occasions. Seriously, the same skills are just as necessary for just about all design work.
Problem solver
7 年Awesome article showing non software developers why they have to be specific enough in order to make software developers life not a burdensome. This article shows all the struggle software developers have while developing starting from the lack of requirements specification with it's pitfalls and ending in all the assumings users have that the software developers should know about.
Principal Tech Lead / Architect ?Quality driven ?Business focused ?Divemaster ?.Net/C# ?Azure/AWS ?MongoDB/SQL ?REST API
7 年Good article.. it's a really interesting way to explain what we as coders do everyday to none tech friends.