girl coder

Scrapping my work — again

I discovered a new emoji this week: the volcano.  Screen Shot 2016-07-19 at 11.58.32 AM

To date, the crocodile has been my go-to emoji for expressing rage.  For example:

This lady with weird pants almost hit me with her bike this morning on Broadway.  crocodie

My coworker called a meeting and didn’t even bother to show up.  crocodie

Someone else took the last swedish fish from the snack jar.  crocodie

But this week, my emoji needs reached a whole new level.   I was trying to get final specs on a new feature, into which I had already poured a number of hours.  After a lot of unhelpful answers over slack from the people who were supposed to be planning the feature, I got a final message:

“Hey don’t worry about this feature too much.  Once you make it we can have people try it out and then we can always just roll it back.”

Screen Shot 2016-07-19 at 11.58.32 AMScreen Shot 2016-07-19 at 11.58.32 AMScreen Shot 2016-07-19 at 11.58.32 AM

Irritating exchanges aside, this is one of the things that has been hard to get used to in software — the idea that everything I do can and will be scrapped, sometimes by me, sometimes the next day, often without a trace of my original labors.

In past jobs for government contractors, nonprofits, and universities, everything I did led somewhere.  My edits were incorporated, my proposals submitted.  Redoing something from scratch was a rarity– if it was bad enough to need redoing, the boss would probably give it to someone else anyway.

Fast-forward to today: rewriting code galls me.  It says to me that I’m just a code monkey who is that much closer to death, that if people respected my time this wouldn’t happen — even though I’m just as often to blame for mistakes.  Every minute I spend redoing something feels like further confirmation of my own worthlessness.  “I may as well not even be here,” I think to myself bitterly as I start cherry-picking commits.

And yet.  My boss offered some encouraging feedback in my annual review last month.  After telling me how happy they are to have me as part of the team for 2016, he offered some constructive feedback.  He encouraged me to be patient and flexible around redoing things. (He knows how bent out of shape I get about this stuff, having received his fair share ofcrocodie.)  He reminded me that reworking is part of the software development process, part of life, and it’s not really a sign of personal shortcoming.  In fact, refusing to rework a feature or to improve it would be the shortcoming.

I still hate redoing things — that hasn’t changed — but I’m starting to see this struggle as an opportunity to practice patience with my sometimes frustrating reality.  No software, not even my own AHEM flawless code, lasts forever.  Heck, in a few years, we’ll scrap this entire code base and rewrite from scratch using the fad JS framework of 2020. Moreover, even a task as mundane as refactoring can offer the opportunity to for reflection and even — dare I say — innovation.



Senior engineers might not be so bad

I’ve talked before about my ambivalence toward senior engineers.  As members of the department with 4+ years’ experience, senior engineers often come across as know-it-alls, eager to criticize whatever you do before you’ve even had time to explain it.  No matter how hard you work, how many annoying little bugs you fix, how many features you contribute of your own initiative, in the end nothing you do impresses or surprises them, because they could do your job better and faster anyway.

It’s easy to resent senior engineers — people who are significantly younger and less organized than I am but make significantly more $$ (because, let’s face it, they are significantly more skilled than I am) — but I’ve seen some great sides of senior engineers over the past few months that have softened my critiques.

One of these glimpses happened a few weeks ago.  I was having a conversation with my senior engineer friend Brent about how overwhelmed I feel about next steps in learning computer science — I want to take a couple of classes, but all of them seem to require Python.  After the year-long slog that was learning JS basics, I lamented, how could I commit the time to learn Python?

At this point, my stereotypical senior engineer would have been like, “Yeah, it’s probably out of your reach.  I program fluently in all languages, and 99% of them are so much more better than Python anyway.  Let me further offer some choice critiques of OOP that only I have thought of.”  And then I would have gone back to my downtrodden and discouraged state.

But Brent is not your stereotypical senior engineer.  He took a breath, and said, “Yeah, but you know, once you’ve learned one language, they’re really not that hard to pick up.  I wouldn’t let that stop you.”

