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 notice...
For further actions, you may consider blocking this person and/or reporting abuse
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:
Create bare minimum to display a message - basically a modified "hello, world!" I did not start with the UI yet!
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.
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.
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.
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.
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...
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.
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.
dude!
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:
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
He's a goodbwoy 😍💙🙌
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.
dude!
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.
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.
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.
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.
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.
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.
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
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
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.
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!
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
This is profound wisdom. Future me appreciates this.
Awesome. We all do that. Making this as an habit is what really requires
Solid punchline before the wrap up.
Also, great tip!
Thanks! Glad you liked it.