Today, I was fortunate to present on microservices at Orlando Code Camp. I think this was my 5th straight year speaking at Code Camp, but it has definitely been long enough that I am now not sure ow long it has been. First of all, I’d like to thank the folks at the Orlando .Net Users Group for inviting me back to speak yet again. More so, I would like to thank the great group that showed up to hear my presentation, “Microservices – Little Services, Big Apps”. It was very humbling to have such a packed room and I hope everyone learned something or was at least mildly entertained. For those of you who attended, the slide deck is below. For those of you who did not attend and arrived here some other way, you can also find the slides but they will probably be far less interesting. I don’t normally record these sessions because I always try to capture a certain amount of technical Zeitgeist both from the current technology landscape and my current professional experience. Also, I feel like these community events deserve a certain amount of exclusivity for those who are able to attend. Over time, most of the content will be posted on my blog one way or another (if it hasn’t been already).
For a few years, I’ve been working with a team that prefers spaces to tabs. More specifically, 2 spaces. I agree that this is a superior visual arrangement and having everyone use it benefits those of us who prefer it, those who don’t care, and will eventually bring those who don’t like it to see the light. Today, however, for reasons that will be more obvious in future posts, it occurred to me that tabs may actually be superior.
This revelation requires first admitting that this is a preference. You may code on a 32” curved 16:9 or a 20” 4:3 rotated to 3:4 portrait. You could be writing code on a flip phone for all I know. Whether you use tabs or spaces, the desired effect is the same: to provide consistent formatting to make the code easier for you to read.
This leads me to my argument for tabs: Tabs are the democratic choice. Tabs put the details of the implementation in th hands of the consumer. Most modern IDEs allow you to customize your tabs. Want tabs to be 7 spaces? Let your crazy-big-odd-numbered-tab freak flag fly! It’s much easier to customize tabs or replace them with spaces than to replace spaces with tabs. So I’m sure this debate will rage on and I will happily continue to use spaces for my code, but for you, my friend, I will give you tabs.
Yes, that is a broad generalization. Yes, broad generalizations are (often) bad. Yes, I see the irony in that. However, tutorials are often bad. The good news is, this is often by design. Tutorials are intended to show you how to do something very specific. This means most basic tutorials are intended to show you how to do that specific thing as succinctly as possible. The problem (or potential problem) with this is that good code is often not particularly succinct. As I mentioned in my previous post, “optimal” code isn’t easy to design and what is “optimal” for one scenario might not be fore another. So in this post, I’m going to explore some concepts that are (often) good. Since they are often not followed in tutorials, it stands to reason that tutorials are (often) bad.
OK, not that kind of DRY. DRY means “Don’t Repeat Yourself”. Tutorials typically keep code in as few places as possible to make it easy to follow the examples. DRY code requires separation of concerns. This means putting your code in the “right” place which means you have to have multiple places to put it. Chances are you need a more complex project/file structure than what a tutorial will show you.
Unless a tutorial is demonstrating some aspect of testing, it most likely doesn’t include any tests. Because of this, the code won’t necessarily be very testable. Making your code testable requires a certain degree of DRYness since you typically want to test small units of code (“unit tests”). Most modern frameworks support features like dependency injection to improve testability, but these features are often absent from tutorials, so beware of tutorials without any tests.
Testability and maintainability go hand in hand. Maintainability is definitely an art and beauty is in the eye of the beholder when it comes to what “easy to read” code looks like, but there are some good rules of thumb:
Keep functions short enough to read on the screen.
Tutorials probably follow number 4, might follow number 3, and very often ignore 1 and 2.
Putting it All Together
The code in tutorials is not typically well structured. Good structure means your code is DRY, testable, and easy to maintain. When following tutorials, look for opportunities to improve the structure. Develop your own toolbox of reusable code and components. You will quickly find that all projects benefit from having at least 3 components: a “core” set of code not tied to a specific implementation, at least one specific implementation, and tests. Nothing is one-size-fits-all so no one template will match every project, but it’s good to have a general approach that prepares you to write “good” code.
Clearly, I should have been in game development. I’ve been coding since the third grade so software was always in the cards for me. I have a degree in Mechanical Engineering so I have the physics chops to handle pretty much any kind of real-world simulation from projectile motion and particle physics to fluid dynamics and even heat transfer. My masters degree is in Industrial Engineering so I know about things like optimization and simulation that are helpful for AI (among other things). And games are fun!
What I realized recently, is that writing “good” code is an Industrial Engineering optimization problem. You see, optimization problems deal with multiple dimensions with often multiple optimal solutions. Note the use of the word “optimal” and not “best”. Optimization problems often have multiple variables and an astronomical number of potential solutions. So when you are optimizing code, what is your goal? Maximize speed of execution? Minimize size of compiled code? Minimize bandwidth used? Minimize processing power used? Minimize total operating cost? Maximize test code coverage? Why not all of them? Well…I’ll tell you why.
One of the most famous examples of an optimization problem and how mind-bogglingly many solutions they could have is the “traveling salesman problem“. The traveling salesman must visit some number of potential clients and then return home. In the simplest version, he is flying from city to city and the only concern is the order of the flights to the various airports. A much more practical and complex version is a package delivery company with a fleet of trucks needing to deliver packages over routes through a complex network of highways and city streets with variable traffic, one way streets, traffic lights, etc. Every variable multiplies the number of solutions by the number of possible options for that variable. The number of possible solutions very quickly gets large – like more than the total number of atoms in the known universe large. What hope do we have of solving these problems? Luckily, we have pretty cool brains.
Malcolm Gladwell wrote a book titled Blink: The Power of Thinking Without Thinking. It’s a great book and I highly recommend reading it, but the gist is our brains are able to take in a vast array of information and come to a conclusion (an “optimal solution”) without consciously thinking about it. This ability to organically problem solve was also recently discovered in single cell organisms. This is why we are pretty good at coming up with decent solutions to these problems without knowing anything about linear algebra. Our brain operates on “heuristics” that our life experiences have allowed our brains accept without having to think about them. In the world of software development, the use of these heuristics are the “art” and allow us to optimize variables that are extremely more challenging and seemingly abstract such as “maximize code reuse” and “maximize maintainability” and, as I like to say, “minimize astonishment“.
Another important consideration in optimization is boundaries. For example, you may be able to purchase a certain amount of computing resources for a certain cost. Additional resources add more cost. This means that you don’t necessarily need to use an absolute minimum number of resources, you just need to make sure that the amount of resources used doesn’t trip the threshold or that if it does, you have a source of revenue to cover the added cost.
In future posts, I will dive into more detail on the day-to-day practical advise on optimizing your code, but first I wanted to take some time to lay some groundwork. In the early days of computers, you were greatly constrained by memory and processing power. You had a limited number of pixels that could be rendered on the screen in a limited number of colors. You could only store so many bytes of code. You were limited to a small number of operations the processor performed. You were limited in the language you could code in and the structure of that language. The optimization required was much more science with a small number of options for each variable. Now, the options are astronomical. What language do you use? What platforms or devices run that code? What communication channels does it leverage? How many millions of colors and pixels does it render? Sure, it is still important to minimize operating cost (storage, CPU cycles, bandwidth, etc.), but you can also get access to a significant amount of resources for little or no cost. This allows you to focus on the art – maintainability and reuse – first, and then solve the challenging scientific problems later (or not at all).
After spending nearly 20 years working for a defense contractor, I joined Deloitte to focus more on software and to build that software for clients outside of the defense business. I’ve been with Deloitte for a few years now and I’m starting to take a more active role in Systems Design and Engineering leadership. This means helping with activities to establish “eminence” of our practitioners. For me, that means being more active in those activities myself…practicing what I preach…eating my own dog food…I think you get the point.
I’ve consolidated some of my old blogs here. It’s been a long time since I’ve posted anything technical, so most of that stuff did not survive the move here. However, I have some nerdy things in the works and a few decades of…wisdom?..to share. I’m looking forward to unleashing the avalanche of blog posts swirling in my head.
I’m trying to run a little more often (ok, a LOT more often) so I’ll be posting about that too. Beware, I am a running nerd so expect plenty of over-analysis while I try to regain or even surpass my fitness level of years gone by.
So for those of you who have stumbled onto my little corner of the internet, I welcome you and hope you find some knowledge, inspiration, or at least some entertainment.
Most people reading this have probably heard the metaphor comparing something to a marathon as opposed to a sprint: your education is a marathon, not a sprint; your career is a marathon, not a sprint; investing is a marathon, not a sprint. At first, the meaning seems obvious. A marathon is 42,195m (26.2 miles) and sprints are 400m or less. You don’t have to be good at math to see that the marathon is more than 100 times longer. The marquis sprinting distance is 100m and is used to crown the “world’s fastest” man and woman. Both cover the distance in less than 11 seconds. Both marathon world records are over 2 hours. The Disney Marathon requires you maintain a pace of 16 minutes per mile which will get you to the finish line in a few seconds less than 7 hours. A marathon is much longer than a sprint. I get it. Or I thought I did until I finished my first marathon.
When I started training for my first 5k, I did a “couch to 5k” program. I ran several days a week running longer and longer intervals until I could run 30 minutes wihout stopping (the approximate time it takes to finish a 5k). To be ready to train for a marathon, I needed to be able to run 8-10 miles wihot stoppimg. About 6 months after that first 5k race, I ran a 15k and started training for my first marathon. My training plan lasted 16 weeks running 4 days a week and peaked at 40 weekly miles and a long run of 20 miles. The long runs took 3-4 hours (or longer). Then I ran for 4 hours and 27 minutes and had over 4,000 people finish ahead of me and many more behind me.
Between my first and second marathon, I ran four 5ks, two 15ks, and three half marathons over more than 2.5 years. I lost 15-20 pounds off of my already slight frame. My goal was to finish faster and run the full distance without stopping (I walked through the water stops during my first marathon). I added a 5th day of running to a 18 week training plan and peaked at 50 miles a week with a long run of 20 miles. This was on top of years of gradually improving fitness.
So if it isn’t obvious yet, a bigger difference between a sprint and a marathon, bigger than the difference in distance, is the difference in preparation required. Most people can run 100m. Most of those who can’t are able to walk 100m. However, most major marathons include hundreds of people who enter and prepare only to fail to finish. This still isn’t the biggest difference.
I don’t know when it specifically occurred to me. Maybe I was on a run and saw someone pushing their belongings in a shopping cart. Maybe I had stopped at my local drug store to buy a Gatorade from someone working a second job. Eventually it occurred to me that not everyone can train for a marathon. You need time, support, health, and at least a little disposable income. If any one of these things is missing, you are going to have a hard time. Start adding them up and it quickly becomes impossible. Running a marathon requires privilege.
When I trained for my first 5k, I wore workout clothes I already owned and wore shoes I bought because they were a bargain, but I did most of my running on a treadmill in a gym. By the time I ran my second marathon, I had gone through more pairs of shoes than I could count and most set me back more than $100. I had enough of my favorite running shorts and sweat wicking shirts to run 5 days a week without having to do laundry in between. I usually had 2 pairs of shoes so one could be nice and dry while the sweat and occasional rain evaporated from the others. I had a wife and extended family to help watch the kids. I had a job that gave me the flexibility to have time to run. I had the required privilege.
So when someone tells you something is a marathon and not a sprint, not only does it take time but it probably also takes preparation. And if it takes both, you must have the privilege to even have the opportunity to undertake something that requires time and preparation. So when someone uses this metaphor, be thankful for the marathons your life gives you the opportunity to run.
The latest foray into the commercialization of running is the Michelob ULTRA 13.1 Marathon Series (http://www.131marathon.com/). I like beer. I even like Michelob. I like running. I accept that for-profit race series exist. So why should this be offensive? Quite simply, 13.1 miles is not a “marathon”. It is a half marathon. A marathon is 26.2 miles. I understand other races are named by their distances. No one is confused or offended by someone saying 5k or 10k, but also no one familiar with running would call those races a “5k marathon” or “10k marathon”. I also understand that a half Ironman is also called a 70.3 Ironman. The difference there is that “Ironman” is a trademark held by the World Triathlon Corporation. Other races can’t call themselves a half ironman or full ironman so they often use the distance (70.3 or 140.6) and just like we use Kleenex as a generic term, people sometimes use the term “70.3 ironman” to describe a half Ironman distance race. However, in my experience the preference seems to be “70.3” or “half ironman”.
I tried to find an explanation for this naming convention. Wikipedia doesn’t know what a 13.1 marathon is and the first several pages of a google search all point to the Michelob race. At first I thought it was comical to see “how far is a 13.1 marathon” but then I realized I had already asked and answered that question by visiting the site above for the Michelob series.
Not surprisingly, it is 13.1 miles.
I can only assume that the goal is to make this race more approachable. Not everyone knows how far a marathon is. Most people have never run one. They know it’s a long race. They might know you get medals and other “swag” when you complete one. They might even know you aren’t required to run the whole time. Calling a race a “13.1 marathon” might make running and racing appealing to more people which I am all for. It still makes my skin crawl.
I’m a very typical runner in many ways. I started in 2009 and did a “couch to 5k” program pounding away on a gym treadmill wearing cotton gym shorts and heavily discounted Nike trainers that were too small. My wife and I ran our first 5k in a relatively small race but we got to wear bibs with numbers on them and had our time recorded electronically and had people we didn’t know cheering us on even though we were nowhere near the front of the pack. I finished that race barely in the front half but I was hooked.
As for my commitment to running, I might be a little more aggressive than some. After that first 5k, we moved straight on to training for a full marathon and threw in a 15k for good measure. After my first marathon in January 2011, I focused on 5ks and half marathons for a while. By the time I ran my second full marathon in 2013 I had moved from the middle of the pack in that first 5k to the 89th percentile in the Marine Corps Marathon. Why am I sharing all of this information? Am I just bragging? Maybe I am bragging a little, but that is because I have earned it. I’m not bragging about finishing ahead of about 89.4% of people who ran with me in DC. I am bragging that I ran that race 45 min and 22 sec faster than my previous race at that distance. I am bragging that I dropped my average pace per mile from 10:12 to 8:28.
You see, most of us who do go out and run every week and race often aren’t racing against each other any more than someone who just does one race to cross it off of their bucket list. We are racing against ourselves. The marathon is the “premier” distance for people who want to improve their running. It is the gold standard yardstick for measuring endurance running performance. That’s still not why I find the term “13.1 marathon” offensive. The real crux of my contempt is this: the body starts to “break down” after covering 20 miles. I’m not going to try explain the physiology, but I will tell you this: even now at my lowest level of fitness and training in years, I could still run 13.1 miles without stopping. It will be slow, but I could finish. I could not run 26.2. The marathon is special. So let’s not water it down by trying to turn it into Kleenex.
I have two quotes from old friends that have stuck in my head in certain situations. The first is, “dancing is like standing still, only faster.” As a runner, I have adapted that to, “running is like falling down, only slower.” The second is, “when you hear hoofbeats, think of horses, not zebras.” As a programmer, I have found there is not much better advice than this second quote.
You would think that the more experience you have, the more likely you are to look for the obvious answer. I’ve found that the opposite is true – while you are going to make “stupid” mistakes less frequently, the majority of your mistakes are still going to be “stupid”. Unfortunately with great power comes great ego, and the most difficult bugs are caused by the occurrence of something that was “never going to happen”. I happened to stumble through 3 of these self-induced hair-pulling-out exercises in a matter of days. To make matters worse, I don’t really code at work anymore. This was a hobby project that I can only work on for an hour or two each night.
First was the infinite loop (and subsequent stack overflow) – one of the few errors that can’t be captured with standard error logging techniques. This problem only happened on the production server so instead of doing the obvious and duplicating the data down to dev so I could debug, I decided to add debug logging until I found the problem. This was the first symptom of my bravado. My application is a state machine “engine” that runs in a loop. As things happen and the state changes, the loop eventually completes. I narrowed down the problem to the state where the error occurred but had trouble getting closer than that. I was convinced that some dark magic was at play and some data anomaly so I spent a few nights adding debugging, publishing, running, repeating.
Finally, I stopped looking for zebras. Instead of continuing to try to zero in on the line of code through trial and error addition of debug logging, I put 3 lines of code in the most obvious places the problem could occur – the 3 while loops that could get called inside my main loop. That immediately pointed me to the loop in question so then I threw an exception when a condition causing an infinite loop occurred. It probably took me all of 5 minutes to determine the state that caused the problem.
So next I had to figure out how the code got into that state. All of the information I needed to solve the rest of the problem, I saw within minutes – and completely ignored. I saw that the state in question could only come from the database because the key data was never set anywhere by code. Therefore, the code that allowed the infinite loop condition must have been in the code that loaded the data from the database. However, rather than looking right where all indications pointed, I looked for zebras. Since I knew how to find the problem, I could now duplicate it on my dev box and debug. That meant I could spend time inspecting variables at breakpoints to see why the problem was happening. After all, this infinite loop was caused by a recursive linked-list relationship – something that was “never going to happen”. There couldn’t have been an obvious reason for something like this to happen so I had dig for a needle in the haystack instead of following the thread attached to the needle. In spite of myself, I did eventually figure out that the problem could absolutely be solved when the data was loaded into the engine. Technically this is after the data is extracted from the database, but the recursive situation doesn’t matter until it gets to the engine so that’s where I put the fix to truncate the recursive linked list since the duplicate reference shouldn’t have been there anyway.
Fast forward a few days. With my problem solved, I was able to run my engine for a few days and then started to look at the output. Then I stumbled on a new error – “An error occurred while reading from the store provider’s data reader. See the inner exception for details” and the inner exception was “Arithmetic overflow error for data type tinyint, value = 2288”. So, the expert programmer has managed to break the Entity Framework. Of course I checked the “obvious” problem – that my model had the wrong data type. Then I went off the deep end. Unfortunately, there are people who have had legitimate problems with EF or linq-to-SQL mapping parameters incorrectly (2288 was a parameter, not a database value). I converted my linq expression into a SQL command and then realized I was once again looking for zebras. Instead of looking at the columns in my database that would map to tinyint, I assumed the problem was in the Entity Framework – code written by Microsoft and used by thousands if not millions of people – and not in MY code. When I stepped through my code and looked at the parameters, I noticed there was a parameter that should’t have even been there. That was my problem – I passed the parameters into my method in the wrong order! Instead of passing “int, null, int, true” I was passing “int, int, null, true”. The 2nd and 3rd parameters were both nullable ints so as far as the compiler was concerned this was all good. Unfortunately it meant it passed my very large primary key into a parameter that was expecting a much smaller value – something that should have been very obvious from the error.
This post has been sitting in draft for so long that I have now had several more “events”. The most recent was while doing a demo on AngularJS directives with my team at work. I was trying to illustrate scope isolation and no matter what I tried I couldn’t figure out why the attribute from the directive specified in my HTML wasn’t making its way to my link function in the directive code. When I turned off scope isolation and pointed at the parent scope, everything worked fine. Even my more Angular-savvy team members were stumped. Then came the “duh” moment – I actually had 2 directives nested inside each other. I was looking at the code in the inner directive and passing data into the outer directive. The HTML of the inner directive wasn’t passing the value from the parent. Yet another zebra chase.
So in conclusion, drop the attitude! When you have problems, they are most likely the most basic and amateur issues. Reign in those horses and let the zebras smack you in the head, don’t go looking for them.
UPDATE: 29 January 2019
I have done it again! I was working on a new framework feature and couldn’t get my test to work. I just KNEW it was a problem with the third-party software I was using. More specifically, I wasn’t sure what I was trying to do was even supported. Then somehow I managed to get everything to work directly with said software. After days of struggling, I discovered I was writing the final portion of my test immediately after testing deleting the exact thing I am trying to test. As usual, my code was doing EXACTLY what I told it to do.
On a side note, since the original post, I was introduced to the concept of rubber duck code reviews. I highly recommend this and your coworkers will thank me.
The 2013 Marine Corps Marathon was my 40th birthday gift/celebration. I turned 40 in September so about a year ago I started looking for a marathon to run around my birthday. Some folks from my local running group were planning on running MCM so it seemed like a good fit – a trip for my wife and me to DC, a chance to visit friends in Baltimore, and a chance to run in one of the premier marathons in the country. Knowing it would sell out fast, I started hitting the web site 1 minute before registration started and after about 45 minutes battling the web site I was registered. Training went as well as it could. I only missed 4 runs in 18 weeks. I did three 20-milers and each one got easier. The taper went great and I was doing all my short runs easily at my goal race pace of 8:10.
This was my first “destination race” so that added some additional excitement. My wife and I flew into Baltimore on Friday and spent some time with friends. I did a 2-mile shake-out run Saturday morning. Since all of my training was in flat Orlando, this was my only really hilly run of all of my training – something that I would later regret. The rest of Saturday was pretty hectic. My wife and her friend were staying in Bethesda the night before the race so we had to check into that hotel. Then we went into DC to check into the hotel I was staying in. We finally got some lunch around 3:00 PM and then headed to the expo to get my bib.
Packet pickup and the expo were both a nightmare. It took about 40 minutes to get through the line to get my number and the B-tag checking system wasn’t working (I heard later that there was a power outage). The wait to get into the expo wasn’t quite as bad but I didn’t have a bag so I got to go in a shorter line. People with bags and purses had a longer wait. Once I got in the expo, they ran out of bags for the bag check about 10 people ahead of me. They said you would just have to find a clear bag if you needed to check something. At first I was panicked because I didn’t realize that the bag check sticker was on the back of my bib (Disney puts them in the bag). Then a guy in front of me looked in a trash can and found a couple of bags so I ended up getting one after all, but not before getting stressed out about my plans for what I was going to take with me to the start area and what I would do with it.
We had dinner at “Founding Farmers” – a really great restaurant in DC – and then headed to another restaurant to meet my running group friends. This was a bit of a long walk (something my wife thinks impacted my performance but I’m not too sure). By the time I got there, only two of them were left (7 of us ran). This was the first of several near misses with my group but it was good to chat with the two of them for a while at the restaurant and then while we walked to the metro back to our hotels.
The night before the race, as usual, I got almost no sleep. It seemed like I could hear cabs honking out on the streets until about 2:00 AM. At 4:30, some guys were out in the hall singing Ricky Martin’s “Cup of Life”. Since I was going to get up at 5:30 anyway, I decided to get up and then had that song stuck in my head all morning. I had a Clif Bar, a dump, got dressed, took a selfie in my race getup, and headed to the metro. The weather was pretty cold (40s) so I had on a long sleeved shirt over the shirt I planned on running in. I put my number on my leg because A) I wanted to be able to get rid of my long sleeved shirt if I needed to and B) I’m used to wearing it there now. I tried putting it on my shirt but it just didn’t feel natural. I also got myself some cheap football gloves and planned on tossing those too.
I got there plenty early. I had time to pee and sit in the hospitality tent for a while and wait for some of my running group friends. By the time they were heading my way, it was about 7:15 so I needed to check my bag and get ready for the 7:55 start. I was too anxious to wait for them any longer so that was my second near miss with my friends. I checked my bag and hit the port-o-let line one more time. While I was waiting in line I set my watch for the marathon distance and my goal time of 3:35. I had never used this particular setting before so I thought it might come in handy. Bad idea. It just gave me extra screens to scroll through when I checked my time throughout the race.
Unfortunately that toilet stop put me way too close to start time. I headed to the starting line and tried to find the 3:30-ish corral. I got as far to the front as I could, but the start was the second thing problem I had with this race. They had corrals on both sides of a divided highway. I stood on the left side and after the Howitzer went off to start the race I watched the 3:45 pacer go running by on the other side while we stood still. The crowd at the beginning was ridiculous. I completely missed a water stop because water was in the back and by the time I was able to get over I was past the last person passing out water. Also, I must have been in the “long” lane because at the first mile marker, my Garmin already said 1.18 miles. You placed yourself at the start so you had some very “optimistic” people toward the front. I felt like I was passing people for about 18 miles. By the time I stopped passing people I felt more like it was because I had slowed down and not because I found people at my pace. I really enjoyed the race overall but the crowds and uneven pacing were a bit annoying.
So now for the fun part – the race. In spite of the MASSIVE crowds and a major uphill climb at the beginning I managed to keep my pace under 9:00 for the first 2 miles. That first climb was pretty impressive – 244 feet according to Garmin in about 2 miles. It didn’t seem too bad at the time and from what I had heard about the course it was all downhill from there. I tossed my gloves at about 2 miles and then the climb turned into my favorite terrain – downhill. I love charging down hills. I was still in heavy traffic but managed to cut loose a bit and made up some serious time. Around 4 miles in I ditched the long sleeved shirt. My favorite part of the race was Georgetown (between the 4 and 5 mile marks). Beautiful town to run through and my watch hit the 5 mile lap just at the top of the last downhill – a massive plunge down Wisconsin to Waterfront. I when I got to the bottom my watch said 6:00 pace for that lap and I believe it – I was flying down that hill. In fact I was a little nervous that I might blow out a knee at the bottom when we had to make a sharp left turn. Somewhere around there was a group of drummers. They were playing big drums that seemed Asian even though the drummers didn’t. The sound was amazing and really gave me a boost.
Between miles 5 and 6, I caught a glimpse of some of the leaders. The road heading toward the zoo was an out-and-back section so they were heading back and at about the 9 mile mark. After hitting the 5k at 26:40 (8:34 pace) I averaged 7:48 for the next 5k hitting the 10k at 50:56 – 8:12 pace which is just what I needed for 3:35. After 6.2 miles I was right on track. Interesting side note – this section I recognized after the fact as the road to the zoo. I went there on a previous trip (I think in high school 20+ years ago). There may have been road signs to plant the memory in my subconscious but it was really only after the race when I thought back to that section that I realized that’s where I was. I hit the 15k at 1:16:39 – 8:13 pace – feeling good and on schedule.
After mile nine we hit the waterfront. I ran by the Kennedy Center where I recalled going on a tour during that high school trip. We went on the roof and a friend and I raced across it. I thought it was interesting that I sprinted on that roof and here I was running by that building 20+ years later.
Miles 10-15 were kind of a blur. I was feeling really good when I hit the half. I remember thinking that doing that again was going to be tough and that I kind of wished I was just doing a half because I could have really killed it. I had no idea what my exact pace was but did know I was at 1:46 for the half – a PB by about 5 minutes. My original goal was 3:40 so at this point I had plenty of room to spare. That was my only real pace check since my Garmin had me in the high 7s up to that point due to the long first mile. Official pace for the half was 8:09 still 3 seconds under my goal for 3:35.
Next was the mall. I remember running toward the Capitol. After scanning the crowds for my wife an her friend, I finally found them after mile 17. It was a great boost to see my wife. I had almost given up on seeing her and figured I already missed her in my running daze. I remember being surprised at how tree-lined the mall was. I think the crowds blocked a lot of the view so everything looked very different.
Circling the Capitol around mile 18 was where I first started to feel it. Up to that point I felt like I could go forever. I still felt pretty strong and just wanted to get to mile 20 figuring I could survive the last 10k. I eased off a bit and was averaging around 8:23 – about my original planned pace to hit 3:40. I felt like keeping that “easy” pace was workable and would definitely get me under 3:40 since I had a good head start.
The last few miles were not all that exciting. We crossed the bridge back to VA and so it was just running on the highway. There was a girl matching my 8:20-ish pace around mile 21. I hung on her shoulder as long as I could but that is when I started to get some tightness in my legs. I managed to run through the first cramp and it seemed to go away. Mile 22 was 8:32 on my Garmin and mile 23 was 8:44. The hills were mostly just overpasses and the bridge at that point but they were starting to take their toll. I adjusted my goal to just finish without having to stop running – I hadn’t broken stride even once to that point. That’s when my legs were really getting angry. At about 24.7 on my watch I was making a left turn coming down an exit ramp when my leg completely cramped up. I had no choice but to stop and stretch. I never really recovered. From that point on I was doing the “marathon shuffle”. Miles 24 and 25 were 9:42 and 10:11 on my Garmin.
Now the hills were real. They weren’t overpasses – they were actual hills. I managed to crank it back up to 9:52 for mile 26. Thanks to my watch setting snafu, my watch stopped at 26.2 which was unfortunately before I made it to the official 26 mile marker. I had been dropping quite a few “F bombs” those last few miles so when I got to 26 and couldn’t see the finish, one was preceded with a “what the”. Then I turned left and saw the most ridiculous part of the course. They had advertised a “flatter finish”. I would hate to know what the old finish was like. This last hill was so steep almost everyone I saw was walking and it seemed like you could put your hands down in front of you to help climb up. It was probably just a few hundred feet, maybe less, but it was brutal. I refused to stop running – something I only did once for that charlie horse – and made it to the top and the last right turn to the finish line.
I’m glad I had sunglasses on because I was holding back tears a few times. Coming up to the finish was the first, then getting my medal from the Marines, then thinking about seeing my wife. I had to climb more ridiculous hills after getting my medal and goodie bag so I stopped for a breather at the top of the hill. I found my wife through a fence and she passed me the phone to call my 5 year-old. She asked if I won (I knew she would). I told her I did “for me” and that I got another medal.
For me this race was a lot of victories. I had been training towards 3:35 on my Garmin. That meant an 8:12 pace on my watch. I had 10 miles in a row under 8:00, 4 more under 8:12, and another 5 under the 8:25 pace I needed for my secondary goal of 3:40. My time for 26.2 on my watch was 3:39:14. My official pace through 30k was 8:08 – fastest cumulative pace of the race after doing 8:34 for the first 5k. I ran a 7:57 pace between the 10k and 15k. I was at 8:11 through 35k and 8:22 through 40k. That means I was under my stretch goal for 35k and dropped under my goal in the last 2 miles.
During my training, when I stopped running on my long runs, it was because I was “too tired” to keep running. This time the cramps in my leg were a new experience for me (not something I would want to happen again) and I felt like I gave everything I had – my body shut down and I did what I could with what I had left.
Now it’s time to give my wife a much needed break from my training over the past 18 weeks. I may race a few more times this year to ride the wave of my race fitness, but no more hardcore training plans for me.
I don’t think anyone can go into a marathon knowing for sure how you are going to do. You can know whether or not you are prepared, if you are healthy, how fast you are able to run. There is no guarantee that will translate to performance on the day. I think the best you can hope for is to finish without saying “if only”. I’m not saying if only I didn’t skip training, if only I went faster/slower in the start/finish, if only the weather was better. I know I did my best and I know what that means today. I have no doubt I can run a marathon in 3:35, but I also am ecstatic that my PR is now 3:42:13.
So you’ve paid your registration fee, trained for months, booked flights and hotel rooms, and now you are ready for your big race. Race day is approaching. What are all of those things you need to remember to avoid major running catastrophe and the little annoyances that could have been avoided? I figured I would share my list in hopes it might help out some others. Post your additions in the comments.
1. Pack everything important in your carry-on bag.
My dad travelled frequently for business and my parents still travel frequently for pleasure. This is a lesson that is a habit for them and has rubbed off on me. For my race travels, that means my shoes, Garmin, and Garmin charger. Anything else I can buy. That doesn’t mean I won’t put my full race outfit and other supplies in my carry-on, but if space becomes an issue I could leave them out.
2. Download your Garmin data then delete your history.I found out the hard way that your lap history can fill up in the middle of a race. Navigating seldom-used watch settings isn’t something you want do be doing while you are running for a PR.
3. Don’t pack gels in your carry-on.
Even though you might get through security, you could have to throw them out or worse miss your flight while they investigate the contents of your bag.
4. Document your running routine as a packing list.
Do you use glide or band-aids, eat homemade pre- or during-run snacks, listen to music? Write it all down before your last few long runs then make sure to pack everything you need. If it’s too late for that, walk through your routine as if you are going for a run and put all the things you pick up in a grocery bag or something similar so you can make sure it all makes it to your luggage.
5. Lay out all your gear the night before.
If you are running close to home, his might not be such a big deal. However finding everything in a cluttered suitcase and unfamiliar setting if a hotel room can be tough especially before sunrise after a restless night. If you use pouches or bags, fill them up the night before. Put the gels in your pockets if that is where you keep them. If you are like me, you will still triple-check everything (and still forget something) but still better to stack the odds in your favor.
6. Don’t forget your Garmin when you leave for the starting line.
I did that heading out to a half marathon. Luckily I had plenty of time to make the 20-minute round trip back to my hotel room, but that was stress I didn’t need. Sure I could have just used the on-course clocks but doing math while running is harder than you would think.
7. Don’t forget about the expo.
Most big races have them and they can be a great place to pick up gear and swag. More importantly, they can be a grocery store for gels and other last-minute needs (things I forgot to out on this list or forgot in spite of putting them in this list). So don’t stress too much since you can find almost anything you might need.
8. Don’t get new race gear at the expo.
Don’t try compression sleeves for 26.2 miles if you’ve never used them. Don’t try some new chewy calorie source when you trained with gels. And for God’s sake don’t get a new pair of shoes unless you lost or forgot yours and found a pair of shoes you’ve run in before.
9. Bring disposable clothes.
Most big races donate discarded clothes to charity so if you anticipate cold weather, bring an old sweatshirt, hat, gloves, whatever you think you might need. Keep in mind that your body heat will warm you up so you may want to discard these things at the start or right after. If you wear extra clothes, make sure your bib is on your bottom layer or on a removable number belt if you have experience with such things (but refer to #8 before you strap on something new).
10. Check in to your flight.
Typically you can check in 24 hours in advance. Get your electronic boarding pass or print it so you are ready to go.
So that is my personal encarnation of my running OCD. Hope it is helpful for you!