I'm proud to say I published my first Ruby Gem the other day, which I created from scratch! Reflecting on the project as a whole, I realized I learned a lot about the process of creating a working program (albeit a simple one), so I'd like to share. I think these ideas could be especially helpful other beginners like me.
The gem, by the way, is a CLI app that lets you find recipes by scraping data from an outside source (link to source code, etc. at end of post). Not revolutionary, but it was still fun :)
Here are five points that I learned which helped me think through the coding process:
Because I was used to writing code along with a tutorial or programs limited to a few lines of code, I had really taken the value of writing out a plan for granted.
In my head, I knew what I wanted to build, so why would I need to waste time writing it down? It turns out that my written plan was one of my most valuable resources. It helped me figure out exactly where to get started, what kind of classes and methods I might need, and how I needed to let the users interact with my program. Without a plan, I’m pretty sure I would have been staring at an empty screen scratching my head.
I don’t think the plan needs to be super detailed, but just enough so you imagine the entire flow of the program (at least this is what I did for a small program like mine). I wrote my plan by imagining how a user would be interacting with the program and exactly what the program would do based on the user’s actions (e.g. Choosing “search for a recipe” would prompt the user to input a keyword, which would then put out a list of recipes that they could choose from). I didn’t include anything technical like “data would be fetched by the scraper,” rather I let the plan guide me as I wrote the code.
Of course, if there are specific specs that need to be fulfilled, I think think they could also be included in a coding plan or perhaps in a separate spec sheet.
I had read a lot about pseudocode in Code Complete. The author is a big advocate of using pseudocode and it definitely helped me think out the more complex parts of my code. The basic idea is to write out exactly what you want a certain section of code to do in plain English before writing any actual code. I guess it’s like a mini-plan that you write out inside each method, class, etc. That will then guide you through any complicated logic and the technicalities of the exact lines of code you need to write.
I’d definitely say it’s much easier to think about the code in plain English opposed to jumping straight into the technical details and logic of, say, a complicated loop. Each line of pseudocode can be translated into the respective working code and furthermore, pseudocode generally makes excellent comments, which make your code easier to understand and manage in the future.
Another thing I want to try in the future is drawing out diagrams when I need to visualize how classes, methods, and data are interconnected with each other. I found myself getting frustrated trying to figure out why the data I was trying to pass around in my program wasn’t getting handled properly. Instead blindly trying to fix this-and-that, I think it would have helped to actually draw it out so I could see with my eyes what was actually going on.
This really helped me move through my gem project without getting stalled or caught up in code I didn’t need until later. Obviously you can’t write out your entire program in one step, but you still need something to work with, right? If you don’t know where to start or get stuck, try breaking up things up into smaller pieces.
For example, work on one method at a time and get it to work and output exactly what you need before trying to weave it into the rest of the code. Or, for a complicated nested loop, start from the inside and work yourself out, getting each portion to work before moving one layer out.
Fake data can used if you need/want to get a certain method or class working, but the other part of your program that handles, creates, or passes in the data isn’t finished yet.
For my CLI gem, I decided to get the command line interface logic working before coding my class (a Recipe class and a Scraper class) so I could at least run the program in the command line. The CLI needed to deal with user input and output data accordingly, such as lists of recipes and the recipe details. To make sure the CLI logic was working properly first, I just faked the recipe data by writing it out by hand and used that while testing the CLI.
Afterwards when I was working on getting the Recipe class set up, I did the same thing: I didn’t have real data because the scraper wasn’t finished, but I wanted to make sure the Recipe class could actually process the data first, so I wrote some recipe data by hand and used it build out the Recipe class’s methods. Once that was working, all I needed to do was get real data with the Scraper class and then the rest of the program would just work.
Separating each “job” into different methods and classes is one of the fundamentals of OOP and programming in general, but I also find that it makes it easier to code, organize your program, and goes hand-in-hand with working in small steps. Because each method supposedly only handles one job, it keeps the code inside each method less complicated and shorter, packaging it up into a neat little box. These “boxes” can then be easily used within other methods or classes without needing to repeat code (stay DRY!).
I also love to use this technique for abstracting out code when the code inside of a single method is getting too complicated or ugly. For example, moving a complex calculation or data processing loop into its own method. Or placing often-used operations into a well-named method that would make your code easier to read—These methods don’t really need to involve complicated code, but I feel it's often worth separating out certain parts to improve the readability of the code.
Last but not least, I found that writing about my coding process has greatly helped me with learning retention and deeper understanding. Writing about what you’re doing requires you to really think about why you did what you did and look up things you don’t completely understand in order to explain them. I also love the idea that my blog posts may one day help someone else going through the same experience as me. Another huge advantage is that your blogs (or notes) become your very own reference manual for later on down the road!
I've worked with applications that use test-driven development, usually Rspec, and I think writing tests first would also go hand-in-hand with planning out a program and working in smalls steps/fake data. I actually don't know how to write tests quite yet, but it's on my list of things to learn.
For in-depth reading on how I worked through creating a CLI gem, you can see my "Creating My First CLI Gem" series on my blog: