Originally authored by Dara Monasch
Late to the Party? Check out the earlier posts in this Series:
Week 2 of Introduction to Systematic Programming focused primarily around How to Design Functions, or the HtDF method. We went over the HtDF Recipe itself and then dove directly into 4 example problems, and discovered lots of interesting tips and tricks for working more accurately and efficiently.
Lesson 1: HtDF Recipe
The purpose of the HtDF Recipe is to “systematize the design of a function” to ensure it is well tested accomplishes its stated purpose. The HtDF Recipe breaks down big problems into smaller, easier to manage problems, which sounds great to me. However, the instructor does make an interesting point here, stating that while this makes really big, complex problems easier to manage, the side effect is that it makes simple problems more complex.
A great tip from this lesson is to always have your Design Recipe “Cheat Sheet” with you when you’re writing your code, so that you can refer to it and make sure you’re on the right path.
Lesson 2: HtDF Details!
After explaining the reasoning behind the HtDF Recipe in Lesson 1, Lesson 2 dives straight into explaining the different elements that make up the HtDF Recipe.
The Signature details what type of data a function consumes and produces. For example, “Number -> Number” would be a Signature for a function that takes multiplies 3x2.
The Purpose gives a succinct description of what the function produces, given what is consumes. I can hear you currently thinking, “How is this different from the Signature?!” Well…. the difference is that the purpose gives context to the Signature, and is intelligible to someone who may not be aware of the original spec of the problem you’re solving. An example of a purpose would be, “Produce 2 times the given number” as opposed to “Number -> Number”.
The Stub is described to be “like scaffolding”; it holds together the structure of your function so that you can run your tests, but it doesn’t actually *do* anything. It must have the correct function name, the correct number of parameters and produce a dummy result of the correct type, but again, no computations should be made in your stub. Following this same example thread, an appropriate stub would be: “(define (double n) 0)”.
The Example/Test was briefly mentioned in the above Stub section, and it is what you’d think, some small QA cases built into your program to assert that it’s working properly! Both Example and Test are used because this portion of the Recipe serves both functions. Most programs will have at least two Tests/Examples. In our example, an appropriate test/example would be “(check-expect (double 3) 6)”.
The Template is a mock function with the correct function name and the right parameter. For the rest of this week, the remainder of the template is simply (…n). Following our example again, the template we would use here would be:
(define (double n)
The Code is what we’ve all been waiting for and I’m sure what those of us beginners all dread, the actual function! One tip that the instructor gives here is to take a copy of the template and expand it, using the examples as models, especially for easier problems.
Testing/Debugging is the last stage (if we’re talking about a linear progression, that is) of the HtDF Recipe. This is exactly what it sounds like… Run your program and hopefully your tests pass! If they don’t… find them, fix them, and try again!
Additional Notes from this Lesson:
- Type names are always capitalized!
- Dr. Racket CHECKS Check-Expects! When you write your Design Recipe the first time, the test should fail because the stub does not actually DO anything. The tests should not pass until you finally write your code.
Lessons 3-6: HtDF Recipe Examples
I decided to group Lessons 3, 4, 5, & 6 together because in Week 2, they’re all examples of how to use the HtDF Recipe. They’re great to watch, but to go over each example in text I don’t think would be very helpful. HOWEVER! I’ve compiled a set of tips from all of these lessons so that you can check out the key points and takeaways, because I believe that this was the point of showing my classmates and myself these examples in the first place.
Takeaway 1 – Make sure your test is composed correctly! If your test fails after you’ve written your code, make sure you crafted the test itself properly before trying to debug your code! A small typo in a test could create hours and hours of work and frustration.
Takeaway 2 – Your template is just your parts list! It’s not a hard and fast rule of how you must compose your function, but it does give you the tools to use, and you can use them more than once!
Takeaway 3 – Don’t forget your image function requirement! (I feel like this is going to come up a LOT…)
Takeaway 4 – Images are sized in pixels, not Numbers, and pixels are always Naturals. Therefore when you’re calculating the size of an image, the Signature should have the result as a Natural, not a Number.
Takeaway 5 – In your Signature, be THE MOST SPECIFIC. This will ensure that your program runs efficiently.
Takeaway 6 – When delivering a Boolean, be explicitly clear what True means, so your function knows how to react.
Takeaway 7 – When crafting your Tests/Examples, really ask yourself how many you need. It may be 2, but it could be more! To help with this, Dr. Racket uses “Code Coverage”, which will take your tests and determine how much of your code is “covered” (or evaluated) by the tests you’ve crafted and executed. This can help you find Boundary Cases (also known as Corner Cases)
This week really emphasized, at least for me, the concept that HtDF truly does make easy problems…. way more difficult. However, I do see the benefit to this design method and I’m eager to get involved in more complex problems and evaluate whether or not the HtDF method really does ease the entire process.
However, what I really did appreciate was that in Lesson 5, the concept of Agile vs. Waterfall programming was discussed, which is something that I find incredibly intriguing. Before that, the HtDF Recipe was being explained as a very linear process, which I can appreciate for simplicity’s sake; however, everything I’ve really learned about programming so far as emphasized the Agile methodology and maintaining flexibility. The instructor for the class talks about making sure that in the event of struggling to get a test to encompass a corner case or figuring out a bug your code, not to worry about going back and making changes not only to the code itself, but to the purpose or signature as well, ensuring that your program truly does cover all of the given specs and produces the most accurate results possible. Love. It.