Taking Small Steps and Small Risks

Starting something new can be risky business. Make one wrong move and you might destroy everything you have worked so hard to achieve. Taking unnecessarily large steps means taking a lot of bad risks. A good risk, on the other hand, is small and easily recovered from. Many large problems can be broken down into smaller steps which have a better chance of succeeding. Everyone makes mistakes and everyone loses from time to time. Taking many small risks curbs the danger of the inevitable losses and makes it easier to learn from failure. When the steps succeed, you have one more piece of evidence validating the course you are perusing. There are good risks and bad risks. Small risks are relatively good and large risks are often not.

Need an example? Lets say you want to take up diving. You’re new to the sport and want to see if you like it. Should you charge in and take a big risk, like jumping off a bridge, or take a more manageable risk and jump off a 10-foot diving board?

Big risks are just that — big. They can pay off in spades or they can fail miserably. There are times when large risks are warranted. Sometimes a big risk has great odds of success, reducing the size of the risk. When there are no options other than a big risk then the choice is clear, a big risk is the only way forward. Taking a big risk when there are better options, however, could either be a great success or eliminate your other options. The reward must be very valuable and the odds good enough to justify a large risk. If those conditions are not met, other options may be preferable.

The road to success is paved with small risks that payed off, and failures which were small enough to learn from. Here and there, a big risk is necessary and may be the best choice. When all the available doors are locked, there’s little harm in leaving the hallway. If it succeeds, more open doors maybe discovered. Nevertheless, taking big risks should be a last resort.

How Can I Make My Risks Smaller?

  • Find low-scope ways of proving assumptions about unknowns. If an assumption can be verified, try to do it in a way which isolates the actions from the rest of the project. If the assumption doesn’t hold true, or the opportunity doesn’t pan out, little harm is done.
  • When implementing an idea, take small and measured steps. Minimize risk by minimizing the distance between starting and confirming the viability each step. If you find that something isn’t working, it’s be better to take only a few days to find out than a few weeks. Break the plan up into smaller milestones which can be verified by solid, specific evidence.

Win Some, Lose Some

This philosophy is all about covering your losses and paving the way for future successes. Taking small risks means taking calculated steps to continue towards a goal. However, one step is not nearly enough. Each risk should lead into the next. When one step succeeds and has been proven to be acceptable, immediately take the next step. When something goes wrong and a risk fails, the only thing to do is to find another step to take. You can try something different to accomplish a similar goal, try something entirely different, or see about moving on without that part of the plan.

Plans change. By taking small risks you can create a more flexible plan. Smaller steps are more amenable to this kind of change. If one piece of the plan fails, it’s easier to replace a smaller component than a larger one. Smaller risks and measured steps make success easier to achieve and the inevitable failures easier to overcome.

Break Down Your Comfort Zone

I used to get stuck in a self-destructive rut in which I would start a project, get some of it done, and then drop it when I came upon a particularly difficult problem. Sometimes the problem was working with a library I didn’t like, having an issue with the build system, or just not understanding a concept well enough. Whatever the problem was, I would lose my motivation and promptly begin a new project. And of course, the start-work-drop cycle would continue. I must have five game engines collecting dust which work well enough in some respects, but aren’t quite usable. I have piles of half-finished projects lying around that I certainly could have finished.

For months I wondered why I couldn’t finish these projects. Sometimes I thought I just didn’t like writing a particular type of code or using a certain language. Slowly, I saw what I was really doing. My goals were lofty and challenging, but I rarely followed through. I didn’t push myself; I avoided the tough problems which would have led to improvement and a completed project.

The goals I set for myself are still outside of my comfort zone and the limits of my skill, but now that’s a good thing. To improve, you must push yourself past your limits. It’s like running — If you never try to beat your time, you won’t run faster. Working within your limits can definitely be productive, but how can you learn something new by doing only what you already know? It’s good to not go too far too fast, but some challenge is necessary. The experience of overcoming difficult problems engenders progress and expands your limits. Once you become comfortable with what was once challenging, greater problems and further improvement can be sought out.

