loading...
Cover image for Wishful Coding

Wishful Coding

rpalo profile image Ryan Palo Updated on ・3 min read

Cover Image credit to René de Ruijter, at least, as far as I can tell.

I've been doing the Advent of Code 2017 challenge this Advent, and I noticed that as I've been working on some of the harder challenges (number spirals, amirite?) I've started doing something that seems to really help me stay locked in to the problem. It's definitely not something groundbreaking, but I figured that I'd share it, in case it helps somebody else.

The Problem: Short Attention Spans and --

Stop me if this scenario seems like a personal attack:

You've just been handed a problem/assignment. You know where you need to start, but as you begin to type the first outlines of your code, one of the things you need to do next pops into your head. You quickly jump over and create a new file for that and try to get a brief sketch down so you won't forget later. As you're doing that, you realize that the new thing that you're adding will need a test case, so you hop over and "just real quick" jot down the test case for what you were working on. You run your tests to make sure everything's failing as expected, but you forgot to configure your tests and the output is all ugly and who could continue to work in that kind of environment? You're not a barbarian after all! And then two hours later… wait a minute, what was I originally working on?

Some of the solution is just self-discipline -- forcing yourself to finish what you're working on before you start the next thing. However, one place I find these mental self-interruptions especially problematic is when I'm trying to solve a big problem and have to keep worrying about little parts of the solution. This is where my tip can come in handy.

One Solution: Use Methods You Wish You Had

This is probably best described with an example.

Let's say you're writing a script that controls an automatic treat dispenser for your dog.

My dog Willy

This is Willy. He's a very good boy.

On your first pass through the code, you might write something like this.

def train(dogs)
  dogs.each do |dog|
    if dog. # Pause here

Now you might think to yourself, "Shoot! Now I need to figure out when these dogs should get treats!" And just like that, your train of thought for the rest of the high-level function is gone.

Here's my solution.

I propose that you confidently carry on like nothing is wrong, and use the methods that you hope Future-You will write.

def train(dogs)
  dogs.each do |dog|
    if dog.good_boy?
      dog.pat!
      give_treat(dog)
      @treats -= 1
    end
  end
end

"But Ryan! We haven't written methods like good_boy?, pat!, or give_treat yet." EXACTLY. That's a problem for Future-Us. The important thing now is to keep you in that flow state and make sure you get your whole thought on the screen before you forget what you're supposed to be doing. We'll come back and fill in the cracks later.

