From Teaching Open Source
Every practicing software developer will have a different opinion about the role of design in software development.
In this chapter, we do not assume that you are a professional software developer -- we assume, instead, that you are still learning, and exploring into the world of open source software development for any number of reasons. Those reasons might be personal (you have a desire to contribute to a particular project), or your interest might be externally motivated (you are a student enrolled in a course that involves interacting with and contributing to an open source community). Regardless, as you approach the authoring of new or modification of existing code, you need to realize that each community will have their own development process, and the role of software design will be more or less obvious depending on how that community likes to collaborate.
Which brings us back to the first sentence of the chapter: everyone has an opinion about how to design code. There are no right answers, as design is a structured creative process. For this reason, we're going to do our best to frame our discussion of the design process in ways that you can reflect and adapt to different projects at different levels of detail as you see fit.
Contents |
[edit] Scope and Scale
It is possible that one developer might think of a "large" project as one that has many thousands of files and millions of lines of code. That would be an experienced developer. If you've never written code before, then being asked to write a program that can print Hello, World! is a large project. The scope and scale of a project is subjective, and we typically employ different processes when designing "in the small" as opposed to designing "in the large."
[edit] Design in the Small
When we are writing small pieces of code, we are typically designing "in the small." For purposes of this chapter, I'll take this to mean the programmer is working with anywhere from 10 to 50 lines of code, and she is concerned about the code being clear and maintainable by other developers.
To be clear, we'll even go one step further: our notion of program design in the small is articulated by Felleisen, Findler, Flatt, and Krishnamurthi in their introductory programming text How to Design Programs, or as it is often abbreviated, HtDP. In the preface you will find a cogent description of a design process (as well as a rationale and motivation for engaging in that process) that every student of programming should study.
In HtDP, the authors outline a six-step process to writing programs. In some contexts, these programs might be called functions, or they might be called procedures, or perhaps methods. Felleisen et al. are concerned about helping programmers learn good habits for writing understandable and maintainable code, and their process starts with the smallest units of code possible. Their process is described as follows:
- the description of the class of problem data;
- the informal specification of a program's behavior;
- the illustration of the behavior with examples;
- the development of a program template or layout;
- the transformation of the template into a complete definition; and
- the discovery of errors through testing.
Lets take a look at what it looks like when this recipe is applied. Then, we'll look at some code from a popular open source project, and demonstrate what a disaster the code is when developers fail to apply any kind of principled approach to "design in the small."
[edit] Demonstrating the Design Recipe
We'll choose a rather arbitrary problem -- adding two numbers -- and demonstrate what the HtDP design recipe looks like.
[edit] Description of the class of problem data
Before writing any code, you must understand the data that code will operate on. Although apparently trivial, adding two numbers can become incredibly complex. In the programming language Javascript, we would say that the two inputs were of the type number, and the return value was of type number. Following the design recipe, we would be encouraged to write the following:
// CONTRACT // addTwoNumbers : number number -> number
Here, I've given the function a name (addTwoNumbers()) and indicated it has two inputs, and returns (->) a number. While it is possible to write code in Javascript that tells you whether a number is an integer or has a fractional component, Javascript (on the surface) treats all numbers (whole or fractional) the same. Languages like Java and C (for example) take a different approach, and have distinct types (int and double) for these different "kinds" of numbers.
There are many reasons we might advocate for this simple, but critical, comment. One is that, as the designer of this program, we must first understand the kinds of data our function will consume, and what it will return. If you cannot do that, then you should probably not start hacking code. Many students of programming assume they'll "figure it out as they go," but we're talking about design, which implies that we're going to think, not hack.
Another reason that we do this is to help future developers understand what kind of data our function is expecting. If someone were to pass a string (or some other kind of data) to our function, it would likely fail. In a language like Javascript, we need to provide some kind of hint to the developer what kinds (or types) of inputs our function expects. As we'll see shortly, many open source projects that use Javascript provide no such help to the developer, making it very difficult to safely/reliably use and/or extend large codebases written in this language.
[edit] Informal specification of a program's behavior
In the case of the function addTwoNumbers, this is simple:
// CONTRACT // addTwoNumbers : number number -> number // PURPOSE // Consume two numbers and return their sum.
If you cannot write a simple statement as to what a function does, then there is a good chance that 1. it is going to be too big and too complex to maintain, or 2. you don't really understand what you're trying to do, and should probably spend more time thinking about your problem.
[edit] Illustrate behavior with examples
Once you understand the inputs and outputs of your program, and you know what it should do, you should be able to write some examples. You might even call these tests, in some ways. Our code might be extended to look like this:
// CONTRACT // addTwoNumbers : number number -> number // PURPOSE // Consume two numbers and return their sum. addTwoNumbers(0,0) == 0 addTwoNumbers(3,5) == 8 addTwoNumbers(-1,1) == 0
FIXME Still in progress, and I would like to refer to a Javascript editor online where students can try this out as they go. Mozilla Skywriter embedded in a TOS wiki page?
FIXME: Everything down here was old thinking, and may or may not come back in.
provide you with an overview of some of the processes you might make use of or encounter as you begin exploring the world of free and open source software development.
- The Explorers
- Hack and Slash
- Fork and Go
- The Canon
- Waterfall
- eXtreme Programming
- Agile