I have found it fun to have goals which are focused on a particular thing which I want to improve. For example, I am learning Haskell. My goals are slowly driving me to learn the language. First I’m just doing practice problems and tutorials. Nothing too difficult, but foreign enough to keep it challenging. My overall goal is to write a full, useful program in Haskell. Right now that’s far beyond my skill level, so I need to slowly ramp up the difficulty of my goals to get me to a point where I can finish that program.

Goals are ineffective if you don’t have the will to complete them. I kept failing because I didn’t have the drive to push through those difficult times and keep learning and improving. Attack the difficult problems. Keep up momentum and continue making progress. As slow as it may be, if you stop progressing you’re liable to stop working altogether. So push past those problems and always take steady, measured steps towards the goal.

My inspiration for this kind of goal setting is what Cal Newport calls “Deep Work“. He advocates setting goals to stretch yourself, which serve the same purpose — to push you past your limits and force improvement. I’ve made deep work a habit; something I do without necessarily meaning to. Cal takes a slightly different approach, saying that one should create an obsession with doing deep work. Either way, nurturing a mindset of constant improvement is crucial. Always strive to improve, and don’t back down from tough problems.

Cellular Automata

The beauty of cellular automata is that they are usually fairly simple discrete systems, but out of that simplicity comes a torrent of complexity. Cellular automations often have emergent properties. They are defined by simple rules, but they produce fascinating results through complex interactions within the system.

But just what is a cellular automation?

A cellular automation consists of a grid of cells. Every cell in the grid has one of a finite number of states. Each time the grid updates, the state of each cell is determined by a set of rules. These rules generally use the cell’s “neighborhood”, a set of cells near the cell in question, to determine the cell’s state. The simulation can continue indefinitely, and sometimes seems to take on a life of its own.

Take a normal every-day elementary school classroom for example. The teacher wants all the kids to form a line boy-girl-boy-girl. The teacher might tell the students to look at their neighbors and see if they’re a member of the opposite sex. If they are, stay there. If not, trade places with the one on your right and check again. It might not be the most efficient way to sort a line of kids, but eventually they’ll probably form a stable line in the specified order.

Let’s take a look at a more complicated example — freeway traffic. Cars move around following relatively simple rules, but often produce very complex situations.

Say you are on the freeway stuck in traffic. The cars in front, behind, and to the right of you are moving slower and blocking the way, but there’s room to your left to merge into a faster lane. So you turn your blinker on and merge into the space to your left, leaving another open space where you were for another car to merge in. Cars are always coming and going, moving around, following simple rules to get to their destination. Cellular automations have no destination, but they still follow a similar set of rules. They move in predictable patterns just as you can (to a limited extent) predict how traffic might flow on the freeway.

The agents of cellular automations are called cells. Cells are just pieces in the automation which have a position in the grid and a state. The simplest cells exist in a one-dimensional space, have binary states (alive or dead, there or not there), and change state according to a small set of rules. This kind of automation would be like the line of kids. It has one dimension, left or right, has only one binary state, boy or girl, and changes according to one simple rule, move right or don’t move. An automation with more dimensions, more states, and more complex rules could produce situations more akin to freeway traffic than school children. But they still operate in basically the same way — according to rules and states.

Cells usually don’t change state based only on their own state. They usually involve their neighbors in matters of state. A cell’s neighbors are a group of cells which have some special relationship to the cell, such as being right next to it. The Moore neighborhood is a common term for the eight cells immediately surrounding the cell. The Von Neumann neighborhood includes the four cells immediately surrounding the cell. This is basically the Moore neighborhood, but not including the cells adjacent to the corners of the cell.

Neighborhoods aren’t always right next to the cell. Sometimes the Von Neumann neighborhood extends two cells out from the center cell. There’s really no reason why cell neighborhoods need to be anywhere near the cell, it just seems to be a common way of doing things.

