Learning by Doing

The Wrong Way

When I learned to code, I thought I was learning the wrong way. The 1980s were the Bronze Age of the personal computer with the Apple II, Commodore 64, Atari 800, and the TRS-80 competing for mind and market share. I had gotten it into my head that every home, school, and office would soon have a PC dutifully managing info and automating tasks like the faithful robots that Isaac Asimov had written about. I felt desperate in my need to understand the inner workings of these heralds of the digital age.

Since I was a cash-strapped college student all I could afford was the deeply discounted and distinctly weird TI-99/4A. I bought the Texas Instruments home computer because its specs were impressive (16-Bit CPU) and it cost about 100 bucks. The TI did not set the world on fire. There was very little commercial software. If I wanted to do more than play a few cartridge-based games and I would need to write my own programs.

There was a very vibrant computer hobbyist magazine market in the 80s. My favorite magazine was COMPUTE! Every issue was chock full of news, speculation, and tutorials for each of the major PC systems. I read COMPUTE! from cover to cover and typed in every TI BASIC program printed each month. Since the TI was far from popular there were few articles devoted to its flavor of BASIC. A few days after I devoured a new issue of COMPUTE! I ran out of things to do with my TI.

Trial and Error

Out of desperation and desire I did something unthinkable! I attempted to adopt the Apple, Commodore, Atari, and TRS programs for the lowly TI. At first my efforts simply failed. The BASIC programming language that all these systems shared was broadly similar, but the display, sound, and file sub systems were very different. I learned, the hard way, that what we might call backend programs today were far more portable than frontend programs. The calculation code of a financial calculator could easily be written in a kind of “universal BASIC” while the charting code had to be redesigned entirely. (We have this problem day! It’s why iOS and Android apps have to be different codebases.)  

I was learning, through trial and error, some of the basic principles of software engineering. Insights that I use in the current Golden Age of cloud computing and internet connected devices. I don’t believe I would have retained, or even truly understood, these principles if I had not attempted to “just do it.” An important part of my learning experience is that I had no idea if I would succeed. It was pure R&D.

Learning by Doing Principles

Here’s what I’ve found to be the important elements of learning by doing (from someone who is learning by doing it).

  1. Limited access to expertise: If we have a lifeline, we’re going to use it. Don’t use it. Don’t Google that error message or look for the answer on Stack Overflow. Just bang your head against the wall until something shakes loose.
  2. Unlimited access to examples: This is what is truly great about open source. We have so many examples of working code. These examples might not directly solve the problem at hand, but they provide hints and inspiration.
  3. Unlimited time: For work and play its best to timebox all our activities lest we miss deadlines or overindulge. But for learning it best to take all the time we need. Learning by doing is exploratory and self-driven. If we rush it, we risk completing the project but not the learning.
  4. Simple systems: The TI-99/4A had a single CPU that executed code slowly, in 16KB of RAM, and plotted graphics on a 256×192 bitmap. There wasn’t much there to distract the learner from her self-appointed task. Lucky for us, every UNIX-based computer has a terminal app that transforms your modern supercomputer into something like a 1980’s home computer. We can even install BASIC! (Well, don’t go that far, Python or JavaScript are fine for learning to code projects.)

The Right Way

In hindsight I realize that my mix of limited resources and unlimited time were a big part of my learning succuss. I had to improvise. I had to stretch and grow. I could not Google or Stack Overflow the answers.  

Don’t take my word for it! Learning by doing (project-based learning) is a pedagogical approved alternative to teacher-led instruction. It also looks a lot like a good Agile development process! At Apple we used to say, “you don’t really know how to write code until after you have written it.” This is why the 2nd  and 3rd  generations of every software system are big improvements. It’s not the new features, it’s the lessons learned by doing that lead to safer, faster, and reliable software.

The Only Way

The core lesson I’ve learned by writing code for 30 years is that we’re still figuring it out. While we have amassed a considerable amount of knowledge the pace of technological change continuously challenges that knowledge. When it comes to coding learning by doing isn’t the wrong way – it’s the only way.


Learning from First Principles