(For those of you that are really concerned, here's how good_boy? is implemented):

class Dog
  # ...
  def good_boy?
    true
  end
end

😬

Wrap Up

So that's the tip! Write the code, and when you come to a section that seems like it might bog you down even a little bit, just pretend you already have a method for that. A secondary benefit of this is that it helps you identify where good places to pull code into separate methods are. You can always come back and clean things up after everything's working a little better.

Got any other pro-tips for blocking out the distractions? Let me know — I'd love to hear them!


Originally posted on assert_not magic?

Posted on by:

rpalo profile

Ryan Palo

@rpalo

Ryan is an engineer in the Sacramento Area with a focus in Python, Ruby, and Rust. Bash/Python Exercism mentor. Coding, physics, calculus, music, woodworking. Message me on DEV!

Discussion

markdown guide
 

This is actually really good advice!

For people who think a little differently (like me), it works the other way around, too. I think bottom-up: from the bottom of the eventual call stack upward. Thus, I will plan out my approach, sometimes stub out my top-level function like you did, and then begin to build the lowest level functions first.

By way of example, when I wrote Omission, I followed this basic workflow:

  1. Create bare minimum to display a message - basically a modified "hello, world!" I did not start with the UI yet!

  2. On paper, jot down the eventual call order. I knew the game would need the content generator for anything to work, so I'd start there. I could temporarily hardcode source content in, instead of loading from a file, so I did that. I got the program to just display some generated content.

  3. Next I added code to load content from a file. Nothing fancy here, I was only wanting to replace the hardcoded source content with material from a text file.

  4. Now I needed interaction, so I wrote the code to allow a user to answer, and for the game to verify that answer. Again, I was still only using a text-based interface. Once I had that, I added scoring. I now had a technically functional command line game.

  5. Now I added the timing-based functions. I didn't need to see any fancy timers, just to make sure the score reflected how long I took to answer.

  6. To get decent further progress, I needed the GUI, so I constructed just the gameplay screen. Don't get hung up on menus at the start!
    I only allowed myself to get the interface to work with the game as it existed. Once that worked...

  7. I began to tweak and improve the gameplay and interface to be closer to what I imagined, working in much the same manner as before: plan it out, write the lowest part first, and work my way up.

  8. Finally, I went back and added the other functionality: menus, additional gameplay modes, etc.

I'm oversimplifying, obviously, but you get the idea.

By working in this manner, I had the advantage that all my code was technically correct as I worked.

Now, a DISCLAIMER: If you think in the top-down described in the article, you probably shouldn't use my workflow. If you aren't a bottom-up programmer, this method is likely only going to confuse you. I intended this only for people who think like me. I merely wanted to show that the author's basic approach works in either direction.

 

That’s a really good juxtaposition of the two methods. It is interesting seeing how much they have in common!

 

This is great. I've gotten to doing this but hadn't really formalized it. I'm now going to practice this with a lot more intention.

 
 

Great tip! I also do that all the time. When I'm focused and deep in the domain I don't want to jump around in the code or between the files. No, I want to write a function, component, ... in one go. That way it all makes sense later when I or someone else will read it.

In some of my programs this programming style has lead to two layers of code:

  • domain layer, here's where I've coded along the requirements in one go and everybody (with domain knowledge) should be able to read it like a book
  • library / helper layer, here are the technical details, you don't need to look here in order to understand what the program does, but most of the bugs are in here, so this is where to look if you want to know HOW it's done

However it's not always a good idea to introduce these layers into the structure of a given framework, because most frameworks give you a (more complex, more technical) structure already. Let's take MVC for example. In order to keep the controllers lean, your domain code should be in the models. But do you need to split your model layer into a domain layer and a library layer? Maybe. But if you need just a few functions in the library / helper layer a simple helper library (not part of the model layer) might be enough. Or think about concerns - normally they should contain domain code (shared behaviour between multiple models), but it's also a good place to fully implement your functions in order to keep them out of your models, so you can use them as a library layer as well.

 

I've been doing this for a while now and my code has been noticeably cleaner.

This is also a great way to introduce the idea of methods to complete beginners. I used this recently in a Java intro class.

In the beginning we pretended many "complicated" methods already existed (readNumber(), isPrime(int), etc.), but as we learned new things, we started filling them in. That way, we could focus on the program logic before learning about all the language specifics (which is a very good thing for when they switch to a different language).

 

That’s really cool! I hadn’t thought about using this idea while teaching. I can see how that would make functions/methods more natural

 

Just in case you didn’t get enough #goodboye
Another picture of Willy

 
 

This to me is the purpose of pseudocode. Planning out what you want to happen, without worrying about all the nitty-gritty details to start.

I do something similar when I code, especially if it's a larger problem. Often, I use comments, to first put down my thoughts similar to "do this, then if this, do that, else do this." After, I can start coding by tackling one comment at a time (which is a lot less daunting). And, usually each comment a good place to test that it's working as expected.

 

"Use Methods You Wish You Had". This is exactly the key. We try so often to do what we want with what we have, instead of thinking what we wish we had.

 

I've heard this referred to as error driven development. I try to use it when I remember. F2 and alt+Enter in IntelliJ help speed this up as well! Goto next error and the "magical fix my code" key combo.

This also often leads to cleaner code, i.e. methods with code at one level of abstraction, rather than a mix (and often mess)

 

Yep! I have had more than a few ‘rake test’ /NoMethodError/head-desk moments.

 
 

Great advise, thanks 👍

What if I told you that I sometimes draw the logo of my app, and write some documentation of possible usage before I even write a single line of code? I hate it, but this how I work :/

P.S. Logo design usually takes forever to get it done because I'm not even designer hahaha

 

Cool technique. I recently started planning on tools like creately, before programming. I try and imagine the complete solution set on the digital whiteboard, and then run through it to get out the problems. After many iterations, I arrive at a sensible looking design. Then I start implementing the code bottom up, with TDD. Thinking this ways saves me a lot of time and effort, yet it results in better quality software.

 

Cool tip! I hadn’t heard of creately, I’ll have to check it out.

 

This method sounds very much like how you would do TDD. You write your tests before you write any code and your tests thus become your documentation and prototyping.

Also, some tools have built in support for this. Take Visual Studio for example. It gives you keyboard shortcuts to quickly create new types and methods as you type your code.

 

That's what Fred Brooks wrote about in Mythical man-month. He proposed to build a higher-level skeleton first, the one that just compiles but implements no useful behavior. Then delving deeper and deeper, considering fail scenarios and edge cases. Though I guess pretty much everybody has came to this approach already by the time he or she has read the book.

 

Neat! I'll have to check that out. He probably spells it out more clearly and concretely than what I have in my head, so that should be helpful.

 

Sometimes I won't want the code to break "compile" so I'll just comment the wishful code, but I always will make a runtime failure if the function isn't complete (e.g. return False, raise exception, etc.)

it's always good to exercise failure paths early

 

Very good article!

It's also what we should do when doing TDD (which is not often enough, at least for me :D): write the interface, check results and then write the code to make the test pass, one step at the time.

 

This is great! It also plays nicely with the practices of TDD/BDD where you write the test and then the code. Being able to “use” the API (even just mocking it out) makes it very clear on what it should do and helps you implement it.

 

I often do this but I take one more step back; Write the overall method that will do the job but fill it with comments indicating my intentions before I actually write the code. I find this really helps make you think about what you need before you commit to decided on the specifics of what you're going to implement.

For something really trivial like your example above, writing it in code works but in more complicated situations it can be another helpful trick to break a problem down.

 

I love this approach 🙌

Personally, I think this helps a lot to organize the code in reasonable levels of abstraction - if I think in terms of high-level methods or functions that I’d like to have, I’ll be less tempted to reach for the file system or make an HTTP request when I should be thinking in terms of my business classes. Getting to the lower levels usually comes naturally out of filling in the missing methods.

 

Yep! That’s what I do by profession. I work at ProtoQuick. We make a lot of prototypes and even production. One of the funnest molds I designed recently was for the ProFroster, for bakers!

 

This is profound wisdom. Future me appreciates this.

 

Awesome. We all do that. Making this as an habit is what really requires

 

Just started real work on a big project I've been wanting to make for while now, and this is really helping! Great article :D

 

Solid punchline before the wrap up.

Also, great tip!

 

Thanks! Glad you liked it.