But what happens when a cell is close to the edge of the grid, so its neighbors are off the edge of the map? The easiest thing to do would be to just assign all the cells outside of the grid a single unchanging state. Another option is having special rules for edge cells to deal with the problem of a cell having fewer neighbors than the others. Sometimes this involves redefining what that cell’s neighborhood is, or even redefining the grid itself. The grid’s edges could loop back around to reference cells on the opposite side simulating a torus. A toroidal grid is edgeless, so cells can move freely around the map without stopping or dealing with edges.

Most cellular automations fit into one of four categories. The first type of automation stabilizes into an unchanging pattern. The second category evolves into a stable system of unchanging and oscillating structures. The third category evolves in a seemingly chaotic way with no end or stability. The fourth category is the most interesting. Category four automations are very complex patterns which cycle between chaotic and stable structures.

Emergence makes cellular automations so interesting. Simple structures interacting with simple rules creating complex systems. I’d highly recommend playing around with CA from time to time. You never know what you might find.

Learning Leads to Appreciation

Everyone takes things for granted. We have to; if we gave everything full consideration we would never get anything done. But learning a little about everything, giving everything just a small amount of consideration, can lead to a lot of respect and admiration for the subject.

I’ve been reading the book CODE written by Charles Petzold. I almost didn’t buy it because I didn’t think I could learn much from a broad introductory text. In the past, I had learned a bit about almost everything the book claimed to cover. As it turns out, CODE is a well thought out and well researched book that ties everything together in ways which I never did. The book gave me a new appreciation for things like hardware and floating point numbers which I took for granted just a few weeks earlier.

These are things I use every day, but never thought twice about them because they’re so common. The same could go for any other topic, like music, food, air, carpentry, architecture, cartography, light, radio, batteries, cars, pens, mining, medicine, aircraft, history, television, printers, dirt, or the moon. All of us are at least influenced by these things every day, but how many take the time to think about them or learn a bit about them?

This learning I’m talking about doesn’t need to be reading a book on the subject. Reading the Wikipedia page or something could be enough, whatever seems interesting to you.

Give it a try. Think of something you normally take for granted. Take ten minutes and look it up on Wikipedia or google it. Learn something new about it and find ways to relate that information to something else. You might find that the subject is more interesting than you thought.

Constructive Constraints

How can constraints be constructive? Constraints are usually seen as things which hold one back. They’re perceived as inherently negative things which only prevent accomplishments and success. We’ve all heard complaints like “I don’t have time” or “I need more resources”. What if constraints weren’t all bad?

Some constraints really are bad and hold you back, but many can be more empowering than restricting. It’s really a matter of perspective: if you perceive a situation to be negative, you’ll probably find a way to make it negative. With a small change in view point, “I don’t have time” becomes “How can I be more efficient and do more with my time?” and “I need more resources” becomes “How can I do more with less? What must stay and what can change?”.

Rewording the issue to view a constraint as a challenge can change your attitude towards it. We’ll always have limited time and resources, those constraints will never disappear. Being negative about such pervasive constraints won’t change them, so why should they be negative? Turn those problems into assets.

Now you might be asking, “how can a problem possibly be an asset?”. In a 1986 talk, mathematician Richard Hamming mentioned that some of the best work that came out of Bell Laboratories was done when the work environment was well below ideal. Innovation was driven not only by thoughts and ideas, but also by the needs of the researchers working there. The limitations of their work environment didn’t stop them from doing great work. They took what they had and did as much as possible with it. A lack of resources didn’t create an inability to work, it spurred innovation to do more with less.

Understanding your problems is the key to turning them into assets. Ask questions about the problem. Try to see it from different perspectives. Why is this a problem? What can I change about it? Why is this problem bad and how can it possibly be good? Once you understand your problems you can begin to change your perception of them. When a problem is seen as more of a benefit than a detriment it is no longer a problem, it’s an asset.

Let’s look into some common examples. These problems will never go away, so how can they be made positive?

“I don’t have time”