A Troublesome Student

I was a poor student in elementary school. I was unable to focus for more than a few minutes at a time. Bored and restless I treated the classroom as a kind of one-man show to entertain myself and earn the admiration of my peers. I remember bringing our family’s fancy silverware to school one morning in 4th grade. During math class I distributed the cutlery to each student at each desk as if we were about to enjoy a meal. But there was no meal and my mother and teachers were not amused.

In this day and age, I would have been diagnosed with a “learning problem.” Most likely Attention Deficit Disorder, the infamous ADD, and perhaps medicated. Luckily, I grew up in the dark ages of the late 1960s. The diagnosis was “troublemaker” and the solution was a desk in the hallway outside of the classroom. I was given only math worksheets and a pencil for entertainment. The educational system had given up on me.

Sitting alone and isolated was one of the best things that ever happened to me as a child.

With no audience and no windows in which to daydream I opened the workbook to page one and started doing math problems. There was nothing else to do and no instructor to rebel against. 

It was slow going at first but by the end of the month I was in love with math and several chapters ahead of the class. I moved up and out from 4th grade into 5th grade math. I was rehabilitated into the inside of the classroom. Eventually, I even started to pay attention to the math teachers. 

I had learned 4th grade math from first principles.

I should note that I’m not a great mathematician. Because of my loner learning style, I don’t do math like classroom-trained people do. For example, I never bothered to memorize my times tables. Instead I write out a table of three number lines, natural, even, and odd. I can then derive any integer product, dividend, or remainder by lookup and simple arithmetic. I had created a tool to avoid route memorization.

More importantly this was my rough introduction into learning how to learn.

Learning without Guidance

Learning from first principles means learning without a guide and building up from what you already know. The most famous example of first principles are the Elements of Euclid. I’m sure you’ve heard of this ancient Greek geometer. He started with a small set of fundamental observations about the behavior of points and lines on a plane and derived hundreds of conclusions that formed the basis of geometry as we practice it today. 

During the early part of my career we had to be a bit like Euclid to figure out how to develop software, deliver applications, and build teams from first principles. Back in the 1980s and 1990s we didn’t have best practices and opinionated programming languages. We had to solve problems with code without guidance.

At Apple we did object-oriented programming before there were object-oriented programming languages. We learned from first principles that function pointers and pointers to pointers (handles) could be used to encapsulate properties and methods into objects. We didn’t invent C++ or Objective-C but when these advances came around, they felt like old friends.

At DoubleClick in the 2000s we did cloud computing without containers or virtual machines. We learned from first principles how to configure hardware and software, so that every server was an exact clone. This enabled ad serving workloads to be automatically propagated through our network so that our QoS was easily maintained in the face of failures. We didn’t invent AWS but when Amazon started marketing their excess capacity, we had a similar business plan on the table. 

The power of learning from first principles is that it empowers you to figure out the future on your own with the tools you have at hand. The best practices and opinionated programming languages if today are the first principle hacks of yesterday.

A Short Guide to Guideless Learning

So, how does one learn this way? How does one start down the path of first principles?

It starts with observation.  Start like Euclid did with a set of simple, self-evident facts that a non-expert can understand. Euclid did this by observing how two points and lines interact to create angles and shapes on a flat surface.  

It helps, in my opinion, to be a non-expert in order to make these observations. I fight hard to ignore what I “know” so I can see what is really going on.

Restrict your observations to the abstract. Euclid only recorded observations are universal regardless of the environment. He focused on how points and lines interact on an ideal surface. Euclid didn’t get caught up in specific details.

Abstraction is a superpower all of us share. Abstraction is the ability to discount the non-essential and to focus on the properties that are shared by seemingly unique entities. It’s been helpful to me to think about effects — not causes — when I’m thinking abstractly.

Build up a foundation of true definitions. Euclid recorded his observations as a handful of definitions upon which he built the empire of two-dimensional geometry. These definitions were Euclid’s building blocks in the same way that the definitions of legal terms build up a contract or the line items of expenses and credits build up a budget.