In that moment, I felt a newfound capability as the whole world of programming opened up to me.  My thoughts raced: Is it possible that learning Python — learning any language — might not be such a big deal?  What if I can do it without much fuss?  What if I can learn anything I need to learn?

Since that conversation, I’ve been devouring the tutorial and even started a Python-based Data Structures course!  Brent was right — it’s really not that difficult to learn a new language, and the time investment is so much lower than it was for my first language.

But my bigger takeaway from this experience is about reserving judgement until I’ve really given something a good try.  Python terrified me at first because I had it in my head that learning it would be a huge time sink.  It continued to loom over me until I tried it out.  Likewise, senior engineers — who I’d all but written off after a few terrible experiences — turned out to be not all bad and maybe even a little bit good.  It’s all a matter of being open to new experiences and not letting pre-conceived notions get the better of me.

Problem? No problem.

Painful revelation #5473984 since beginning to code: I need better problem-solving habits.  Sure, I’m plenty smart and can use problem solving skills if I really need to, but step-by-step problem-solving is not yet second-nature.

I didn’t realize how sloppy my problem-solving process was until I started school last year.  At that point, I had been doing JS on my own for about 9 months, and my approach to problem solving was as follows:

  1. puzzled stick figureSee a problem
  2. Brainstorm about what could be causing the problem -> {usually no idea}
  3. Fiddle with a few things and look for typos -> {typically creates even more problems}
  4. Get super frustrated
  5. Print out my entire database
  6. Anger-eat a sleeve of Oreos, taking no pleasure in them
  7. Undo everything back to just the one problem
  8. Binge-watch Parks and Rec until I can calm down enough to think about the problem again

Now, having looked on with some brilliant colleagues, I see that there are much less maddening ways to find bugs.  Even though many problems still start out as a ‘black box’ in my mind, I now take a much more scientific approach — something like this:

  1. See a problem.
  2. Distill the problem.  Say what you expect vs. what you are getting, or draw it on paper if it is complicated.  This helps you crystallize the problem in your mind, and sometimes even helps you solve it at this step.
  3. Isolate the problem function(s). This may mean commenting out sections of HTML or JavaScript in order to focus on just one part of the code.
  4. Simplify inputs and outputs.  Sometimes cluttered code or complex variable names can make a problem seem overly complicated.  Separate long conditionals into into multiple lines when you can; replace variable names with simpler names.  (Classic blunder: Just because a function is named “postToApi” doesn’t mean that calling this function will actually post to an API.  Sometimes semantic naming can trip you up by creating an assumption of functionality.)  If your program isn’t logging the object you expected, replace the object with a string like ‘foo’ make sure your log statement is being executed.
  5. Break the problematic part into smaller pieces and run through them one by one.  Split a complicated function into smaller pieces.  You can run each piece individually, then start putting pieces together one by one.  As you add each piece in, you’ll be able to see which addition breaks the combination. (Keep in mind — it may be more than one problem and likely is if you’ve gotten this far…)
  6. Watch EVERYTHING.  Watch each variable in the buggy snippet of code from start to finish using logs or a debugger statement.  See where the variables diverge from what you expected.  The nice thing about debuggers is that they often uncover contributing factors that you might not have suspected.

If all else fails, rewrite from scratch.  Sometimes you hit a point where you’re not making progress by debugging.  This can be caused by a stupid mistake, like a typo that you don’t see, or by a bigger logical flaw.  In either case, sometimes the quickest way to a solution is to re-write one or many parts of your function from scratch, without looking at the original.  This might sound like a cop-out, but you don’t always have time to walk away from a problem 10 times and come back to it; sometimes you just need a clean slate to rethink your approach.

Keep breathing.  Keep eating and drinking.  Go watch Ron Swanson eat a Meat Tornado, or whatever gets your mind in a different space.  An exhausted and frazzled engineer is like a bull in a china shop, perpetuating code problems through little mistakes and oversights, but a happy and healthy engineer is better than the best debugger there is.