The first question to ask might be, “Is this really important enough to spend my time on?”. If the answer is yes for any reason, but you still don’t have enough time, start to dig into the cause of the so-called problem. How are you using your time right now? If it is for the most part being used wisely, identify the slowest or least productive tasks. How can they be improved? Can that work be automated or delegated? Do they really need to be done at all? Your available time can increase dramatically if you constantly try to find ways to improve your methods.

“I don’t have enough resources”

This question is more difficult because it can certainly be true in many areas. You can’t make bread without flour, for example. But do you really need every resource you think you need? Look at each element and identify exactly why it’s needed. What is its purpose? Can anything else adequately replace this resource? How can the requirement be reduced in size? Resources are limited, that will always be true, but there are many areas where resource requirements can be decreased.

As I mentioned, the above problems are often artificial. However, there are times when the problems really are problems. There’s no getting around the fact that you currently can’t write a novel in an hour or build a house in a day. When these problems are artificial, there are many ways to make the problem work for you instead of against you. When the problems truly are impediments to your progress it might seem impossible to turn them into assets. In that case, I still think you can to find a way to make them constructive. Necessity is the mother of invention.

Notebook Updater: Automating With Python

Last week I found myself wanting to automate some todo list maintenance. I’m keeping my todo list in a Zim wiki so I can access my notes easier. The internal links and formatting is very nice to have. Around the same time I was a bit curious about Python. I hadn’t worked with it in years, and even then I didn’t do anything significant with the language. I decided to take a couple of days to throw together a little script to take care of the menial work involved with maintaining my wiki. It’s a little kludgey, but it gets the job done. It probably isn’t very useful to anyone else, but I put it in a Gist just in case.

The work this program automates is fairly simple. It copies two sections of text from one file to another and does some minor editing of the first file. Since Zim has a small, regular syntax and stores everything in text files, this wasn’t a difficult task. As I started designing the program though, it became obvious that there was more work involved than I thought.

The Notebook Updater starts by reading two sections from the first (“Home”) text file — Schedule and Time Log. I keep all of my tasks in the Schedule section and a rough log of my time usage in Time Log. Both sections are copied to the second (“Week”) file and placed under the heading for the current day. After the data is safely stored in the Week file, the program starts modifying the data to update the Home file. The day’s completed tasks are removed and tomorrow’s tasks appended to the list. Then the Time Log section is cleared and the job is done.

Since this was such a small project it did not need any classes. I wrote tests using unittest for each function and tested the general operation of the program on some test data files.

This design worked out well, but there were some issues. When I started the project I didn’t plan as well as I could have. Some features of the program were designed on the spot as I was building. The features should have been well defined before I started working. This lack of design created led to messy code in some (read: many) areas. Even though it isn’t a huge or important project it still doesn’t feel right. Text manipulation isn’t my best subject, so I doubt the text-handling code is very efficient, but that’s probably not as important in this case.

The Notebook Updater project was a fun way to get started with Python. I learned something new and automated some menial work at the same time. Writing code for yourself really is a great way to learn.

You can find the Notebook Updater code here.

Planning And Doing

When should you stop planning and start working? In some projects I was ensnared by analysis paralysis and never got past the planning stage. In others I started writing code far too early and ended up redesigning the project several times. Both cases are obviously not productive and waste a lot of time.

I have been thinking about my process and why I get stuck so often. My fear of not starting seems to be greater than my fear of not finishing. I would often spend an hour or two thinking about how amazing the finished product would be and then jump into the code. Writing code must be more productive than designing code, right?

Being too eager to start working can be just as destructive and counter productive as over-planning. Without a solid plan the project is like a building without a foundation, it’ll sink into the mud when you start construction. Starting with a very detailed and rigid plan will produce a project like a house of cards; it’ll collapse under it’s own weight with the slightest disturbance. The process I’m describing tries to avoid the problems of both extremes by creating a solid plan and reevaluating it after each stage in development. It all starts with a good plan.

Continue reading