I find it helpful to record each observation about the system I’m studying on an index card. These cards become my working dictionary for the problem space. As a bonus index card are cheap, easy to order and reorder, and restrict my verbosity.

Apply simple logic to the definitions to make predictions. Euclid used his definitions to build up hundreds of propositions. These propositions were not simple and not obvious, and yet he derived them simply and obviously. When Euclid was done, he could predict the number of degrees in an angle, the length of lines, and the diameter of circles.

It helps to express predictions in diagrams and to show how the logic works in with arrows and annotation. I used to start with the diagram. But if the underlying observations, abstractions, and definitions are not rigorous then the diagram is worthless. I’ve seen these worthless diagrams on whiteboards and in business docs during my entire career.

Be a Lazy 9-Year-Old

The lazy 9-year-old version of me accidently discovered learning from first principles out of a fascination with patterns and a lack of fascination with listening to others. I’ve matured and now deeply value what others, even elementary school math teachers, have to say.

A great place to discover learning from first principles is in the classroom. The student has to be receptive. The teacher has to be empowered. Parents have to be patient. Society has to be supportive.

I still use learning from first principles to this day. It’s how I figure out how to deliver more value with less budget or scale software development with hundreds of engineers. In full disclosure I do read and value all the books and blog post on best practices and prior experiences. But I view this prior art as theory and not law. There is still a lazy 9-year-old deep inside me who isn’t content with being told. I need to find out how things work for myself.


Success Means Learning

Much of my success in life I attribute not to the fortunes or misfortunes of my birth (genetics, socioeconomics) but to my ability to learn and act on what I’ve learned.

I could be totally wrong. As an experiment of one all my success could be due to luck and happenstance. I have learned that all-or-nothing explanations tend to be wrong. It’s unlikely that any answer to any complex question is due to a single factor. There is almost always a collaborator lurking in the background!

In the case of learning I have found that the ability to continuously learn is much more important to living in the 20th and 21st centuries than other highly desirable abilities. A good general learner is better able to handle change, surprise, and ambiguity than the expert or the specialist. This is my personal experience of personal growth and of managing hundreds of software engineers and managers over the last 30 years.

Here is a trivial example:

  • JP is an okay coder. Not brilliant but able to reliably get the job done with help from co-workers and stack overflow. 
  • PJ is an excellent coder. Brilliant but only really into one programming paradigm. 
  • JP has no strong opinions and thus their work is all over the place in terms of coding style and techniques.
  • PJ has many very strong opinions on “best practices” and thus their code is clear, concise, and predictable.
  • It is interesting to note that a JP story point tends to be a larger but fixed value as compared to PJ. JP takes about the same amount of time and effort to get anything done whereas PJ tends to be more variable in their output. 
  • A scrum master can sleep on the job with JP but really needs to pay attention to PJ as one never quite knows when or what PJ is going to deliver.

I bet you’ve already caught on to my attempt at fooling you! Over my 30 years of coding I’ve been both JP and PJ. I started out as a PJ and gradually I’ve learned to become a JP. The time and effort it takes to become an expert and to formulate strong opinions has led to diminishing returns. Our world just continues to spin faster with more variability than purists have time to master.

Who would you rather have on your team, JP or PJ? Who would you rather manage? Who would you rather be?

We need both JPs and PJs. I’ve worked at startups and large enterprises where we have tried to hire only one type and that has led to disaster. JPs make few “clever hacks” while PJs hit few milestones. A team of mostly JPs with some PJs seems to be ideal.

The main difference between JP and PJ is how they learn and how they use what they learn.

In the following series of six blog posts I’ll look at how I’ve optimized my ability to learn based on the themes of learning from first principles, learning by doing, thinking with external representation, learning through community, learning through imitation, and the realization that ultimately all learning is self-guided. 

In full disclosure, I have invented none of these concepts and not everyone agrees that these ideas completely model the learning experience. I’m just standing on the shoulders of giants and organizing useful knowledge, in a general way, as best as I can.

I’d love to hear about your experiences with learning so that I can better refine my own ideas (which, BTW, is an example of community learning).