Software Design by Example
Skip to main content
Software Design by Example
A tool-based introduction with Python
The best way to learn design in any field is to study examples,<br>and the most approachable examples are ones that readers are already familiar with.<br>These lessons therefore build small versions<br>of tools that programmers use every day<br>to show how experienced software designers think.<br>Along the way,<br>they introduce some fundamental ideas in computer science<br>that many self-taught programmers haven't encountered.<br>We hope these lessons will help you design better software yourself,<br>and that if you know how programming tools work,<br>you'll be more likely to use them<br>and better able to use them well.
Chapters
Introduction
Objects and Classes
Finding Duplicate Files
Matching Patterns
Parsing Text
Running Tests
An Interpreter
Functions and Closures
Protocols
A File Archiver
An HTML Validator
A Template Expander
A Code Linter
Page Layout
Performance Profiling
Object Persistence
Binary Data
A Database
A Build Manager
A Package Manager
Transferring Files
Serving Web Pages
A File Viewer
Undo and Redo
A Virtual Machine
A Debugger
Observers
Generating Documentation
A File Cache
Concurrency
Conclusion
Appendices
License
Code of Conduct
Contributing
Bibliography
Glossary
Syllabus
Bonus Material
In Detail
Chapter 1: Introduction<br>The best way to learn design is to study examples, and the best programs to use as examples are the ones programmers use every day. These lessons therefore build small versions of tools that programmers use every day to show how experienced software designers think. Along the way, they introduce some fundamental ideas in computer science that many self-taught programmers haven't encountered. The lessons assume readers can write small programs and want to write larger ones, or are looking for material to use in software design classes that they teach.<br>Chapter 2: Objects and Classes<br>Object-oriented programming was invented to solve two problems: what is a natural way to represent real-world "things" in code, and how can we organize that code so that it's easiser to understand, test, and extend? This chapter shows how object-oriented systems solve those problems by implementing a very simple object system using simpler data structures.<br>Chapter 3: Finding Duplicate Files<br>The naïve way to find duplicated files is to compare each file to all the others, but that is unworkably slow for large sets of files. A better approach is to generate a short label that depends only on the file's contents so that we only need to compare files with the same label. This idea is the basis of many real-world applications, including the cryptographic systems used for secure online communication.<br>Chapter 4: Matching Patterns<br>Pattern matching is ubiquitous in computer programs. Whether we are selecting a set of files to open or finding names and email addresses inside those files, we need an efficient way to find matches for complex patterns. This chapter therefore implements the filename matching used in the Unix shell to show how more complicated tools like regular expressions works.<br>Chapter 5: Parsing Text<br>A parser turns text that's easy for a human being to read into a data structure that a computer can work with. The complete parser for a language like Python can be very complex, but this chapter illustrates the key ideas by building a parser for the simple filename matching patterns implemented in the previous chapter.<br>Chapter 6: Running Tests<br>Every programming language has tools to collect tests, run them, and report their results. This chapter shows how such tools are built, both to help programmers use them more effectively, and to illustrate the single most important idea in this book: that programs are just another kind of data.<br>Chapter 7: An Interpreter<br>A program in memory is just a data structure, each of whose elements triggers some operation in the interpreter that's executing it. This chapter builds a very simple interpreter to show how this process works, and to show that we can evaluate the quality of a program's design by asking how extensible it is.<br>Chapter 8: Functions and Closures<br>This chapter extends the little interpreter of the previous one to allow users to define functions of their own. By doing so, it shows that the way programs handle variable scope is a design choice, and that the use of a particular technique called closures enables programs written in Python (and other modern programming languages) to encapsulate information in useful ways.<br>Chapter 9: Protocols<br>This chapter starts by showing how we can simplify testing by temporarily replacing real functions with ones that return predictable values, then uses our need to do that to motivate discussion of ways that programmers can hook their own code into the Python interpreter. Unlike other chapters in this book, this one focuses on Python itself rather than the things we can build with...