Systematic Program Design
January 3rd, 2024
Retrospective
Before taking this course, I assumed that a skilled intuition for designing programs could only be developed though exposure and practice. Professor Gregor Kiczales' instruction in Systematic Program Design (CPSC110) has managed to convince me otherwise. During the course, Kiczales shows how simple design techniques can be built upon one another to write functions for increasingly complex programs. He constantly expresses the importance of learning by doing and encourages students to work ahead of him to prove their growing intuition for program design. At first, I disliked the course's slow pacing. Over time however, I came to realize that this slow pace allows him to methodically step through the thought-process needed for designing functions. CPSC110 emphasizes the importance of working through the design process correctly rather than quickly.
My only exposure to Racket before taking this course was listening to my CS/DS-major friends complain about how terrible it is. After heavy exposure to the language myself, I can't say I disagree. However, I did find that Racket excels at teaching systematic program design. Racket’s simplicity compared to other programming languages forces you to start from first principles and not rely on higher-level program abstractions to solve problems. Consequently, barely more than a single lecture is spent getting comfortable with Racket, which allows students to focus less on the language and more on systematic program design.
What I Learned
This course is valuable in the fact that it teaches students to design programs in a systematic manner. You are first taught the best practices to convert real world information into data definitions implemented in code. Kiczales details how these "data definitions" can be used to create templates for functions that operate on those data definitions. At first I was skeptical that these templates were a one-size-fits-all skeleton for any function. Despite my skepticism, the course proves through example that these templates can be adapted to any function necessary. Although it is not shown in the course, the systematic program design process is built on top of a very solid foundation of computer science theory. CPSC110's goal is, as Kiczales says, to break program design down to a science, rather than typing code and hoping for the best.
Dislikes
The DrRacket IDE is slow and gaudy, and many keywords in the Racket language are oddly cryptic. Writing a "big bang" function for my "world program" was just one of many cases where I pondered if Racket's developers thought it more important to be unique than practical. In addition to this, every expression in Racket is enclosed in parentheses. This came to its natural conclusion when I found myself nesting up to eight sets of parentheses for a program. Although this issue can be partially remedied by careful and consistent indentation, excessive parentheses makes the program design process a nightmare. I believe that the onus for designing readable code should fall on the designer(s) of a language's syntax first and foremost. Programmers should not be limited by a programming language when trying to write readable code.
While I still believe that programming languages design should prioritize readability, my opinions about Racket have changed significantly after taking the University of Washington Seattle’s Programming Languages course. You can read my updated thoughts on Racket in Perhaps I Was Too Hard on Racket (Bonus Segment)
Another major gripe with the course is that the final project is off-limits to students that do not follow the paid track. I would have liked the opportunity to use the skills I developed through the second half of the course in a cumulative exercise. Fortunately, the practice problems and midterm project are available for free, so I don't feel that I missed out on much.
Suggestions for Students
Get comfortable using recursion. A purely functional programming language means no iteration, which means that you need to build a deep understanding of recursive programming to succeed.
Key Takeaways
- Systematic design uses higher-level design concepts to break down complicated problems to a point where one can solve them simply.
- Identifying the structure of information in a problem is a key step in program design.
- Unit tests should be made before writing the body of a function, as this gives you concrete examples for what a function should output.
- Given a base case, trust that the natural recursion in a program will work as expected.
Table of Contents