A Philosophy Of Software Design John Ousterhout
download
https://ebookbell.com/product/a-philosophy-of-software-design-
john-ousterhout-42507470
Explore and download more ebooks at ebookbell.com
Here are some recommended products that we believe you will be
interested in. You can click the link to download.
A Philosophy Of Software Design Ousterhout John
https://ebookbell.com/product/a-philosophy-of-software-design-
ousterhout-john-49563888
A Philosophy Of Software Design 2nd Edition Ousterhout John
https://ebookbell.com/product/a-philosophy-of-software-design-2nd-
edition-ousterhout-john-37173268
A Philosophy Of Software Design 2nd Edition 2nd Edition John K
Ousterhout
https://ebookbell.com/product/a-philosophy-of-software-design-2nd-
edition-2nd-edition-john-k-ousterhout-53309146
Prospective Philosophy Of Software A Simondonian Study Coline
Ferrarato
https://ebookbell.com/product/prospective-philosophy-of-software-a-
simondonian-study-coline-ferrarato-10658472
A Philosophy Of Gun Violence Alan J Reid
https://ebookbell.com/product/a-philosophy-of-gun-violence-alan-j-
reid-44898478
A Philosophy Of Faith Belief Truth And Varieties Of Commitment Finlay
Malcolm
https://ebookbell.com/product/a-philosophy-of-faith-belief-truth-and-
varieties-of-commitment-finlay-malcolm-46348350
A Philosophy Of Struggle The Leonard Harris Reader Leonard Harris
https://ebookbell.com/product/a-philosophy-of-struggle-the-leonard-
harris-reader-leonard-harris-46669104
A Philosophy Of Sacred Nature Leon Niemoczynski Nam T Nguyen
https://ebookbell.com/product/a-philosophy-of-sacred-nature-leon-
niemoczynski-nam-t-nguyen-49438154
A Philosophy Of Comedy On Stage And Screenyou Have To Be There Shaun
May
https://ebookbell.com/product/a-philosophy-of-comedy-on-stage-and-
screenyou-have-to-be-there-shaun-may-50219166
A Philosophy Of Software Design John Ousterhout
A Philosophy Of Software Design John Ousterhout
A Philosophy of Software Design
John Ousterhout
Stanford University
A Philosophy of Software Design
by John Ousterhout
Copyright © 2018 John K. Ousterhout.
All rights reserved. No part of this book may be reproduced, in any form or by any means, without
permission in writing from the author.
Published by Yaknyam Press, Palo Alto, CA.
Cover design by Pete Nguyen and Shirin Oreizy (www.hellonextstep.com).
Printing History:
April 2018: First Edition (v1.0)
November 2018: First Edition (v1.01)
ISBN 978-1-7321022-0-0
Digital book(s) (epub and mobi) produced by Booknook.biz.
Contents
Preface
1 Introduction
1.1 How to use this book
2 The Nature of Complexity
2.1 Complexity defined
2.2 Symptoms of complexity
2.3 Causes of complexity
2.4 Complexity is incremental
2.5 Conclusion
3 Working Code Isn’t Enough
3.1 Tactical programming
3.2 Strategic programming
3.3 How much to invest?
3.4 Startups and investment
3.5 Conclusion
4 Modules Should Be Deep
4.1 Modular design
4.2 What’s in an interface?
4.3 Abstractions
4.4 Deep modules
4.5 Shallow modules
4.6 Classitis
4.7 Examples: Java and Unix I/O
4.8 Conclusion
5 Information Hiding (and Leakage)
5.1 Information hiding
5.2 Information leakage
5.3 Temporal decomposition
5.4 Example: HTTP server
5.5 Example: too many classes
5.6 Example: HTTP parameter handling
5.7 Example: defaults in HTTP responses
5.8 Information hiding within a class
5.9 Taking it too far
5.10 Conclusion
6 General-Purpose Modules are Deeper
6.1 Make classes somewhat general-purpose
6.2 Example: storing text for an editor
6.3 A more general-purpose API
6.4 Generality leads to better information hiding
6.5 Questions to ask yourself
6.6 Conclusion
7 Different Layer, Different Abstraction
7.1 Pass-through methods
7.2 When is interface duplication OK?
7.3 Decorators
7.4 Interface versus implementation
7.5 Pass-through variables
7.6 Conclusion
8 Pull Complexity Downwards
8.1 Example: editor text class
8.2 Example: configuration parameters
8.3 Taking it too far
8.4 Conclusion
9 Better Together Or Better Apart?
9.1 Bring together if information is shared
9.2 Bring together if it will simplify the interface
9.3 Bring together to eliminate duplication
9.4 Separate general-purpose and special-purpose code
9.5 Example: insertion cursor and selection
9.6 Example: separate class for logging
9.7 Example: editor undo mechanism
9.8 Splitting and joining methods
9.9 Conclusion
10 Define Errors Out Of Existence
10.1 Why exceptions add complexity
10.2 Too many exceptions
10.3 Define errors out of existence
10.4 Example: file deletion in Windows
10.5 Example: Java substring method
10.6 Mask exceptions
10.7 Exception aggregation
10.8 Just crash?
10.9 Design special cases out of existence
10.10 Taking it too far
10.11 Conclusion
11 Design it Twice
12 Why Write Comments? The Four Excuses
12.1 Good code is self-documenting
12.2 I don’t have time to write comments
12.3 Comments get out of date and become misleading
12.4 All the comments I have seen are worthless
12.5 Benefits of well-written comments
13 Comments Should Describe Things that Aren’t Obvious from the Code
13.1 Pick conventions
13.2 Don’t repeat the code
13.3 Lower-level comments add precision
13.4 Higher-level comments enhance intuition
13.5 Interface documentation
13.6 Implementation comments: what and why, not how
13.7 Cross-module design decisions
13.8 Conclusion
13.9 Answers to questions from Section 13.5
14 Choosing Names
14.1 Example: bad names cause bugs
14.2 Create an image
14.3 Names should be precise
14.4 Use names consistently
14.5 A different opinion: Go style guide
14.6 Conclusion
15 Write The Comments First
15.1 Delayed comments are bad comments
15.2 Write the comments first
15.3 Comments are a design tool
15.4 Early comments are fun comments
15.5 Are early comments expensive?
15.6 Conclusion
16 Modifying Existing Code
16.1 Stay strategic
16.2 Maintaining comments: keep the comments near the code
16.3 Comments belong in the code, not the commit log
16.4 Maintaining comments: avoid duplication
16.5 Maintaining comments: check the diffs
16.6 Higher-level comments are easier to maintain
17 Consistency
17.1 Examples of consistency
17.2 Ensuring consistency
17.3 Taking it too far
17.4 Conclusion
18 Code Should be Obvious
18.1 Things that make code more obvious
18.2 Things that make code less obvious
18.3 Conclusion
19 Software Trends
19.1 Object-oriented programming and inheritance
19.2 Agile development
19.3 Unit tests
19.4 Test-driven development
19.5 Design patterns
19.6 Getters and setters
19.7 Conclusion
20 Designing for Performance
20.1 How to think about performance
20.2 Measure before modifying
20.3 Design around the critical path
20.4 An example: RAMCloud Buffers
20.5 Conclusion
21 Conclusion
Index
Summary of Design Principles
Summary of Red Flags
Preface
People have been writing programs for electronic computers for more than 80
years, but there has been surprisingly little conversation about how to design
those programs or what good programs should look like. There has been
considerable discussion about software development processes such as agile
development and about development tools such as debuggers, version control
systems, and test coverage tools. There has also been extensive analysis of
programming techniques such as object-oriented programming and functional
programming, and of design patterns and algorithms. All of these discussions
have been valuable, but the core problem of software design is still largely
untouched. David Parnas’ classic paper “On the Criteria to be used in
Decomposing Systems into Modules” appeared in 1971, but the state of the
art in software design has not progressed much beyond that paper in the
ensuing 45 years.
The most fundamental problem in computer science is problem
decomposition: how to take a complex problem and divide it up into pieces
that can be solved independently. Problem decomposition is the central
design task that programmers face every day, and yet, other than the work
described here, I have not been able to identify a single class in any
university where problem decomposition is a central topic. We teach for
loops and object-oriented programming, but not software design.
In addition, there is a huge variation in quality and productivity among
programmers, but we have made little attempt to understand what makes the
best programmers so much better or to teach those skills in our classes. I have
talked with several people I consider to be great programmers, but most of
them had difficulty articulating specific techniques that give them their
advantage. Many people assume that software design skill is an innate talent
that cannot be taught. However, there is quite a bit of scientific evidence that
outstanding performance in many fields is related more to high-quality
practice than innate ability (see, for example, Talent is Overrated by Geoff
Colvin).
For many years these issues have perplexed and frustrated me. I have
wondered whether software design can be taught, and I have hypothesized
that design skill is what separates great programmers from average ones. I
finally decided that the only way to answer these questions was to attempt to
teach a course on software design. The result is CS 190 at Stanford
University. In this class I put forth a set of principles of software design.
Students then work through a series of projects to assimilate and practice the
principles. The class is taught in a fashion similar to a traditional English
writing class. In an English class, students use an iterative process where they
write a draft, get feedback, and then rewrite to make improvements. In CS
190, students develop a substantial piece of software from scratch. We then
go through extensive code reviews to identify design problems, and students
revise their projects to fix the problems. This allows students to see how their
code can be improved by applying design principles.
I have now taught the software design class three times, and this book is
based on the design principles that emerged from the class. The principles are
fairly high level and border on the philosophical (“Define errors out of
existence”), so it is hard for students to understand the ideas in the abstract.
Students learn best by writing code, making mistakes, and then seeing how
their mistakes and the subsequent fixes relate to the principles.
At this point you may well be wondering: what makes me think I know
all the answers about software design? To be honest, I don’t. There were no
classes on software design when I learned to program, and I never had a
mentor to teach me design principles. At the time I learned to program, code
reviews were virtually nonexistent. My ideas about software design come
from personal experience writing and reading code. Over my career I have
written about 250,000 lines of code in a variety of languages. I’ve worked on
teams that created three operating systems from scratch, multiple file and
storage systems, infrastructure tools such as debuggers, build systems, and
GUI toolkits, a scripting language, and interactive editors for text, drawings,
presentations, and integrated circuits. Along the way I’ve experienced
firsthand the problems of large systems and experimented with various
design techniques. In addition, I’ve read a considerable amount of code
written by other people, which has exposed me to a variety of approaches,
both good and bad.
Out of all of this experience, I’ve tried to extract common threads, both
about mistakes to avoid and techniques to use. This book is a reflection of my
experiences: every problem described here is one that I have experienced
personally, and every suggested technique is one that I have used
successfully in my own coding.
I don’t expect this book to be the final word on software design; I’m sure
there are valuable techniques that I’ve missed, and some of my suggestions
may turn out to be bad ideas in the long run. However, I hope that the book
will start a conversation about software design. Compare the ideas in this
book with your own experiences and decide for yourself whether the
approaches described here really do reduce software complexity. This book is
an opinion piece, so some readers will disagree with some of my suggestions.
If you do disagree, try to understand why. I’m interested in hearing about
things that work for you, things that don’t work, and any other ideas you may
have about software design. I hope that the ensuing conversations will
improve our collective understanding of software design. I will incorporate
what I learn in future editions of this book.
The best way to communicate with me about the book is to send email to
the following address:
software-design-book@googlegroups.com
I’m interested in hearing specific feedback about the book, such as bugs or
suggestions for improvement, as well as general thoughts and experiences
related to software design. I’m particularly interested in compelling examples
that I can use in future editions of the book. The best examples illustrate an
important design principle and are simple enough to explain in a paragraph or
two. If you would like to see what other people are saying on the email
address and participate in discussions, you can join the Google Group
software-design-book.
If for some reason the software-design-book Google Group should
disappear in the future, search on the Web for my home page; it will contain
updated instructions for how to communicate about the book. Please don’t
send book-related email to my personal email address.
I recommend that you take the suggestions in this book with a grain of
salt. The overall goal is to reduce complexity; this is more important than any
particular principle or idea you read here. If you try an idea from this book
and find that it doesn’t actually reduce complexity, then don’t feel obligated
to keep using it (but, do let me know about your experience; I’d like to get
feedback on what works and what doesn’t).
Many people have offered criticisms or made suggestions that improved
the quality of the book. The following people offered helpful comments on
various drafts of the book: Jeff Dean, Sanjay Ghemawat, John Hartman,
Brian Kernighan, James Koppel, Amy Ousterhout, Kay Ousterhout, Rob
Pike, Partha Ranganathan, Keith Schwartz, and Alex Snaps. Christos
Kozyrakis suggested the terms “deep” and “shallow” for classes and
interfaces, replacing previous terms “thick” and “thin”, which were
somewhat ambiguous. I am indebted to the students in CS 190; the process of
reading their code and discussing it with them has helped to crystallize my
thoughts about design.
Chapter 1
Introduction
(It’s All About Complexity)
Writing computer software is one of the purest creative activities in the
history of the human race. Programmers aren’t bound by practical limitations
such as the laws of physics; we can create exciting virtual worlds with
behaviors that could never exist in the real world. Programming doesn’t
require great physical skill or coordination, like ballet or basketball. All
programming requires is a creative mind and the ability to organize your
thoughts. If you can visualize a system, you can probably implement it in a
computer program.
This means that the greatest limitation in writing software is our ability to
understand the systems we are creating. As a program evolves and acquires
more features, it becomes complicated, with subtle dependencies between its
components. Over time, complexity accumulates, and it becomes harder and
harder for programmers to keep all of the relevant factors in their minds as
they modify the system. This slows down development and leads to bugs,
which slow development even more and add to its cost. Complexity increases
inevitably over the life of any program. The larger the program, and the more
people that work on it, the more difficult it is to manage complexity.
Good development tools can help us deal with complexity, and many
great tools have been created over the last several decades. But there is a limit
to what we can do with tools alone. If we want to make it easier to write
software, so that we can build more powerful systems more cheaply, we must
find ways to make software simpler. Complexity will still increase over time,
in spite of our best efforts, but simpler designs allow us to build larger and
more powerful systems before complexity becomes overwhelming.
There are two general approaches to fighting complexity, both of which
will be discussed in this book. The first approach is to eliminate complexity
by making code simpler and more obvious. For example, complexity can be
reduced by eliminating special cases or using identifiers in a consistent
fashion.
The second approach to complexity is to encapsulate it, so that
programmers can work on a system without being exposed to all of its
complexity at once. This approach is called modular design. In modular
design, a software system is divided up into modules, such as classes in an
object-oriented language. The modules are designed to be relatively
independent of each other, so that a programmer can work on one module
without having to understand the details of other modules.
Because software is so malleable, software design is a continuous process
that spans the entire lifecycle of a software system; this makes software
design different from the design of physical systems such as buildings, ships,
or bridges. However, software design has not always been viewed this way.
For much of the history of programming, design was concentrated at the
beginning of a project, as it is in other engineering disciplines. The extreme
of this approach is called the waterfall model, in which a project is divided
into discrete phases such as requirements definition, design, coding, testing,
and maintenance. In the waterfall model, each phase completes before the
next phase starts; in many cases different people are responsible for each
phase. The entire system is designed at once, during the design phase. The
design is frozen at the end of this phase, and the role of the subsequent phases
is to flesh out and implement that design.
Unfortunately, the waterfall model rarely works well for software.
Software systems are intrinsically more complex than physical systems; it
isn’t possible to visualize the design for a large software system well enough
to understand all of its implications before building anything. As a result, the
initial design will have many problems. The problems do not become
apparent until implementation is well underway. However, the waterfall
model is not structured to accommodate major design changes at this point
(for example, the designers may have moved on to other projects). Thus,
developers try to patch around the problems without changing the overall
design. This results in an explosion of complexity.
Because of these issues, most software development projects today use an
incremental approach such as agile development, in which the initial design
focuses on a small subset of the overall functionality. This subset is designed,
implemented, and then evaluated. Problems with the original design are
discovered and corrected, then a few more features are designed,
implemented and evaluated. Each iteration exposes problems with the
existing design, which are fixed before the next set of features is designed.
By spreading out the design in this way, problems with the initial design can
be fixed while the system is still small; later features benefit from experience
gained during the implementation of earlier features, so they have fewer
problems.
The incremental approach works for software because software is
malleable enough to allow significant design changes partway through
implementation. In contrast, major design changes are much more
challenging for physical systems: for example, it would not be practical to
change the number of towers supporting a bridge in the middle of
construction.
Incremental development means that software design is never done.
Design happens continuously over the life of a system: developers should
always be thinking about design issues. Incremental development also means
continuous redesign. The initial design for a system or component is almost
never the best one; experience inevitably shows better ways to do things. As
a software developer, you should always be on the lookout for opportunities
to improve the design of the system you are working on, and you should plan
on spending some fraction of your time on design improvements.
If software developers should always be thinking about design issues, and
reducing complexity is the most important element of software design, then
software developers should always be thinking about complexity. This book
is about how to use complexity to guide the design of software throughout its
lifetime.
This book has two overall goals. The first is to describe the nature of
software complexity: what does “complexity” mean, why does it matter, and
how can you recognize when a program has unnecessary complexity? The
book’s second, and more challenging, goal is to present techniques you can
use during the software development process to minimize complexity.
Unfortunately, there isn’t a simple recipe that will guarantee great software
designs. Instead, I will present a collection of higher-level concepts that
border on the philosophical, such as “classes should be deep” or “define
errors out of existence.” These concepts may not immediately identify the
best design, but you can use them to compare design alternatives and guide
your exploration of the design space.
1.1 How to use this book
Many of the design principles described here are somewhat abstract, so they
may be hard to appreciate without looking at actual code. It has been a
challenge to find examples that are small enough to include in the book, yet
large enough to illustrate problems with real systems (if you encounter good
examples, please send them to me). Thus, this book may not be sufficient by
itself for you to learn how to apply the principles.
The best way to use this book is in conjunction with code reviews. When
you read other people’s code, think about whether it conforms to the concepts
discussed here and how that relates to the complexity of the code. It’s easier
to see design problems in someone else’s code than your own. You can use
the red flags described here to identify problems and suggest improvements.
Reviewing code will also expose you to new design approaches and
programming techniques.
One of the best ways to improve your design skills is to learn to recognize
red flags: signs that a piece of code is probably more complicated than it
needs to be. Over the course of this book I will point out red flags that
suggest problems related to each major design issue; the most important ones
are summarized at the back of the book. You can then use these when you are
coding: when you see a red flag, stop and look for an alternate design that
eliminates the problem. When you first try this approach, you may have to try
several design alternatives before you find one that eliminates the red flag.
Don’t give up easily: the more alternatives you try before fixing the problem,
the more you will learn. Over time, you will find that your code has fewer
and fewer red flags, and your designs are cleaner and cleaner. Your
experience will also show you other red flags that you can use to identify
design problems (I’d be happy to hear about these).
When applying the ideas from this book, it’s important to use moderation
and discretion. Every rule has its exceptions, and every principle has its
limits. If you take any design idea to its extreme, you will probably end up in
a bad place. Beautiful designs reflect a balance between competing ideas and
approaches. Several chapters have sections titled “Taking it too far,” which
describe how to recognize when you are overdoing a good thing.
Almost all of the examples in this book are in Java or C++, and much of
the discussion is in terms of designing classes in an object-oriented language.
However, the ideas apply in other domains as well. Almost all of the ideas
related to methods can also be applied to functions in a language without
object-oriented features, such as C. The design ideas also apply to modules
other than classes, such as subsystems or network services.
With this background, let’s discuss in more detail what causes
complexity, and how to make software systems simpler.
Chapter 2
The Nature of Complexity
This book is about how to design software systems to minimize their
complexity. The first step is to understand the enemy. Exactly what is
“complexity”? How can you tell if a system is unnecessarily complex? What
causes systems to become complex? This chapter will address those
questions at a high level; subsequent chapters will show you how to
recognize complexity at a lower level, in terms of specific structural features.
The ability to recognize complexity is a crucial design skill. It allows you
to identify problems before you invest a lot of effort in them, and it allows
you to make good choices among alternatives. It is easier to tell whether a
design is simple than it is to create a simple design, but once you can
recognize that a system is too complicated, you can use that ability to guide
your design philosophy towards simplicity. If a design appears complicated,
try a different approach and see if that is simpler. Over time, you will notice
that certain techniques tend to result in simpler designs, while others correlate
with complexity. This will allow you to produce simpler designs more
quickly.
This chapter also lays out some basic assumptions that provide a
foundation for the rest of the book. Later chapters take the material of this
chapter as given and use it to justify a variety of refinements and conclusions.
2.1 Complexity defined
For the purposes of this book, I define “complexity” in a practical way.
Complexity is anything related to the structure of a software system that
makes it hard to understand and modify the system. Complexity can take
many forms. For example, it might be hard to understand how a piece of code
works; it might take a lot of effort to implement a small improvement, or it
might not be clear which parts of the system must be modified to make the
improvement; it might be difficult to fix one bug without introducing another.
If a software system is hard to understand and modify, then it is complicated;
if it is easy to understand and modify, then it is simple.
You can also think of complexity in terms of cost and benefit. In a
complex system, it takes a lot of work to implement even small
improvements. In a simple system, larger improvements can be implemented
with less effort.
Complexity is what a developer experiences at a particular point in time
when trying to achieve a particular goal. It doesn’t necessarily relate to the
overall size or functionality of the system. People often use the word
“complex” to describe large systems with sophisticated features, but if such a
system is easy to work on, then, for the purposes of this book, it is not
complex. Of course, almost all large and sophisticated software systems are
in fact hard to work on, so they also meet my definition of complexity, but
this need not necessarily be the case. It is also possible for a small and
unsophisticated system to be quite complex.
Complexity is determined by the activities that are most common. If a
system has a few parts that are very complicated, but those parts almost never
need to be touched, then they don’t have much impact on the overall
complexity of the system. To characterize this in a crude mathematical way:
The overall complexity of a system (C) is determined by the complexity
of each part p (cp) weighted by the fraction of time developers spend working
on that part (tp). Isolating complexity in a place where it will never be seen is
almost as good as eliminating the complexity entirely.
Complexity is more apparent to readers than writers. If you write a piece
of code and it seems simple to you, but other people think it is complex, then
it is complex. When you find yourself in situations like this, it’s worth
probing the other developers to find out why the code seems complex to
them; there are probably some interesting lessons to learn from the
disconnect between your opinion and theirs. Your job as a developer is not
just to create code that you can work with easily, but to create code that
others can also work with easily.
2.2 Symptoms of complexity
Complexity manifests itself in three general ways, which are described in the
paragraphs below. Each of these manifestations makes it harder to carry out
development tasks.
Change amplification: The first symptom of complexity is that a
seemingly simple change requires code modifications in many different
places. For example, consider a Web site containing several pages, each of
which displays a banner with a background color. In many early Web sites,
the color was specified explicitly on each page, as shown in Figure 2.1(a). In
order to change the background for such a Web site, a developer might have
to modify every existing page by hand; this would be nearly impossible for a
large site with thousands of pages. Fortunately, modern Web sites use an
approach like that in Figure 2.1(b), where the banner color is specified once
in a central place, and all of the individual pages reference that shared value.
With this approach, the banner color of the entire Web site can be changed
with a single modification. One of the goals of good design is to reduce the
amount of code that is affected by each design decision, so design changes
don’t require very many code modifications.
Cognitive load: The second symptom of complexity is cognitive load,
which refers to how much a developer needs to know in order to complete a
task. A higher cognitive load means that developers have to spend more time
learning the required information, and there is a greater risk of bugs because
they have missed something important. For example, suppose a function in C
allocates memory, returns a pointer to that memory, and assumes that the
caller will free the memory. This adds to the cognitive load of developers
using the function; if a developer fails to free the memory, there will be a
memory leak. If the system can be restructured so that the caller doesn’t need
to worry about freeing the memory (the same module that allocates the
memory also takes responsibility for freeing it), it will reduce the cognitive
load. Cognitive load arises in many ways, such as APIs with many methods,
global variables, inconsistencies, and dependencies between modules.
System designers sometimes assume that complexity can be measured by
lines of code. They assume that if one implementation is shorter than another,
then it must be simpler; if it only takes a few lines of code to make a change,
then the change must be easy. However, this view ignores the costs
associated with cognitive load. I have seen frameworks that allowed
applications to be written with only a few lines of code, but it was extremely
difficult to figure out what those lines were. Sometimes an approach that
requires more lines of code is actually simpler, because it reduces
cognitive load.
Figure 2.1: Each page in a Web site displays a colored banner. In (a) the background color for the
banner is specified explicitly in each page. In (b) a shared variable holds the background color and each
page references that variable. In (c) some pages display an additional color for emphasis, which is a
darker shade of the banner background color; if the background color changes, the emphasis color must
also change.
Unknown unknowns: The third symptom of complexity is that it is not
obvious which pieces of code must be modified to complete a task, or what
information a developer must have to carry out the task successfully. Figure
2.1(c) illustrates this problem. The Web site uses a central variable to
determine the banner background color, so it appears to be easy to change.
However, a few Web pages use a darker shade of the background color for
emphasis, and that darker color is specified explicitly in the individual pages.
If the background color changes, then the the emphasis color must change to
match. Unfortunately, developers are unlikely to realize this, so they may
change the central bannerBg variable without updating the emphasis color.
Even if a developer is aware of the problem, it won’t be obvious which pages
use the emphasis color, so the developer may have to search every page in the
Web site.
Of the three manifestations of complexity, unknown unknowns are the
worst. An unknown unknown means that there is something you need to
know, but there is no way for you to find out what it is, or even whether there
is an issue. You won’t find out about it until bugs appear after you make a
change. Change amplification is annoying, but as long as it is clear which
code needs to be modified, the system will work once the change has been
completed. Similarly, a high cognitive load will increase the cost of a change,
but if it is clear which information to read, the change is still likely to be
correct. With unknown unknowns, it is unclear what to do or whether a
proposed solution will even work. The only way to be certain is to read every
line of code in the system, which is impossible for systems of any size. Even
this may not be sufficient, because a change may depend on a subtle design
decision that was never documented.
One of the most important goals of good design is for a system to be
obvious. This is the opposite of high cognitive load and unknown unknowns.
In an obvious system, a developer can quickly understand how the existing
code works and what is required to make a change. An obvious system is one
where a developer can make a quick guess about what to do, without thinking
very hard, and yet be confident that the guess is correct. Chapter 18 discusses
techniques for making code more obvious.
2.3 Causes of complexity
Now that you know the high-level symptoms of complexity and why
complexity makes software development difficult, the next step is to
understand what causes complexity, so that we can design systems to avoid
the problems. Complexity is caused by two things: dependencies and
obscurity. This section discusses these factors at a high level; subsequent
chapters will discuss how they relate to lower-level design decisions.
For the purposes of this book, a dependency exists when a given piece of
code cannot be understood and modified in isolation; the code relates in some
way to other code, and the other code must be considered and/or modified if
the given code is changed. In the Web site example of Figure 2.1(a), the
background color creates dependencies between all of the pages. All of the
pages need to have the same background, so if the background is changed for
one page, then it must be changed for all of them. Another example of
dependencies occurs in network protocols. Typically there is separate code
for the sender and receiver for the protocol, but they must each conform to
the protocol; changing the code for the sender almost always requires
corresponding changes at the receiver, and vice versa. The signature of a
method creates a dependency between the implementation of that method and
the code that invokes it: if a new parameter is added to a method, all of the
invocations of that method must be modified to specify that parameter.
Dependencies are a fundamental part of software and can’t be completely
eliminated. In fact, we intentionally introduce dependencies as part of the
software design process. Every time you write a new class you create
dependencies around the API for that class. However, one of the goals of
software design is to reduce the number of dependencies and to make the
dependencies that remain as simple and obvious as possible.
Consider the Web site example. In the old Web site with the background
specified separately on each page, all of the Web pages were dependent on
each other. The new Web site fixed this problem by specifying the
background color in a central place and providing an API that individual
pages use to retrieve that color when they are rendered. The new Web site
eliminated the dependency between the pages, but it created a new
dependency around the API for retrieving the background color. Fortunately,
the new dependency is more obvious: it is clear that each individual Web
page depends on the bannerBg color, and a developer can easily find all the
places where the variable is used by searching for its name. Furthermore,
compilers help to manage API dependencies: if the name of the shared
variable changes, compilation errors will occur in any code that still uses the
old name. The new Web site replaced a nonobvious and difficult-to-manage
dependency with a simpler and more obvious one.
The second cause of complexity is obscurity. Obscurity occurs when
important information is not obvious. A simple example is a variable name
that is so generic that it doesn’t carry much useful information (e.g., time).
Or, the documentation for a variable might not specify its units, so the only
way to find out is to scan code for places where the variable is used.
Obscurity is often associated with dependencies, where it is not obvious that
a dependency exists. For example, if a new error status is added to a system,
it may be necessary to add an entry to a table holding string messages for
each status, but the existence of the message table might not be obvious to a
programmer looking at the status declaration. Inconsistency is also a major
contributor to obscurity: if the same variable name is used for two different
purposes, it won’t be obvious to developer which of these purposes a
particular variable serves.
In many cases, obscurity comes about because of inadequate
documentation; Chapter 13 deals with this topic. However, obscurity is also a
design issue. If a system has a clean and obvious design, then it will need less
documentation. The need for extensive documentation is often a red flag that
the design isn’t quite right. The best way to reduce obscurity is by
simplifying the system design.
Together, dependencies and obscurity account for the three
manifestations of complexity described in Section 2.2. Dependencies lead to
change amplification and a high cognitive load. Obscurity creates unknown
unknowns, and also contributes to cognitive load. If we can find design
techniques that minimize dependencies and obscurity, then we can reduce the
complexity of software.
2.4 Complexity is incremental
Complexity isn’t caused by a single catastrophic error; it accumulates in lots
of small chunks. A single dependency or obscurity, by itself, is unlikely to
affect significantly the maintainability of a software system. Complexity
comes about because hundreds or thousands of small dependencies and
obscurities build up over time. Eventually, there are so many of these small
issues that every possible change to the system is affected by several of them.
The incremental nature of complexity makes it hard to control. It’s easy
to convince yourself that a little bit of complexity introduced by your current
change is no big deal. However, if every developer takes this approach for
every change, complexity accumulates rapidly. Once complexity has
accumulated, it is hard to eliminate, since fixing a single dependency or
obscurity will not, by itself, make a big difference. In order to slow the
growth of complexity, you must adopt a “zero tolerance” philosophy, as
discussed in Chapter 3.
2.5 Conclusion
Complexity comes from an accumulation of dependencies and obscurities. As
complexity increases, it leads to change amplification, a high cognitive load,
and unknown unknowns. As a result, it takes more code modifications to
implement each new feature. In addition, developers spend more time
acquiring enough information to make the change safely and, in the worst
case, they can’t even find all the information they need. The bottom line is
that complexity makes it difficult and risky to modify an existing code base.
Chapter 3
Working Code Isn’t Enough
(Strategic vs. Tactical Programming)
One of the most important elements of good software design is the
mindset you adopt when you approach a programming task. Many
organizations encourage a tactical mindset, focused on getting features
working as quickly as possible. However, if you want a good design, you
must take a more strategic approach where you invest time to produce clean
designs and fix problems. This chapter discusses why the strategic approach
produces better designs and is actually cheaper than the tactical approach
over the long run.
3.1 Tactical programming
Most programmers approach software development with a mindset I call
tactical programming. In the tactical approach, your main focus is to get
something working, such as a new feature or a bug fix. At first glance this
seems totally reasonable: what could be more important than writing code
that works? However, tactical programming makes it nearly impossible to
produce a good system design.
The problem with tactical programming is that it is short-sighted. If
you’re programming tactically, you’re trying to finish a task as quickly as
possible. Perhaps you have a hard deadline. As a result, planning for the
future isn’t a priority. You don’t spend much time looking for the best
design; you just want to get something working soon. You tell yourself that
it’s OK to add a bit of complexity or introduce a small kludge or two, if that
allows the current task to be completed more quickly.
This is how systems become complicated. As discussed in the previous
chapter, complexity is incremental. It’s not one particular thing that makes a
system complicated, but the accumulation of dozens or hundreds of small
things. If you program tactically, each programming task will contribute a
few of these complexities. Each of them probably seems like a reasonable
compromise in order to finish the current task quickly. However, the
complexities accumulate rapidly, especially if everyone is programming
tactically.
Before long, some of the complexities will start causing problems, and
you will begin to wish you hadn’t taken those early shortcuts. But, you will
tell yourself that it’s more important to get the next feature working than to
go back and refactor existing code. Refactoring may help out in the long run,
but it will definitely slow down the current task. So, you look for quick
patches to work around any problems you encounter. This just creates more
complexity, which then requires more patches. Pretty soon the code is a mess,
but by this point things are so bad that it would take months of work to clean
it up. There’s no way your schedule can tolerate that kind of delay, and fixing
one or two of the problems doesn’t seem like it will make much difference,
so you just keep programming tactically.
If you have worked on a large software project for very long, I suspect
you have seen tactical programming at work and have experienced the
problems that result. Once you start down the tactical path, it’s difficult to
change.
Almost every software development organization has at least one
developer who takes tactical programming to the extreme: a tactical tornado.
The tactical tornado is a prolific programmer who pumps out code far faster
than others but works in a totally tactical fashion. When it comes to
implementing a quick feature, nobody gets it done faster than the tactical
tornado. In some organizations, management treats tactical tornadoes as
heroes. However, tactical tornadoes leave behind a wake of destruction. They
are rarely considered heroes by the engineers who must work with their code
in the future. Typically, other engineers must clean up the messes left behind
by the tactical tornado, which makes it appear that those engineers (who are
the real heroes) are making slower progress than the tactical tornado.
3.2 Strategic programming
The first step towards becoming a good software designer is to realize that
working code isn’t enough. It’s not acceptable to introduce unnecessary
complexities in order to finish your current task faster. The most important
thing is the long-term structure of the system. Most of the code in any system
is written by extending the existing code base, so your most important job as
a developer is to facilitate those future extensions. Thus, you should not think
of “working code” as your primary goal, though of course your code must
work. Your primary goal must be to produce a great design, which also
happens to work. This is strategic programming.
Strategic programming requires an investment mindset. Rather than
taking the fastest path to finish your current project, you must invest time to
improve the design of the system. These investments will slow you down a
bit in the short term, but they will speed you up in the long term, as illustrated
in Figure 3.1.
Some of the investments will be proactive. For example, it’s worth taking
a little extra time to find a simple design for each new class; rather than
implementing the first idea that comes to mind, try a couple of alternative
designs and pick the cleanest one. Try to imagine a few ways in which the
system might need to be changed in the future and make sure that will be
easy with your design. Writing good documentation is another example of a
proactive investment.
Other investments will be reactive. No matter how much you invest up
front, there will inevitably be mistakes in your design decisions. Over time,
these mistakes will become obvious. When you discover a design problem,
don’t just ignore it or patch around it; take a little extra time to fix it. If you
program strategically, you will continually make small improvements to the
system design. This is the opposite of tactical programming, where you are
continually adding small bits of complexity that cause problems in the future.
3.3 How much to invest?
So, what is the right amount of investment? A huge up-front investment, such
as trying to design the entire system, won’t be effective. This is the waterfall
method, and we know it doesn’t work. The ideal design tends to emerge in
bits and pieces, as you get experience with the system. Thus, the best
approach is to make lots of small investments on a continual basis. I suggest
spending about 10–20% of your total development time on investments. This
amount is small enough that it won’t impact your schedules significantly, but
large enough to produce significant benefits over time. Your initial projects
will thus take 10–20% longer than they would in a purely tactical approach.
That extra time will result in a better software design, and you will start
experiencing the benefits within a few months. It won’t be long before you’re
developing at least 10–20% faster than you would if you had programmed
tactically. At this point your investments become free: the benefits from your
past investments will save enough time to cover the cost of future
investments. You will quickly recover the cost of the initial investment.
Figure 3.1 illustrates this phenomenon.
Figure 3.1: At the beginning, a tactical approach to programming will make progress more quickly
than a strategic approach. However, complexity accumulates more rapidly under the tactical approach,
which reduces productivity. Over time, the strategic approach results in greater progress. Note: this
figure is intended only as a qualitative illustration; I am not aware of any empirical measurements of
the precise shapes of the curves.
Conversely, if you program tactically, you will finish your first projects
10–20% faster, but over time your development speed will slow as
complexity accumulates. It won’t be long before you’re programming at least
10–20% slower. You will quickly give back all of the time you saved at the
beginning, and for the rest of system’s lifetime you will be developing more
slowly than if you had taken the strategic approach. If you haven’t ever
worked in a badly degraded code base, talk to someone who has; they will
tell you that poor code quality slows development by at least 20%.
3.4 Startups and investment
In some environments there are strong forces working against the strategic
approach. For example, early-stage startups feel tremendous pressure to get
their early releases out quickly. In these companies, it might seem that even a
10–20% investment isn’t affordable. As a result, many startups take a tactical
approach, spending little effort on design and even less on cleanup when
problems pop up. They rationalize this with the thought that, if they are
successful, they’ll have enough money to hire extra engineers to clean things
up.
If you are in a company leaning in this direction, you should realize that
once a code base turns to spaghetti, it is nearly impossible to fix. You will
probably pay high development costs for the life of the product. Furthermore,
the payoff for good (or bad) design comes pretty quickly, so there’s a good
chance that the tactical approach won’t even speed up your first product
release.
Another thing to consider is that one of the most important factors for
success of a company is the quality of its engineers. The best way to lower
development costs is to hire great engineers: they don’t cost much more than
mediocre engineers but have tremendously higher productivity. However, the
best engineers care deeply about good design. If your code base is a wreck,
word will get out, and this will make it harder for you to recruit. As a result,
you are likely to end up with mediocre engineers. This will increase your
future costs and probably cause the system structure to degrade even more.
Facebook is an example of a startup that encouraged tactical
programming. For many years the company’s motto was “Move fast and
break things.” New engineers fresh out of college were encouraged to dive
immediately into the company’s code base; it was normal for engineers to
push commits into production in their first week on the job. On the positive
side, Facebook developed a reputation as a company that empowered its
employees. Engineers had tremendous latitude, and there were few rules and
restrictions to get in their way.
Facebook has been spectacularly successful as a company, but its code
base suffered because of the company’s tactical approach; much of the code
was unstable and hard to understand, with few comments or tests, and painful
to work with. Over time the company realized that its culture was
unsustainable. Eventually, Facebook changed its motto to “Move fast with
solid infrastructure” to encourage its engineers to invest more in good design.
It remains to be seen whether Facebook can successfully clean up the
problems that accumulated over years of tactical programming.
In fairness to Facebook, I should point out that Facebook’s code probably
isn’t much worse than average among startups. Tactical programming is
commonplace among startups; Facebook just happens to be a particularly
visible example.
Fortunately, it is also possible to succeed in Silicon Valley with a
strategic approach. Google and VMware grew up around the same time as
Facebook, but both of these companies embraced a more strategic approach.
Both companies placed a heavy emphasis on high quality code and good
design, and both companies built sophisticated products that solved complex
problems with reliable software systems. The companies’ strong technical
cultures became well known in Silicon Valley. Few other companies could
compete with them for hiring the top technical talent.
These examples show that a company can succeed with either approach.
However, it’s a lot more fun to work in a company that cares about software
design and has a clean code base.
3.5 Conclusion
Good design doesn’t come for free. It has to be something you invest in
continually, so that small problems don’t accumulate into big ones.
Fortunately, good design eventually pays for itself, and sooner than you
might think.
It’s crucial to be consistent in applying the strategic approach and to think
of investment as something to do today, not tomorrow. When you get in a
crunch it will be tempting to put off cleanups until after the crunch is over.
However, this is a slippery slope; after the current crunch there will almost
certainly be another one, and another after that. Once you start delaying
design improvements, it’s easy for the delays to become permanent and for
your culture to slip into the tactical approach. The longer you wait to address
design problems, the bigger they become; the solutions become more
intimidating, which makes it easy to put them off even more. The most
effective approach is one where every engineer makes continuous small
investments in good design.
Chapter 4
Modules Should Be Deep
One of the most important techniques for managing software complexity is to
design systems so that developers only need to face a small fraction of the
overall complexity at any given time. This approach is called modular design,
and this chapter presents its basic principles.
4.1 Modular design
In modular design, a software system is decomposed into a collection of
modules that are relatively independent. Modules can take many forms, such
as classes, subsystems, or services. In an ideal world, each module would be
completely independent of the others: a developer could work in any of the
modules without knowing anything about any of the other modules. In this
world, the complexity of a system would be the complexity of its worst
module.
Unfortunately, this ideal is not achievable. Modules must work together
by calling each others’s functions or methods. As a result, modules must
know something about each other. There will be dependencies between the
modules: if one module changes, other modules may need to change to
match. For example, the arguments for a method create a dependency
between the method and any code that invokes the method. If the required
arguments change, all invocations of the method must be modified to
conform to the new signature. Dependencies can take many other forms, and
they can be quite subtle. The goal of modular design is to minimize the
dependencies between modules.
In order to manage dependencies, we think of each module in two parts:
an interface and an implementation. The interface consists of everything that
a developer working in a different module must know in order to use the
given module. Typically, the interface describes what the module does but
not how it does it. The implementation consists of the code that carries out
the promises made by the interface. A developer working in a particular
module must understand the interface and implementation of that module,
plus the interfaces of any other modules invoked by the given module. A
developer should not need to understand the implementations of modules
other than the one he or she is working in.
Consider a module that implements balanced trees. The module probably
contains sophisticated code for ensuring that the tree remains balanced.
However, this complexity is not visible to users of the module. Users see a
relatively simple interface for invoking operations to insert, remove, and
fetch nodes in the tree. To invoke an insert operation, the caller need only
provide the key and value for the new node; the mechanisms for traversing
the tree and splitting nodes are not visible in the interface.
For the purposes of this book, a module is any unit of code that has an
interface and an implementation. Each class in an object-oriented
programming language is a module. Methods within a class, or functions in a
language that isn’t object-oriented, can also be thought of as modules: each of
these has an interface and an implementation, and modular design techniques
can be applied to them. Higher-level subsystems and services are also
modules; their interfaces may take different forms, such as kernel calls or
HTTP requests. Much of the discussion about modular design in this book
focuses on designing classes, but the techniques and concepts apply to other
kinds of modules as well.
The best modules are those whose interfaces are much simpler than their
implementations. Such modules have two advantages. First, a simple
interface minimizes the complexity that a module imposes on the rest of the
system. Second, if a module is modified in a way that does not change its
interface, then no other module will be affected by the modification. If a
module’s interface is much simpler than its implementation, there will be
many aspects of the module that can be changed without affecting other
modules.
4.2 What’s in an interface?
The interface to a module contains two kinds of information: formal and
informal. The formal parts of an interface are specified explicitly in the code,
and some of these can be checked for correctness by the programming
language. For example, the formal interface for a method is its signature,
which includes the names and types of its parameters, the type of its return
value, and information about exceptions thrown by the method. Most
programming languages ensure that each invocation of a method provides the
right number and types of arguments to match its signature. The formal
interface for a class consists of the signatures for all of its public methods,
plus the names and types of any public variables.
Each interface also includes informal elements. These are not specified in
a way that can be understood or enforced by the programming language. The
informal parts of an interface include its high-level behavior, such as the fact
that a function deletes the file named by one of its arguments. If there are
constraints on the usage of a class (perhaps one method must be called before
another), these are also part of the class’s interface. In general, if a developer
needs to know a particular piece of information in order to use a module, then
that information is part of the module’s interface. The informal aspects of an
interface can only be described using comments, and the programming
language cannot ensure that the description is complete or accurate1. For
most interfaces the informal aspects are larger and more complex than the
formal aspects.
One of the benefits of a clearly specified interface is that it indicates
exactly what developers need to know in order to use the associated module.
This helps to eliminate the “unknown unknowns” problem described in
Section 2.2.
4.3 Abstractions
The term abstraction is closely related to the idea of modular design. An
abstraction is a simplified view of an entity, which omits unimportant
details. Abstractions are useful because they make it easier for us to think
about and manipulate complex things.
In modular programming, each module provides an abstraction in form of
its interface. The interface presents a simplified view of the module’s
functionality; the details of the implementation are unimportant from the
standpoint of the module’s abstraction, so they are omitted from the interface.
In the definition of abstraction, the word “unimportant” is crucial. The
more unimportant details that are omitted from an abstraction, the better.
However, a detail can only be omitted from an abstraction if it is
unimportant. An abstraction can go wrong in two ways. First, it can include
details that are not really important; when this happens, it makes the
abstraction more complicated than necessary, which increases the cognitive
load on developers using the abstraction. The second error is when an
abstraction omits details that really are important. This results in obscurity:
developers looking only at the abstraction will not have all the information
they need to use the abstraction correctly. An abstraction that omits important
details is a false abstraction: it might appear simple, but in reality it isn’t. The
key to designing abstractions is to understand what is important, and to look
for designs that minimize the amount of information that is important.
As an example, consider a file system. The abstraction provided by a file
system omits many details, such as the mechanism for choosing which blocks
on a storage device to use for the data in a given file. These details are
unimportant to users of the file system (as long as the system provides
adequate performance). However, some of the details of a file system’s
implementation are important to users. Most file systems cache data in main
memory, and they may delay writing new data to the storage device in order
to improve performance. Some applications, such as databases, need to know
exactly when data is written through to storage, so they can ensure that data
will be preserved after system crashes. Thus, the rules for flushing data to
secondary storage must be visible in the file system’s interface.
We depend on abstractions to manage complexity not just in
programming, but pervasively in our everyday lives. A microwave oven
contains complex electronics to convert alternating current into microwave
radiation and distribute that radiation throughout the cooking cavity.
Fortunately, users see a much simpler abstraction, consisting of a few buttons
to control the timing and intensity of the microwaves. Cars provide a simple
abstraction that allows us to drive them without understanding the
mechanisms for electrical motors, battery power management, anti-lock
brakes, cruise control, and so on.
4.4 Deep modules
The best modules are those that provide powerful functionality yet have
simple interfaces. I use the term deep to describe such modules. To visualize
the notion of depth, imagine that each module is represented by a rectangle,
as shown in Figure 4.1. The area of each rectangle is proportional to the
functionality implemented by the module. The top edge of a rectangle
represents the module’s interface; the length of that edge indicates the
complexity of the interface. The best modules are deep: they have a lot of
functionality hidden behind a simple interface. A deep module is a good
abstraction because only a small fraction of its internal complexity is visible
to its users.
Figure 4.1: Deep and shallow modules. The best modules are deep: they allow a lot of functionality to
be accessed through a simple interface. A shallow module is one with a relatively complex interface,
but not much functionality: it doesn’t hide much complexity.
Module depth is a way of thinking about cost versus benefit. The benefit
provided by a module is its functionality. The cost of a module (in terms of
system complexity) is its interface. A module’s interface represents the
complexity that the module imposes on the rest of the system: the smaller and
simpler the interface, the less complexity that it introduces. The best modules
are those with the greatest benefit and the least cost. Interfaces are good, but
more, or larger, interfaces are not necessarily better!
The mechanism for file I/O provided by the Unix operating system and its
descendants, such as Linux, is a beautiful example of a deep interface. There
are only five basic system calls for I/O, with simple signatures:
int open(const char* path, int flags, mode_t permissions);
ssize_t read(int fd, void* buffer, size_t count);
ssize_t write(int fd, const void* buffer, size_t count);
off_t lseek(int fd, off_t offset, int referencePosition);
int close(int fd);
The open system call takes a hierarchical file name such as /a/b/c and returns
an integer file descriptor, which is used to reference the open file. The other
arguments for open provide optional information such as whether the file is
being opened for reading or writing, whether a new file should be created if
there is no existing file, and access permissions for the file, if a new file is
created. The read and write system calls transfer information between buffer
areas in the application’s memory and the file; close ends the access to the
file. Most files are accessed sequentially, so that is the default; however,
random access can be achieved by invoking the lseek system call to change
the current access position.
A modern implementation of the Unix I/O interface requires hundreds of
thousands of lines of code, which address complex issues such as:
How are files represented on disk in order to allow efficient access?
How are directories stored, and how are hierarchical path names
processed to find the files they refer to?
How are permissions enforced, so that one user cannot modify or delete
another user’s files?
How are file accesses implemented? For example, how is functionality
divided between interrupt handlers and background code, and how do
these two elements communicate safely?
What scheduling policies are used when there are concurrent accesses to
multiple files?
How can recently accessed file data be cached in memory in order to
reduce the number of disk accesses?
How can a variety of different secondary storage devices, such as disks
and flash drives, be incorporated into a single file system?
All of these issues, and many more, are handled by the Unix file system
implementation; they are invisible to programmers who invoke the system
calls. Implementations of the Unix I/O interface have evolved radically over
the years, but the five basic kernel calls have not changed.
Another example of a deep module is the garbage collector in a language
such as Go or Java. This module has no interface at all; it works invisibly
behind the scenes to reclaim unused memory. Adding garbage collection to a
system actually shrinks its overall interface, since it eliminates the interface
for freeing objects. The implementation of a garbage collector is quite
complex, but that complexity is hidden from programmers using the
language.
Deep modules such as Unix I/O and garbage collectors provide powerful
abstractions because they are easy to use, yet they hide significant
implementation complexity.
4.5 Shallow modules
On the other hand, a shallow module is one whose interface is relatively
complex in comparison to the functionality that it provides. For example, a
class that implements linked lists is shallow. It doesn’t take much code to
manipulate a linked list (inserting or deleting an element takes only a few
lines), so the linked list abstraction doesn’t hide very many details. The
complexity of a linked list interface is nearly as great as the complexity of its
implementation. Shallow classes are sometimes unavoidable, but they don’t
provide help much in managing complexity.
Here is an extreme example of a shallow method, taken from a project in
a software design class:
private void addNullValueForAttribute(String attribute) {
data.put(attribute, null);
}
From the standpoint of managing complexity, this method makes things
worse, not better. The method offers no abstraction, since all of its
functionality is visible through its interface. For example, callers probably
need to know that the attribute will be stored in the data variable. It is no
simpler to think about the interface than to think about the full
implementation. If the method is documented properly, the documentation
will be longer than the method’s code. It even takes more keystrokes to
invoke the method than it would take for a caller to manipulate the data
variable directly. The method adds complexity (in the form of a new interface
for developers to learn) but provides no compensating benefit.
Red Flag: Shallow Module
A shallow module is one whose interface is complicated relative to the
functionality it provides. Shallow modules don’t help much in the battle
against complexity, because the benefit they provide (not having to learn
about how they work internally) is negated by the cost of learning and
using their interfaces. Small modules tend to be shallow.
4.6 Classitis
Unfortunately, the value of deep classes is not widely appreciated today. The
conventional wisdom in programming is that classes should be small, not
deep. Students are often taught that the most important thing in class design
is to break up larger classes into smaller ones. The same advice is often given
about methods: “Any method longer than N lines should be divided into
multiple methods” (N can be as low as 10). This approach results in large
numbers of shallow classes and methods, which add to overall system
complexity.
The extreme of the “classes should be small” approach is a syndrome I
call classitis, which stems from the mistaken view that “classes are good, so
more classes are better.” In systems suffering from classitis, developers are
encouraged to minimize the amount of functionality in each new class: if you
want more functionality, introduce more classes. Classitis may result in
classes that are individually simple, but it increases the complexity of the
overall system. Small classes don’t contribute much functionality, so there
have to be a lot of them, each with its own interface. These interfaces
accumulate to create tremendous complexity at the system level. Small
classes also result in a verbose programming style, due to the boilerplate
required for each class.
4.7 Examples: Java and Unix I/O
One of the most visible examples of classitis today is the Java class library.
The Java language doesn’t require lots of small classes, but a culture of
classitis seems to have taken root in the Java programming community. For
example, to open a file in order to read serialized objects from it, you must
create three different objects:
FileInputStream fileStream =
new FileInputStream(fileName);
BufferedInputStream bufferedStream =
new BufferedInputStream(fileStream);
ObjectInputStream objectStream =
new ObjectInputStream(bufferedStream);
A FileInputStream object provides only rudimentary I/O: it is not capable of
performing buffered I/O, nor can it read or write serialized objects. The
BufferedInputStream object adds buffering to a FileInputStream, and the
ObjectInputStream adds the ability to read and write serialized objects. The
first two objects in the code above, fileStream and bufferedStream, are never
used once the file has been opened; all future operations use objectStream.
It is particularly annoying (and error-prone) that buffering must be
requested explicitly by creating a separate BufferedInputStream object; if a
developer forgets to create this object, there will be no buffering and I/O will
be slow. Perhaps the Java developers would argue that not everyone wants to
use buffering for file I/O, so it shouldn’t be built into the base mechanism.
They might argue that it’s better to keep buffering separate, so people can
choose whether or not to use it. Providing choice is good, but interfaces
should be designed to make the common case as simple as possible (see
the formula on page 6). Almost every user of file I/O will want buffering, so
it should be provided by default. For those few situations where buffering is
not desirable, the library can provide a mechanism to disable it. Any
mechanism for disabling buffering should be cleanly separated in the
interface (for example, by providing a different constructor for
FileInputStream, or through a method that disables or replaces the buffering
mechanism), so that most developers do not even need to be aware of its
existence.
In contrast, the designers of the Unix system calls made the common case
simple. For example, they recognized that sequential I/O is most common, so
they made that the default behavior. Random access is still relatively easy to
do, using the lseek system call, but a developer doing only sequential access
need not be aware of that mechanism. If an interface has many features, but
most developers only need to be aware of a few of them, the effective
complexity of that interface is just the complexity of the commonly used
features.
4.8 Conclusion
By separating the interface of a module from its implementation, we can hide
the complexity of the implementation from the rest of the system. Users of a
module need only understand the abstraction provided by its interface. The
most important issue in designing classes and other modules is to make them
deep, so that they have simple interfaces for the common use cases, yet still
provide significant functionality. This maximizes the amount of complexity
that is concealed.
1There exist languages, mostly in the research community, where the overall behavior of a method
or function can be described formally using a specification language. The specification can be checked
automatically to ensure that it matches the implementation. An interesting question is whether such a
formal specification could replace the informal parts of an interface. My current opinion is that an
interface described in English is likely to be more intuitive and understandable for developers than one
written in a formal specification language.
Chapter 5
Information Hiding (and Leakage)
Chapter 4 argued that modules should be deep. This chapter, and the next few
that follow, discuss techniques for creating deep modules.
5.1 Information hiding
The most important technique for achieving deep modules is information
hiding. This technique was first described by David Parnas1. The basic idea is
that each module should encapsulate a few pieces of knowledge, which
represent design decisions. The knowledge is embedded in the module’s
implementation but does not appear in its interface, so it is not visible to other
modules.
The information hidden within a module usually consists of details about
how to implement some mechanism. Here are some examples of information
that might be hidden within a module:
How to store information in a B-tree, and how to access it efficiently.
How to identify the physical disk block corresponding to each logical
block within a file.
How to implement the TCP network protocol.
How to schedule threads on a multi-core processor.
How to parse JSON documents.
The hidden information includes data structures and algorithms related to the
mechanism. It can also include lower-level details such as the size of a page,
and it can include higher-level concepts that are more abstract, such as an
assumption that most files are small.
Information hiding reduces complexity in two ways. First, it simplifies
the interface to a module. The interface reflects a simpler, more abstract view
of the module’s functionality and hides the details; this reduces the cognitive
load on developers who use the module. For instance, a developer using a B-
tree class need not worry about the ideal fanout for nodes in the tree or how
to keep the tree balanced. Second, information hiding makes it easier to
evolve the system. If a piece of information is hidden, there are no
dependencies on that information outside the module containing the
information, so a design change related to that information will affect only
the one module. For example, if the TCP protocol changes (to introduce a
new mechanism for congestion control, for instance), the protocol’s
implementation will have to be modified, but no changes should be needed in
higher-level code that uses TCP to send and receive data.
When designing a new module, you should think carefully about what
information can be hidden in that module. If you can hide more information,
you should also be able to simplify the module’s interface, and this makes the
module deeper.
Note: hiding variables and methods in a class by declaring them private
isn’t the same thing as information hiding. Private elements can help with
information hiding, since they make it impossible for the items to be accessed
directly from outside the class. However, information about the private items
can still be exposed through public methods such as getter and setter
methods. When this happens the nature and usage of the variables are just as
exposed as if the variables were public.
The best form of information hiding is when information is totally hidden
within a module, so that it is irrelevant and invisible to users of the module.
However, partial information hiding also has value. For example, if a
particular feature or piece of information is only needed by a few of a class’s
users, and it is accessed through separate methods so that it isn’t visible in the
most common use cases, then that information is mostly hidden. Such
information will create fewer dependencies than information that is visible to
every user of the class.
5.2 Information leakage
The opposite of information hiding is information leakage. Information
leakage occurs when a design decision is reflected in multiple modules. This
creates a dependency between the modules: any change to that design
decision will require changes to all of the involved modules. If a piece of
information is reflected in the interface for a module, then by definition it has
been leaked; thus, simpler interfaces tend to correlate with better information
hiding. However, information can be leaked even if it doesn’t appear in a
module’s interface. Suppose two classes both have knowledge of a particular
file format (perhaps one class reads files in that format and the other class
writes them). Even if neither class exposes that information in its interface,
they both depend on the file format: if the format changes, both classes will
need to be modified. Back-door leakage like this is more pernicious than
leakage through an interface, because it isn’t obvious.
Information leakage is one of the most important red flags in software
design. One of the best skills you can learn as a software designer is a high
level of sensitivity to information leakage. If you encounter information
leakage between classes, ask yourself “How can I reorganize these classes so
that this particular piece of knowledge only affects a single class?” If the
affected classes are relatively small and closely tied to the leaked
information, it may make sense to merge them into a single class. Another
possible approach is to pull the information out of all of the affected classes
and create a new class that encapsulates just that information. However, this
approach will be effective only if you can find a simple interface that
abstracts away from the details; if the new class exposes most of the
knowledge through its interface, then it won’t provide much value (you’ve
simply replaced back-door leakage with leakage through an interface).
Red Flag: Information Leakage
Information leakage occurs when the same knowledge is used in multiple
places, such as two different classes that both understand the format of a
particular type of file.
5.3 Temporal decomposition
One common cause of information leakage is a design style I call temporal
decomposition. In temporal decomposition, the structure of a system
corresponds to the time order in which operations will occur. Consider an
application that reads a file in a particular format, modifies the contents of the
file, and then writes the file out again. With temporal decomposition, this
application might be broken into three classes: one to read the file, another to
perform the modifications, and a third to write out the new version. Both the
file reading and file writing steps have knowledge about the file format,
which results in information leakage. The solution is to combine the core
mechanisms for reading and writing files into a single class. This class will
get used during both the reading and writing phases of the application. It’s
easy to fall into the trap of temporal decomposition, because the order in
which operations must occur is often on your mind when you code. However,
most design decisions manifest themselves at several different times over the
life of the application; as a result, temporal decomposition often results in
information leakage.
Order usually does matter, so it will be reflected somewhere in the
application. However, it shouldn’t be reflected in the module structure unless
that structure is consistent with information hiding (perhaps the different
stages use totally different information). When designing modules, focus on
the knowledge that’s needed to perform each task, not the order in which
tasks occur.
Red Flag: Temporal Decomposition
In temporal decomposition, execution order is reflected in the code
structure: operations that happen at different times are in different methods
or classes. If the same knowledge is used at different points in execution, it
gets encoded in multiple places, resulting in information leakage.
5.4 Example: HTTP server
To illustrate the issues in information hiding, let’s consider the design
decisions made by students implementing the HTTP protocol in a software
design course. It’s useful to see both the things they did well and they areas
where they had problems.
HTTP is a mechanism used by Web browsers to communicate with Web
servers. When a user clicks on a link in a Web browser or submits a form, the
browser uses HTTP to send a request over the network to a Web server. Once
the server has processed the request, it sends a response back to the browser;
the response normally contains a new Web page to display. The HTTP
protocol specifies the format of requests and responses, both of which are
represented textually. Figure 5.1 shows a sample HTTP request describing a
form submission. The students in the course were asked to implement one or
more classes to make it easy for Web servers to receive incoming HTTP
requests and send responses.
Figure 5.1: A POST request in the HTTP protocol consists of text sent over a TCP socket. Each
request contains an initial line, a collection of headers terminated by an empty line, and an optional
body. The initial line contains the request type (POST is used for submitting form data), a URL
indicating an operation (/comments/create) and optional parameters (photo_id has the value 246), and
the HTTP protocol version used by the sender. Each header line consists of a name such as Content-
Length followed by its value. For this request, the body contains additional parameters (comment and
priority).
5.5 Example: too many classes
The most common mistake made by students was to divide their code into a
large number of shallow classes, which led to information leakage between
the classes. One team used two different classes for receiving HTTP requests;
the first class read the request from the network connection into a string, and
the second class parsed the string. This is an example of a temporal
decomposition (“first we read the request, then we parse it”). Information
leakage occurred because an HTTP request can’t be read without parsing
much of the message; for example, the Content-Length header specifies the
length of the request body, so the headers must be parsed in order to compute
the total request length. As a result, both classes needed to understand most
of the structure of HTTP requests, and parsing code was duplicated in both
classes. This approach also created extra complexity for callers, who had to
invoke two methods in different classes, in a particular order, to receive a
request.
Because the classes shared so much information, it would have been
better to merge them into a single class that handles both request reading and
parsing. This provides better information hiding, since it isolates all
knowledge of the request format in one class, and it also provides a simpler
interface to callers (just one method to invoke).
This example illustrates a general theme in software design: information
hiding can often be improved by making a class slightly larger. One
reason for doing this is to bring together all of the code related to a particular
capability (such as parsing an HTTP request), so that the resulting class
contains everything related to that capability. A second reason for increasing
the size of a class is to raise the level of the interface; for example, rather than
having separate methods for each of three steps of a computation, have a
single method that performs the entire computation. This can result in a
simpler interface. Both of these benefits apply in the example of the previous
paragraph: combining the classes brings together all of the code related to
parsing an HTTP request, and it replaces two externally-visible methods with
one. The combined class is deeper than the original classes.
Of course, it is possible to take the notion of larger classes too far (such
as a single class for the entire application). Chapter 9 will discuss conditions
under which it makes sense to separate code into multiple smaller classes.
5.6 Example: HTTP parameter handling
After an HTTP request has been received by a server, the server needs to
access some of the information from the request. The code that handles the
request in Figure 5.1 might need to know the value of the photo_id
parameter. Parameters can be specified in the first line of the request
(photo_id in Figure 5.1) or, sometimes, in the body (comment and priority in
Figure 5.1). Each parameter has a name and a value. The values of
parameters use a special encoding called URL encoding; for example, in the
value for comment in Figure 5.1, “+” is used to represent a space character,
and “%21” is used instead of “!”. In order to process a request, the server will
need the values for some of the parameters, and it will want them in
unencoded form.
Most of the student projects made two good choices with respect to
parameter handling. First, they recognized that server applications don’t care
whether a parameter is specified in the header line or the body of the request,
so they hid this distinction from callers and merged the parameters from both
locations together. Second, they hid knowledge of URL encoding: the HTTP
parser decodes parameter values before returning them to the Web server, so
that the value of the comment parameter in Figure 5.1 will be returned as
“What a cute baby!”, not “What+a+cute+baby%21”). In both of these cases,
information hiding resulted in simpler APIs for the code using the HTTP
module.
However, most of the students used an interface for returning parameters
that was too shallow, and this resulted in lost opportunities for information
hiding. Most projects used an object of type HTTPRequest to hold the parsed
HTTP request, and the HTTPRequest class had a single method like the
following one to return parameters:
public Map<String, String> getParams() {
return this.params;
}
Rather than returning a single parameter, the method returns a reference to
the Map used internally to store all of the parameters. This method is shallow,
and it exposes the internal representation used by the HTTPRequest class to
store parameters. Any change to that representation will result in a change to
the interface, which will require modifications to all callers. When
implementations are modified, the changes often involve changes in the
representation of key data structures (to improve performance, for example).
Thus, it’s important to avoid exposing internal data structures as much as
possible. This approach also makes more work for callers: a caller must first
invoke getParams, then it must call another method to retrieve a specific
parameter from the Map. Finally, callers must realize that they should not
modify the Map returned by getParams, since that will affect the internal state
of the HTTPRequest.
Here is a better interface for retrieving parameter values:
public String getParameter(String name) { ... }
public int getIntParameter(String name) { ... }
getParameter returns a parameter value as a string. It provides a slightly
deeper interface than getParams above; more importantly, it hides the internal
representation of parameters. getIntParameter converts the value of a
parameter from its string form in the HTTP request to an integer (e.g., the
photo_id parameter in Figure 5.1). This saves the caller from having to
request string-to-integer conversion separately, and hides that mechanism
from the caller. Additional methods for other data types, such as
getDoubleParameter, could be defined if needed. (All of these methods will
throw exceptions if the desired parameter doesn’t exist, or if it can’t be
converted to the requested type; the exception declarations have been omitted
in the code above).
5.7 Example: defaults in HTTP responses
The HTTP projects also had to provide support for generating HTTP
responses. The most common mistake students made in this area was
inadequate defaults. Each HTTP response must specify an HTTP protocol
version; one team required callers to specify this version explicitly when
creating a response object. However, the response version must correspond to
that in the request object, and the request must already be passed as an
argument when sending the response (it indicates where to send the
response). Thus, it makes more sense for the HTTP classes to provide the
response version automatically. The caller is unlikely to know what version
to specify, and if the caller does specify a value, it probably results in
information leakage between the HTTP library and the caller. HTTP
responses also include a Date header specifying the time when the response
was sent; the HTTP library should provide a sensible default for this as well.
Defaults illustrate the principle that interfaces should be designed to make
the common case as simple as possible. They are also an example of partial
information hiding: in the normal case, the caller need not be aware of the
existence of the defaulted item. In the rare cases where a caller needs to
Another Random Document on
Scribd Without Any Related Topics
A Philosophy Of Software Design John Ousterhout
A Philosophy Of Software Design John Ousterhout
A Philosophy Of Software Design John Ousterhout
The Project Gutenberg eBook of The Legal
Position of the Clergy
This ebook is for the use of anyone anywhere in the United
States and most other parts of the world at no cost and with
almost no restrictions whatsoever. You may copy it, give it away
or re-use it under the terms of the Project Gutenberg License
included with this ebook or online at www.gutenberg.org. If you
are not located in the United States, you will have to check the
laws of the country where you are located before using this
eBook.
Title: The Legal Position of the Clergy
Author: Philip Vernon Smith
Release date: August 28, 2012 [eBook #40606]
Most recently updated: October 23, 2024
Language: English
Credits: Produced by David Clarke, Ian Swainson and the Online
Distributed Proofreading Team at http://www.pgdp.net
*** START OF THE PROJECT GUTENBERG EBOOK THE LEGAL
POSITION OF THE CLERGY ***
Handbooks for the Clergy
EDITED BY
ARTHUR W. ROBINSON, B.D.
VICAR OF ALLHALLOWS BARKING
BY THE TOWER
THE LEGAL POSITION OF
THE CLERGY
THE LEGAL POSITION OF
THE CLERGY
BY
P. V. SMITH, LL.D.
CHANCELLOR OF THE DIOCESE OF MANCHESTER
AUTHOR OF "THE LAW OF CHURCHWARDENS AND SIDESMEN
IN THE TWENTIETH CENTURY," ETC.
LONGMANS, GREEN, AND CO.
39 PATERNOSTER ROW, LONDON
NEW YORK AND BOMBAY
1905
All rights reserved
PREFACE
In the following pages an endeavour has been made to give a
succinct sketch of the legal position of the parish clergy of the
Church of England in respect both of spiritualities and of
temporalities. The book, being intended for their use, does not touch
upon the subject of ordination by which they acquired the status of
deacons or priests. Nor does it deal with the episcopate or the non-
parochial clergy, except so far as these subjects are connected with
the parochial system.
Like all other human arrangements, our English Church law is, of
course, far from being ideally perfect. It may be safely affirmed that
there has never been either a Church or a State in which the law has
actually been what it ideally ought to have been. It is important to
recognise the difference between the two positions; for there has
sometimes been a disposition on the part of individuals to confuse
them, and to treat what they consider to be the ideal law, as if it
were the actual law, and as if, as such, it demanded their loyal
obedience. Such an attitude, whether in ecclesiastical or civil
matters, is anarchical in its tendency; for it sets up private judgment
instead of the constituted authority as the criterion of what ought or
ought not to be done. It can only be justified where the actual law is
absolutely inconsistent with the fundamental principles of morality or
of Christian truth. The object of the present treatise is to state
succinctly what the law is,—not what it ought to be; and no opinion
is expressed or suggestion offered as to points in which amendment
would be proper or expedient.
Within the limited compass of the book it is obviously impossible to
enter into details; and the reader who desires information as to
these will find them in the authorities to which reference is made. It
must also be borne in mind that the general law on the subject of
P. V. SMITH.
buildings, property, and pecuniary rights is, in various places,
modified by special local enactments or customs. These can only be
ascertained on the spot, or by consulting the Acts of Parliament in
which they are embodied or recorded.
One other word of caution is desirable. In explaining the legal
position of the parochial clergy, it is, of course, necessary to indicate
the exact limits of their rights. If they venture beyond these limits,
they are manifestly in the wrong. But no community, either
ecclesiastical or civil, could maintain its well-being, or even its
coherence, if every individual were on all occasions to take
advantage of the full tether of his legal rights. It will frequently be
wise and proper for the clergy, in their relations with their
ecclesiastical superiors or with the lay officials and other laity of the
parish, not to adopt the most uncompromising attitude which the
letter of the law permits to them. The dictates of love and of
Christian forbearance, and of consideration for the claims of others,
as well as of expediency, will not warrant the infringement by an
individual of the ordinances of either the Church or the State. But
they will more than justify him in refraining from taking up a position
of defiance which these ordinances may strictly entitle him to
assume.
Easter, 1905.
pages xxi-xiv
pages 1-24
CONTENTS
List of Abbreviations
CHAPTER I
General Legal Position
1.Spiritual, ecclesiastical, and civil status of the clergy. 2. Sources of
Church law. 3. Written and unwritten law—Foreign Canon law—Pre-
Reformation Canons—Acts of Parliament—Canons of 1603—Canons
of 1640—Other canons. 4. Decisions of Church courts—Distinction
between judicial and legislative action. 5. Legal status of the ancient
Parish—Rector or Parson—Patronage or Advowson—Vicar—Perpetual
curate. 6. Dissolution of the Monasteries—Impropriate rectories—
New churches and ecclesiastical parishes—Assistant parochial clergy
—Titular vicars—Incumbent—Curate. 7. Minister in charge—Lecturer.
8. Status of clergy ordained elsewhere than in England or Ireland, or
ordained for service in the colonies or foreign countries—Scottish
clergy. 9. Benefices—Beneficed and unbeneficed clergy. 10. Bishops,
their relation to the clergy—Suffragan bishops—Chancellors. 11.
Archdeacons. 12. Rural Deans. 13. Judicial procedure—Church
Discipline Act, 1840—Public Worship Regulation Act, 1874—Clergy
Discipline Act, 1892. 14. Abstinence of Clergy from secular pursuits.
15. Civil exemptions—Municipal and Parliamentary qualifications and
disqualifications. 16. Restrictions as to labour, business, and trade—
Lawful exceptions—Penalties for unlawful trading. 17. Protection in
performance of religious rites—Act against brawling. 18. Indelibility
of Orders—Relinquishment of clerical status
CHAPTER II
Beneficed Clergy
1. Admission by bishop on presentation of patron—Lapse to bishop,
archbishop, or Crown. 2. Transfers of advowsons or rights of
presentation—Next presentations—Power of patron to present
himself—Restrictions under Benefices Act, 1898. 3. Qualification for
admission—Grounds for refusal by bishop—Testimony as to fitness.
4. Procedure in case of refusal by bishop. 5. Publication of notice of
intended admission. 6. Mode of admission—Institution—Licence—
Collation—Declarations of assent and against simony—Oaths of
allegiance and canonical obedience—Reading of Thirty-nine Articles.
7. Effect of admission—Induction. 8. Fees on admission. 9. Cure of
Souls—Duties laid down in Ordination Service—Residence—Divine
service—Marriages—Burials—Private ministrations. 10. Exclusive
right of administration—Superior right of bishop—Modern comity as
between town parishes. 11. Private ministrations—Service in
unconsecrated buildings—Meetings for worship. 12. Private chapels
—Chapels of institutions—Unconsecrated proprietary chapels. 13.
Formation of new parishes—Approval or otherwise of incumbent. 14.
Holding of two benefices. 15. Neglect of duty—Commission of
inquiry—Procedure on adverse report of Commission. 16. Residence
on benefice—Forfeitures for non-residence—Bishop's licence of non-
residence—Grounds for licence. 17. Monition, sequestration, and
avoidance of benefice for non-residence. 18. Performance of duties
where incumbent is non-resident. 19. Restrictions on interfering with
duties during period of non-residence. 20. Reckoning of time as to
residence. 21. Vacation of benefice by death, resignation, admission
to other preferment, or deprivation. 22. Resignation; unconditional
except upon an exchange—Engagement to resign illegal except
under Clergy Resignation Bonds Act, 1828—Corrupt resignations and
exchanges—Pensions under Incumbents Resignation Acts. 23.
Vacation of benefice on admission to other preferment. 24.
pages 25-54
pages 55-64
Deprivation ipso facto—Declaration of vacancy by bishop on
conviction of incumbent in certain cases—Sentences of deprivation
under Acts of 1840 and 1892
CHAPTER III
Unbeneficed Clergy
1. Classes of unbeneficed clergy—Bishop's licence—Declaration of
assent—Examination and admission by bishop—Discretion of bishop
—Revocation of licence. 2. Curates or ministers in charge—(a) On
vacancy of benefice—(b) On sequestration of benefice for
incumbent's bankruptcy or debt—(c) On incumbent's non-residence
—(d) On incumbent's neglect of duties—(e) On formation of Peel
district. 3. Assistant curates—Stipend—Notice to quit or relinquish
curacy—Discretion of incumbent as to employment—Appointment
where duties are inadequately performed; or where circumstances of
parish require it. 4. Performance of duty by other clergy—Discretion
of incumbent—Licence of bishop—Production of licence and entry of
names of preachers in a book. 5. Lecturers and preachers—
Performance of other ministerial duties
CHAPTER IV
Laity of the Parish
1. Relations between incumbent and lay officials. 2. The vestry—
Constitution, meetings, and voting in ancient parishes, and in new
parishes—Vestries Act, 1818—Present functions—Select vestries. 3.
Churchwardens—Election in ancient and new parishes—Admission.
4. Parson's or vicar's and people's wardens—Duties: (a) Care of
fabric and ornaments of the church and of the churchyard—(b)
Seating of parishioners—(c) Provision of requisites for service—(d)
pages 65-79
Maintenance of order in church and churchyard—(e) Collection and
concurrence in disposal of offertory money—(f) Charge of church
and benefice during vacancy, if appointed sequestrators—
Restrictions on powers. 5. Sidesmen. 6. Church trustees. 7. Parish
clerk—Appointment and removal. 8. Sexton. 9. Beadle. 10. Organist
and choristers. 11. Officiating of lay readers and other laymen. 12.
Other lay work—Visiting of poor and sick—Sunday schools—Church
elementary schools. 13. Parochial church councils
CHAPTER V
Divine Service
1. Duty of clergy as to uniformity of service—Divergence by lawful
authority—Liberty under Act of 1872. 2. Morning and Evening Prayer
—Litany—Bishop 0.5em;">may order two full services, and a third
service, with sermon. 3. Notices during Divine service—Notices on
church door—Banns. 4. Offertory—Other collections in a church or
chapel—Duty of incumbent as to money entrusted to him. 5.
Questions as to the legality of various church ornaments, vestments,
and ceremonies—Legal decisions as to (A) Stone Holy Table—Crucifix
—Cross—Candlesticks—Flower-vases—Pictures—Sculptures—
Credence table—Second Holy Table—Chancel gates—Baldacchino—
Voice of parishioners in vestry—(B) Attire of clergy at Holy
Communion—Surplice—Hood—Albe—Vestment or chasuble—Tunicle
—Stole—Chaplain's scarf—Biretta—Black gown—(C) Incense—
Processions with lighted candles—Lighted candles at Holy
Communion—Mixed chalice—Wafers—Agnus Dei and other hymns—
Position of minister—Genuflexions—Elevation—Sign of the Cross—
Ablutions—Reservation. 6. Baptism not to be refused—Time for the
ceremony—Private baptism in urgent cases—Godparents—Reception
in church after private baptism—Conditional baptism—Immersion or
affusion—Notice to bishop in cases of adult baptism—Deacon may
baptize—Lay baptism. 7. Times for and notice of Holy Communion—
pages 80-99
Communion not to be unlawfully refused—Who are to be repelled
from it—Procedure in such cases—Jenkins v. Cook—Persons coming
from other parishes—Persons attending dissenting places of worship
—Persons baptized in another communion and not confirmed. 8.
Sermons and homilies—Provisions of rubrics, Canons, and Acts of
Parliament. 9. Catechising. 10. Churching of women
CHAPTER VI
Marriage
1. Duty of minister to solemnise marriage between persons legally
competent—Unlawful solemnisation, when a felony—Marriage, when
void. 2. Original places for banns and marriages—Churches of new
parishes—Licences for banns and marriages in chapels—Parishes
having no regular services in parish church—Where parish church is
being rebuilt or repaired—No reconsecration necessary where church
is rebuilt or enlarged and position of Holy Table altered. 3. Persons
legally competent to intermarry—Religion or absence of religion of
the parties no ground for refusal to solemnise marriage. 4. Minimum
age—Consent of parents or guardians in case of unions—Marriage
without consent, in absence of notice—Marriage below lawful age. 5.
Marriage of lunatic or non compos, void. 6. Absence, unheard of, for
seven years—Relief from punishment for bigamy—Invalidity of
remarriage. 7 Divorce abroad—Divorce in England under Act of 1857
—Remarriage of divorced persons. 8. Marriage of foreigners—
Requirements of laws of foreign States—Precautions to be observed.
9. Prohibited degrees of kindred and affinity. 10. Publication of
banns—Time and form—Seven days' notice—Publication and
marriage without notice and due inquiry—Publication where parties
dwell in different parishes or districts—Where one dwells in Scotland,
or in Ireland—What constitutes dwelling—Correct names to be
published—Status need not be published—Publication to be from
book and signed—Forbidding of banns. 11. Marriage, with consent of
pages 100-120
minister, on registrar's certificate—Not permitted on registrar's
licence. 12. Marriage on licence of bishop or Archbishop of
Canterbury—Grant of bishop's licence—Previous affidavit before
surrogate—Duty of minister on production of licence—Names in
licence—Grant of licence a favour and not a right. 13. Marriage,
where and when to be solemnised—Priest or deacon may marry—
Penalty for solemnising marriage at improper place or time. 14.
Reading of service after marriage at a registry office—Second
solemnisation of marriage. 15. Fees for banns, certificate of banns,
and marriage. 16. Marriage register books—Certificate of marriage.
17. Presumption of marriage of persons coming to Holy Communion
—Proof of no marriage—Validity of marriage governed by law of
place of solemnisation—Capacity to contract marriage governed by
law of domicile—-Marriage between British subjects in a foreign
country or on board ship
CHAPTER VII
Burial
1. Right of burial by clergyman of the parish where death occurs—
Bells to be rung—Burial in case of death in another parish—Relief in
case interment is refused—No right to particular hour or spot of
burial—Incumbent or churchwardens cannot sell or grant grave-
spaces in perpetuity or brick graves—Reservation of exclusive right
of burial on grant of addition to churchyard—Faculty for exclusive
grave space in other cases—Burial of non-parishioners not dying
within the parish. 2. Burial of bodies cast up by the sea or tidal or
navigable water. 3. Burial of person dying unbaptized or
excommunicate and of felo de se—Burial of child of dissenter or
person who has received lay baptism—Interment cannot be required
without convenient warning. 4. Bringing of corpse into church and
burial under church. 5. Fees—Prepayment not enforceable—
Customary amount—On burial of non-parishioners—Tables of fees—
pages 121-134
pages 135-140
Special fees for brick graves, iron coffins, and other extras—Fees and
rights of burial where new ecclesiastical parish has its own burial
ground. 6. Use of Burial Service in unconsecrated ground—Use of
special form—Permission of burial without Church rites and with or
without some other service on notice under Act of 1880—Day and
time for burial—Fee. 7. Delivery of registrar's certificate of death or
order of coroner at funeral. 8. Fees on interments in cemeteries
under Cemeteries Clauses Act, 1847. 9. Burial Acts—Consecrated
and unconsecrated parts of burial grounds—Chapels—Fees of
incumbents, clerks, and sextons—Sale of rights to vaults and
monuments—Burial Act, 1900—Tables of fees—Restrictions on future
fees to incumbents, churchwardens, and sextons—Commutation of
fees. 10. Cremation—Burial of cremated remains. 11. Faculty for
removal of body from one unconsecrated place of interment to
another—Licence of Home Secretary for removal in other cases
CHAPTER VIII
Private Ministrations
1. Visitation and Communion of the Sick—-Canon 67—Order for the
Visitation—Confession and absolution of the sick—Regulations as to
Communion. 2. Preparation for Confirmation. 3. Spiritual advice and
comfort—Confession—Absolution. 4. Ordinary visitation and
intercourse
CHAPTER IX
Temporalities
1. Possessions and revenues of benefices of ancient parishes and
new ecclesiastical parishes. 2. Incumbent a corporation sole—
Restrictions on his acquisition and holding of landed property—
Licence in mortmain—Mortmain and Charitable Uses Acts—School
Sites Acts—Inability to hold as a corporation land upon trusts. 3.
Freehold of church and churchyard of ancient parish in rector—
Chancel repairable by rector—Enforcement of repairs—Possession
and custody of church in incumbent and churchwardens—Right of
incumbent to keys and control of organ and bells—Canon 88—Right
of rector to profits of soil of churchyard—Felling of trees in
churchyard—Freehold of church and churchyard of new parish in
incumbent—Exemption from rates and contributions to making new
streets—Removal of part of church as a dangerous structure. 4.
Rights of bishop and parishioners in church and churchyard—Power
of incumbent as to ordinary tombstones and inscriptions in
churchyard—Glass shades for wreaths—Appeal to consistory and
higher courts—Faculties for monuments in church and other
alterations and additions in church and churchyard—Application by
incumbent and churchwardens after resolution of vestry—Consent of
rector to alteration in chancel—Faculty for vault or space for
exclusive burial—Removal of earth or bones from churchyard, or
other desecration—Faculty for diversion of ancient footpath through
churchyard, and for throwing part of churchyard into highway—
Restoration of wall wilfully thrown down—Easement of light and air
over churchyard—Laying out of closed churchyard as a garden and
removal of gravestones—Restrictions as to building on closed or
disused burial-grounds. 5. Glebe, rectorial and vicarial—Exemption
from tithe—Waste—Cultivation of glebe—Cutting down of trees—
Opening and working of mines and quarries and gravel pits. 6.
Statutory facilities for parsonage houses and other buildings and
repair of chancels—Gilbert Acts—Loans by, and mortgages to Queen
Anne's Bounty—Purchase of land—Building and improving of farm
buildings and labourers' dwellings—Gifts and bequests of parsonage
houses and glebe—Sale and exchange of parsonage houses and
glebe. 7. Letting of parsonage house where incumbent has licence to
reside elsewhere. 8. Farming or letting of glebe—Agricultural,
building, and mining leases. 9. Repair of parsonage house and glebe
buildings—Ecclesiastical Dilapidations Act, 1871. 10. Diocesan
surveyors—Proceedings (a) on vacancies in benefices and (b) in
other cases—Exemption from liability for five years after certificate of
surveyor. 11. (a) Inspection and report by surveyor on a vacancy—
Objections to report—Order of bishop—Debt from late incumbent, or
his estate, to new incumbent—Payment of amount recovered to
Queen Anne's Bounty—Loan of amount not recovered—Balance to
be paid by new incumbent—Dilapidation Account—Liability where a
vacancy occurs between inspection of buildings and certificate of
completion of works. 12. (b) Inspection of buildings on complaint of
archdeacon, rural dean, or patron, or on request of incumbent—
Inspection after and during sequestration of benefice—Report—
Objections—Decision of bishop—Loans—Dilapidation Account—
Execution of repairs—-Charge of cost on income in case of benefice
under sequestration—Vacancy before execution of works—Liability of
sequestrator spending excessive amount on repairs. 13. Payment of
money out of dilapidation account on certificate of surveyor—Liability
and duty of incumbent—Rebuilding or remodelling instead of
repairing. 14. Insurance of parsonage house, glebe buildings, and
chancel against fire—Production of receipts for premiums at
visitations—Payment and application of insurance money and
reinstatement of buildings in the event of fire—Sequestration of
benefice to raise any requisite balance. 15. Exemption from Act of
1871 of buildings let on lease under which tenant is liable—
Inspection by surveyor. 16. Faculty or consent of bishop and patron
to alterations in buildings—Liability of incumbent for alterations not
so sanctioned—Power of bishop to authorise removal of unnecessary
buildings—Movable sheds or garden frames. 17. Vacation of benefice
—Cesser of rights of former incumbent—Right of widow to two
months' residence in parsonage house—Inspection of premises
pending settlement of dilapidations—Emblements—Apportionment of
rents, tithe rentcharge, and other income. 18. Tithe commutation
rentcharge under Act of 1836 and amending Acts—Assessment in
lieu of great or rectorial tithes and small or vicarial tithes—
Extraordinary tithe rentcharge in respect of hop and other gardens
and orchards—Act of 1886—Assessment of tithe rentcharge with
regard to prices of wheat, barley, and oats—Variation according to
pages 141-168
pages 169-174
septennial average prices. 19. Payment of tithe rentcharge and
recovery by distress on appointment of receiver—Recovery from
railway company. 20. Dues (i.) ordinary and (ii.) special—Variety by
law and custom—Payments on the customary four offering days—
Easter offerings—Rights of vicar of new ecclesiastical parish. 21.
Mortuaries. 22. Dues for special services or concessions. 23. Pew
rents under special or general Acts of Parliament—Under Church
Building and New Parishes Acts—Recovery of pew rents. 24. First
fruits and tenths—Exemption of small benefices—Number of
benefices remaining liable. 25. Income or property tax—On
parsonage house, glebe lands, and tithe rentcharge—On landed
property in occupation of incumbent—On other stipend, fees,
perquisites, and profits—Legal deductions—Test as to whether
receipts are or are not liable to tax—Voluntary contributions to
minister in respect of his office—Grants from Curates' Augmentation
Fund—Grants from Queen Victoria Clergy Fund
Index
LIST OF ABBREVIATIONS
A. C.
Law Reports (House of Lords and Privy Council)
1891 onwards.
A. & E. Adolphus & Ellis's Reports (King's Bench)1834-41.
Add. Addam's Reports (Ecclesiastical) 1822-6.
Ambl. Ambler's Reports (Chancery) 1737-83.
App. Ca.
Law Reports (House of Lords and Privy Council)
1875-90.
Atk. Atkyn's Reports (Chancery) 1735-54.
Ayl. Par. Ayliffe's Parergon Juris Canonici Anglicani, 1726.
B. & C.
Barnewall & Cresswell's Reports (King's Bench)
1822-30.
B. & Ad.
Barnewall & Adolphus' Reports (King's Bench) 1830-
34.
B. & Ald.
Barnewall & Alderson's Reports (King's Bench)
1818-22.
B. & Sm. Best & Smith's Reports (Queen's Bench) 1861-70.
Beav. Beavan's Reports (Chancery) 1838-66.
Bl. Comm. Blackstone's Commentaries on the Laws of England.
Burn. Burn's Ecclesiastical Law, 4 vols.
Canon.
One of the Constitutions and Canons Ecclesiastical
agreed upon in the Canterbury convocation begun
in 1603.
C. B. Common Bench Reports, 1845-56.
C. B. N. S. Common Bench Reports, New Series, 1856-65.
C. & K.
Carrington & Kirwan's Reports (Nisi Prius) 1843-
1853.
C. P. D. Law Reports (Common Pleas Division) 1875-80.
Ch. Law Reports, Chancery Division, 1891 onwards.
Ch. D. Law Reports, Chancery Division, 1875-90.
Cl. & F. Clark & Finnelly's Reports (House of Lords) 1831-46.
Clarke, Proxis
Francis Clarke's Proxis in Curiis Ecclesiasticis, 1666,
1684.
Co. Inst.
Coke's Institutes of the Laws of England, Second
Part.
Co. Litt.
Coke upon Littleton (with notes by Hargrave and
Butler).
Co. Rep. Coke's Reports, 1598-1616.
Com. Dig. Comyn's Digest.
Cowp. Cowper's Reports (King's Bench) 1774-78.
Cripps.
Cripps's Law relating to the Church and Clergy, 6th
ed., 1886.
Cro. Jac. Croke's Reports (temp. James I.) 1603-1625.
Curt. Curteis's Ecclesiastical Reports, 1834-44.
Degge. Sir Simon Degge's Parson's Counsellor.
Dr. & Sm. Drewry & Smale's Reports (Chancery) 1859-65.
E. & B. Ellis & Blackburn's Reports (Queen's Bench) 1854-8.
Eccl. & Adm. Ecclesiastical & Admiralty Reports (Spinks) 1853-5.
El. & El. Ellis & Ellis' Reports (Queen's Bench) 1858-61.
Ex. Exchequer Reports, 1847-56.
Ex. D. Law Reports (Exchequer Division) 1875-1880.
Geary
Geary's Law of Marriage and Family Relations (A. &
C. Black, 1892).
Gibs. Cod. Gibson's Codex Juris Ecclesiastici Anglicani.
Hag. Cons. Haggard's Consistory Reports, 1729-1821.
Hag. Eccl. Haggard's Ecclesiastical Reports, 1827-1832.
H. & C.
Hurlstone & Coltman's Reports (Exchequer) 1862-
66.
H. L. C. House of Lords Cases, 1847-66.
Hob. Hobart's Reports, 1611-20.
Ir. Ch. Rep.
App.
Irish Chancery Reports (Appendix).
J. & H. Johnson & Hemming's Reports (Chancery) 1859-62.
J. P. Justice of the Peace, 1837 onwards.
Johns.
John Johnson's Clergyman's Vade Mecum, 6th ed.,
1731.
Jur. Jurist (Reports) 1837-54.
Jur. N. S. Jurist, New Series (Reports) 1855-66.
K. B. Law Reports (King's Bench) 1901 onwards.
L. J. (Ch., C.P.,
Ex. Q.B.)
Law Journal 1823-31; New Series 1832 onwards
(Chancery, Common Pleas, Exchequer, Queen's
Bench).
L. J. Eccl. Ditto (Ecclesiastical Cases).
L. J. M. C. Ditto (Magistrates' Cases).
L. J. P. M. & A. Ditto (Probate, Matrimonial, and Admiralty Cases).
L. R. A. & E. Law Reports, 1865-75 (Admiralty and Ecclesiastical).
L. R. C. P. Ex.
Q. B.
Ditto (Common Law).
L. R. Ch. Ditto (Chancery Appeals).
L. R. Eq. Ditto (Equity).
L. R. H. L. Ditto (House of Lords).
L. R. H. L. Sc. Ditto (Scotch and Divorce Appeals).
L. R. P. C. Ditto (Privy Council).
L. T. N. S. Law Times (New Series) Reports, 1859 onwards.
M. & S. Maule & Selwyn's Reports (King's Bench) 1813-17.
M. & W. Meeson & Welsby's Reports (Exchequer) 1836-47.
Marsh. Marshall's Reports (Common Pleas) 1813-1816.
Mer. Merivale's Reports (Chancery) 1815-17.
Moo. P. C. Moore's Privy Council Reports, 1836-62.
Moo. P. C. N.
S.
Ditto, New Series, 1862-73.
N. R. New Reports (Equity and Common Law) 1862-65.
Not. of Ca.
Notes of Cases (Ecclesiastical and Maritime) 1841-
50.
P. Law Reports, Probate Division, 1891 onwards.
P. D. Law Reports, Probate Division, 1875-90.
Phill. Phillimore's Reports (Ecclesiastical) 1809-1821.
Phill. Eccl. Law
Phillimore's Ecclesiastical Law of the Church of
England, 2 vols., 2nd ed., 1895.
P. Wms. Peere Williams' Reports (Chancery) 1695-1735.
Q. B. Queen's Bench Reports (Adolphus & Ellis) 1841-52.
Q. B. Law Reports (Queen's Bench) 1891-1900.
Q. B. D. Law Reports (Queen's Bench Division) 1875-1890.
Rob. Eccl. Robertson's Reports (Ecclesiastical) 1844-1853.
Sc. L. R. Scottish Law Reporter, 1865 onwards.
Sm. Churchw.
Smith's Law of Churchwardens and Sidesmen in the
Twentieth Century (Wells, Gardner, & Co., 2s.).
Str. Strange's Reports, 1715-47.
Strype's
Annals
John Strype's Annals of the Reformation (ed. 1824)
4 vols.
Sw. & Tr.
Swabey & Tristram's Reports (Probate and Divorce)
1858-65.
Taun. Taunton's Reports (Common Pleas) 1807-1819.
Times Law
Rep.
Times Law Reports, 1884 onwards.
T. R.
Durnford & East's Term Reports (King's Bench)
1785-1800.
Trist. Cons.
Judgm.
Tristram's Consistory Judgments, 1872-90.
Ventr. Ventris' Reports (King's Bench) 1668-91.
Ves. Vesey Junior's Reports (Chancery) 1789-1816.
Wats. Watson's Clergyman's Law, 4th ed., 1747.
Willes Willes Reports (Common Pleas) 1737-58.
Wils. Wilson's Reports (Common Law) 1743-74.
W. R. Weekly Reporter, 1853 onwards.
Yo. & Jer. Younge & Jervis's Reports (Exchequer) 1826-30.
A Philosophy Of Software Design John Ousterhout
CHAPTER I
GENERAL LEGAL POSITION
1. In every country where a Christian Church is permitted to exist,
the power and authority of her clergy to exercise their functions will
rest upon a triple basis and be subject to twofold restrictions and
limitations. In the first place, (i.) they derive their spiritual authority
from their ordination, and this authority is independent of the
particular Church to which they belong. But, in the next place, they
are bound on the one hand (ii.) to obey the regulations of the
Church of which they are the ministers, and must also, on the other
hand, (iii.) conform to the laws of the country in which they labour.
For they can only actively exercise their functions by the licence or
permission of the ruling power of that country, and subject to any
conditions which it may choose to impose. These principles apply
equally whether the Church is what we call established or not. The
only difference is that if the Church is established, her own
regulations are part of the law of the land; whereas, if she is not
established, the law of the land sanctions or suffers the existence of
these regulations as a private contract or arrangement between the
ministers and other members of the Church. But even in the case of
an established Church, her ministers will obviously be restricted in
the exercise of their functions by civil regulations which do not form
part of the ecclesiastical law. Thus there may be nothing in the law
of his Church to prevent a clergyman from holding a religious service
or preaching in a crowded thoroughfare. But in England and other
civilised countries any attempt to do so would be checked by the
existing laws against the obstruction of highways. In the following
pages no attempt will be made to point out the non-ecclesiastical
laws and limitations to which a parish priest is subject. For though
they necessarily affect himself and his spiritual work, they do so only
indirectly. They touch him not as a minister or even as a Christian,
but as a citizen; and they touch his spiritual work only in so far as
that work has a material and civil element.
2. Confining then our attention to the ecclesiastical law under which
the parish priest holds his position and acts in this country, we note
in the first place, that the Church being here established, this
ecclesiastical law is equally the law of the Church and the law of the
State. This is true whatever be its origin, and however it came into
force; and it has always had this double aspect, since (with the
exception of the brief interval of the Commonwealth—a period which
is not recognised in our jurisprudence as having had any legal
existence) there never has been a time in our history when the
Church of England has not been the Established Church of the
nation. Portions of our Church system and Church law have had an
exclusively ecclesiastical origin, by canon or otherwise, and have
been adopted or acquiesced in by the State. Further portions have
been created by the joint or concurrent action of the Church and the
State. Other portions again have been due to the sole action of the
civil legislature, which has received the tacit assent of the Church
but has never been confirmed by any formal ecclesiastical
ratification. From whichever of these three sources any particular
point of our Church law may have been derived, its validity and
obligation is the same. It binds the Church and her ministers and
members irrespectively of its origin, and is at present in force unless
it has either been formally repealed or become obsolete and fallen
into desuetude.
3. Again, like our civil law, our ecclesiastical law is in part written
and in part unwritten or customary. Foreign canon or conciliar law or
papal law is only binding in England so far as it has been received by
immemorial custom, and has thus become part of our unwritten law,
or has been incorporated into our written law by the ratification of
an Act of Parliament, or a canon or constitution of our own Church;
and the binding force of the English Pre-Reformation canons,
ordinances, and provincial constitutions stands on the same footing.
For the Commission authorised by the Act for the Submission of the
Clergy of 1533 to examine the English canons and constitutions,
and, with the king's assent, declare which of them should be in force
and which should be abrogated, was never appointed, although the
time for its appointment was extended by Acts of 1535 and 1543,
and the scope of its inquiry was extended by the latter Act so as to
include foreign canons and ordinances.[1] Consequently the only
written Church law is to be found in Acts of Parliament and the
Prayer-Book,[2] and in Post-Reformation canons, which, however,
except so far as they are confirmed by Act of Parliament, or declare
the unwritten law of the Church, are only binding on the clergy.[3] Of
these the chief are those known as the Canons of 1603, which were
agreed upon at the sitting of the Canterbury Convocation begun in
that year, and were separately passed two years afterwards by the
York Convocation. Many portions of them are, however, now
obsolete; and Canon 36 and the last words of Canon 102 have been
superseded by new canons made in 1865-66 and 1888. The Canons
of 1640 were passed after the dissolution of Parliament, which,
according to the custom of the realm, put an end also to the
existence of Convocation, and they have no legal force.[4]
4. Much discussion has arisen upon a fourth source of Church law,
namely, the decisions of our ecclesiastical courts. It is important to
draw a clear distinction between legislative and judicial functions. A
court, whether ecclesiastical or civil, has nothing to do with enacting
laws. Its province is confined to interpreting them, when their
meaning is obscure or disputed. No doubt, in the course of this
interpretation, it will sometimes make law by deciding in a particular
way a point on which the legislature has left the matter in doubt,
and has not itself clearly laid down the law. Many questions affecting
the clergy and the Church have, in fact, been thus determined by
our civil as well as by our ecclesiastical tribunals. But if one of our
civil courts, in interpreting the civil law, delivers a decision which
does not commend itself to the common sense of the nation, it is
recognised that the remedy lies not in altering the constitution of the
court and endeavouring to obtain a fresh legal decision which shall
upset the other, but in obtaining an Act of Parliament expressly over-
ruling the unsatisfactory decision. If this is not done, the law may
have been technically judge-made, but it is acquiesced in and
assented to by Parliament and the nation. The same principle applies
to the decisions of ecclesiastical courts. The natural way of getting
rid of an obnoxious decision is not by fresh adjudication, but by
legislation. Until it has been reversed by one or other of these
means, the decision of a court, which de facto possesses
ecclesiastical jurisdiction, is binding upon the Church as part of her
law for the time being. We have somewhat lost sight of this
principle, owing to the extreme difficulty of obtaining any definition
or alteration of Church law by a legislative process. But the true
remedy lies in a healthy revival of the exercise of ecclesiastical
legislation, and not in an endeavour to make the ecclesiastical
judicature, whether as now existing or after a reform of the courts,
discharge legislative functions which are wholly outside its proper
province.
5. The legal position of the parochial clergy depends for its ultimate
origin upon the legal status of the ancient Parish. The word is the
English form of the Greek παροικία (habitation), and the Latin
parochia, an expression originally synonymous with diocese (Gr.
διοίκησις, i.e. administration; Lat. diœcesis, used of a district or part
of a province in the Roman Empire), and applied to the territory
assigned to the jurisdiction of a bishop, which was served by him
and a college of clergy under him. But under Archbishop Theodore
(668-690) or shortly after his time the process was begun of
encouraging the lords of manors and great landowners to build
churches for themselves and their dependants, and devote the tithes
of their manors or estates to the maintenance of divine worship in
these churches, and the performance of religious duties among the
residents on the estates. This process was gradually extended
throughout the country, and, wherever it was adopted, the tithes
were assigned either to the priest for the time being in charge of the
church, who was in that case called the rector (governor of the
church) or parson (Lat. persona)[5] or to a monastery, the members
of which were then expected to serve the church. The manor or
estate, including any detached and outlying portions, became the
parish of the church, and developed into a territorial unit not only for
ecclesiastical but also for many civil purposes. Where the church was
served by a single rector, the landowner who had endowed it and his
successors after him were given in return the right of nominating to
the bishop a clerk in Holy Orders to become rector of the church, or,
in other words, they acquired the patronage or advowson[6] of the
benefice. The frequent cases of neglect in the service of the parish,
where a monastery was rector, led, in the thirteenth century, to the
requirement that in such cases a succession of individual priests
should be appointed to discharge the duty, with a definite portion of
the endowments of the benefice as their stipend for so doing. As a
rule the great tithes, being those of corn, grain, hay, and wood,
were reserved to the monastery, and were in consequence styled
rectorial tithes, while the officiating priest, who was styled a vicar,
was endowed with the remaining or small tithes, which consequently
were called vicarial. But in a few instances the officiating priest,
instead of becoming entitled to the small tithes, only received a fixed
monetary stipend. Where this occurred, he was called a perpetual
curate. It was the rule that rectories, whether in the hands of a
monastery or a succession of individual priests, should be endowed
not only with the tithes of the parish, but also with a house and
lands, which are called glebe; and sometimes these houses and
lands, or a part of the lands, were assigned towards the stipend of
the vicar.
6. Towards the close of Henry VIII.'s reign the monasteries were
dissolved, and their rectories and the rectorial tithes of the parishes
and other endowments attached thereto, and the right of
nominating vicars or perpetual curates to the parishes passed, with
the rest of the monastic property, in some cases into the hands of
the Crown or of private individuals who received grants of them from
the Crown, while in other cases they went to the endowment of
episcopal sees or of colleges, hospitals, or other public institutions.
Whichever happened, the rectory and rectorial tithes became
thenceforth impropriate, and the vicar or perpetual curate was left
with the vicarial tithes and other endowments, or a stipend, as the
case might be, to serve the parish as the beneficed parish priest.
Later on, and particularly during the nineteenth century, the growth
of the population and the rapid increase of our urban centres, owing
to the steady migration from the villages to the towns, has rendered
the building of new churches and the creation of new ecclesiastical
areas a matter of pressing importance; and the same causes have
necessitated the employment in the larger parishes of additional
clergy, whether stipendiary or voluntary. In some cases an old parish
has been divided into distinct and separate parishes, each of which
has received a portion of the old church endowments, and has
become a rectory, vicarage, or perpetual curacy, according to the
status of the old parish;[7] or a vicarage has been converted into a
rectory upon a surrender of the rectorial tithes by the impropriator.
[8] But, as a rule, new ecclesiastical districts or parishes have been
formed and churches built without resorting to the old endowments;
and the Church Building and New Parishes Acts provided that the
ministers put in charge of these new districts or parishes and
churches should be perpetual curates, and should, like the old
rectors, vicars, and perpetual curates, be corporations, with
perpetual succession.[9] But in 1868 it was enacted that the
incumbent of every parish and new ecclesiastical parish, who was
authorised to publish banns, and solemnise marriages, churchings,
and baptisms in his church, and was not a rector, should, for the
purpose of designation only, be styled a vicar, and his benefice
should for the same purpose be styled a vicarage.[10] The modern
generic title, which includes every beneficed parish priest, is
incumbent. The proper and ancient term for rectors, vicars, and all
other parochial clergy, whether beneficed or unbeneficed, is curate,
as having the cure of souls within the parish.[11] But in modern
practice this term, when used by itself, is generally applied to the
unbeneficed or assistant curates in a parish.
7. Two other classes of parochial clergy remain to be mentioned.
Where, for any reason, the incumbent is for a prolonged period
disabled from performing the duties of his office, a substitute will be
appointed under the designation of Minister in Charge. Again, in
some parishes, lectureships have been endowed, and are held by a
lecturer, who, in respect of his duties as such, is independent of the
incumbent.
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.
More than just a book-buying platform, we strive to be a bridge
connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.
Join us on a journey of knowledge exploration, passion nurturing, and
personal growth every day!
ebookbell.com

More Related Content

PPTX
How to become a software developer
PDF
Modern Software Engineering Doing What Works To Build Better Software Faster ...
PPT
Methodology for Information System Project Management
PPTX
Writing Better Code - Helping Developers make Decisions.pptx
PDF
Usable Software Design
PDF
Learn To Code Like A Professional With Pythonan Open Source Versatile And Pow...
PPTX
How to become a Software Engineer Carrier Path for Software Developer
PPTX
To document or not to document? An exploratory study on developers' motivatio...
How to become a software developer
Modern Software Engineering Doing What Works To Build Better Software Faster ...
Methodology for Information System Project Management
Writing Better Code - Helping Developers make Decisions.pptx
Usable Software Design
Learn To Code Like A Professional With Pythonan Open Source Versatile And Pow...
How to become a Software Engineer Carrier Path for Software Developer
To document or not to document? An exploratory study on developers' motivatio...

Similar to A Philosophy Of Software Design John Ousterhout (20)

PPSX
Soft Eng 1st PPT
PDF
Core J2EE Patterns 1st Edition Deepak Alur
PDF
Download full ebook of Basics Of Programming Dg Junior instant download pdf
PDF
Simple Object Oriented Design (MEAP V04) Mauricio Aniche
PPT
Agile Methodologies And Extreme Programming - Svetlin Nakov
PDF
CSC 404 | Final Presentation
PDF
How To Become A Good C# Programmer
PPT
01.intro
PPT
Best practices for agile design
PPTX
Refactoring, 2nd Edition
PDF
TDD - Cultivating a Beginner's Mind
PDF
Software Development Standard Operating Procedure
PDF
Memos case study Innerworkings
PDF
So You Just Inherited a $Legacy Application...
PPT
Introduction to Agile Software Development & Python
PPT
Agile Methodologies And Extreme Programming
PDF
Surviving the technical interview
PDF
Systems Analysis and Design 8th Edition Kendall Solutions Manual all chapter ...
PDF
Software as a craft (February, 2018)
PDF
Analysis Of Algorithms An Active Learning Approach 1st Edition Jeffrey J Mcco...
Soft Eng 1st PPT
Core J2EE Patterns 1st Edition Deepak Alur
Download full ebook of Basics Of Programming Dg Junior instant download pdf
Simple Object Oriented Design (MEAP V04) Mauricio Aniche
Agile Methodologies And Extreme Programming - Svetlin Nakov
CSC 404 | Final Presentation
How To Become A Good C# Programmer
01.intro
Best practices for agile design
Refactoring, 2nd Edition
TDD - Cultivating a Beginner's Mind
Software Development Standard Operating Procedure
Memos case study Innerworkings
So You Just Inherited a $Legacy Application...
Introduction to Agile Software Development & Python
Agile Methodologies And Extreme Programming
Surviving the technical interview
Systems Analysis and Design 8th Edition Kendall Solutions Manual all chapter ...
Software as a craft (February, 2018)
Analysis Of Algorithms An Active Learning Approach 1st Edition Jeffrey J Mcco...
Ad

Recently uploaded (20)

PPTX
PLASMA AND ITS CONSTITUENTS 123.pptx
PDF
Nurlina - Urban Planner Portfolio (english ver)
PDF
The TKT Course. Modules 1, 2, 3.for self study
PDF
Everyday Spelling and Grammar by Kathi Wyldeck
PDF
Compact First Student's Book Cambridge Official
PPTX
UNIT_2-__LIPIDS[1].pptx.................
PPTX
2025 High Blood Pressure Guideline Slide Set.pptx
PPTX
Cite It Right: A Compact Illustration of APA 7th Edition.pptx
PDF
Solved Past paper of Pediatric Health Nursing PHN BS Nursing 5th Semester
PDF
Chevening Scholarship Application and Interview Preparation Guide
PPTX
Climate Change and Its Global Impact.pptx
PDF
Disorder of Endocrine system (1).pdfyyhyyyy
PPTX
Macbeth play - analysis .pptx english lit
PDF
Laparoscopic Colorectal Surgery at WLH Hospital
PDF
anganwadi services for the b.sc nursing and GNM
PDF
Hospital Case Study .architecture design
PPTX
principlesofmanagementsem1slides-131211060335-phpapp01 (1).ppt
PDF
Journal of Dental Science - UDMY (2022).pdf
PPTX
pharmaceutics-1unit-1-221214121936-550b56aa.pptx
PPTX
Case Study on mbsa education to learn ok
PLASMA AND ITS CONSTITUENTS 123.pptx
Nurlina - Urban Planner Portfolio (english ver)
The TKT Course. Modules 1, 2, 3.for self study
Everyday Spelling and Grammar by Kathi Wyldeck
Compact First Student's Book Cambridge Official
UNIT_2-__LIPIDS[1].pptx.................
2025 High Blood Pressure Guideline Slide Set.pptx
Cite It Right: A Compact Illustration of APA 7th Edition.pptx
Solved Past paper of Pediatric Health Nursing PHN BS Nursing 5th Semester
Chevening Scholarship Application and Interview Preparation Guide
Climate Change and Its Global Impact.pptx
Disorder of Endocrine system (1).pdfyyhyyyy
Macbeth play - analysis .pptx english lit
Laparoscopic Colorectal Surgery at WLH Hospital
anganwadi services for the b.sc nursing and GNM
Hospital Case Study .architecture design
principlesofmanagementsem1slides-131211060335-phpapp01 (1).ppt
Journal of Dental Science - UDMY (2022).pdf
pharmaceutics-1unit-1-221214121936-550b56aa.pptx
Case Study on mbsa education to learn ok
Ad

A Philosophy Of Software Design John Ousterhout

  • 1. A Philosophy Of Software Design John Ousterhout download https://ebookbell.com/product/a-philosophy-of-software-design- john-ousterhout-42507470 Explore and download more ebooks at ebookbell.com
  • 2. Here are some recommended products that we believe you will be interested in. You can click the link to download. A Philosophy Of Software Design Ousterhout John https://ebookbell.com/product/a-philosophy-of-software-design- ousterhout-john-49563888 A Philosophy Of Software Design 2nd Edition Ousterhout John https://ebookbell.com/product/a-philosophy-of-software-design-2nd- edition-ousterhout-john-37173268 A Philosophy Of Software Design 2nd Edition 2nd Edition John K Ousterhout https://ebookbell.com/product/a-philosophy-of-software-design-2nd- edition-2nd-edition-john-k-ousterhout-53309146 Prospective Philosophy Of Software A Simondonian Study Coline Ferrarato https://ebookbell.com/product/prospective-philosophy-of-software-a- simondonian-study-coline-ferrarato-10658472
  • 3. A Philosophy Of Gun Violence Alan J Reid https://ebookbell.com/product/a-philosophy-of-gun-violence-alan-j- reid-44898478 A Philosophy Of Faith Belief Truth And Varieties Of Commitment Finlay Malcolm https://ebookbell.com/product/a-philosophy-of-faith-belief-truth-and- varieties-of-commitment-finlay-malcolm-46348350 A Philosophy Of Struggle The Leonard Harris Reader Leonard Harris https://ebookbell.com/product/a-philosophy-of-struggle-the-leonard- harris-reader-leonard-harris-46669104 A Philosophy Of Sacred Nature Leon Niemoczynski Nam T Nguyen https://ebookbell.com/product/a-philosophy-of-sacred-nature-leon- niemoczynski-nam-t-nguyen-49438154 A Philosophy Of Comedy On Stage And Screenyou Have To Be There Shaun May https://ebookbell.com/product/a-philosophy-of-comedy-on-stage-and- screenyou-have-to-be-there-shaun-may-50219166
  • 6. A Philosophy of Software Design John Ousterhout Stanford University
  • 7. A Philosophy of Software Design by John Ousterhout Copyright © 2018 John K. Ousterhout. All rights reserved. No part of this book may be reproduced, in any form or by any means, without permission in writing from the author. Published by Yaknyam Press, Palo Alto, CA. Cover design by Pete Nguyen and Shirin Oreizy (www.hellonextstep.com). Printing History: April 2018: First Edition (v1.0) November 2018: First Edition (v1.01) ISBN 978-1-7321022-0-0 Digital book(s) (epub and mobi) produced by Booknook.biz.
  • 8. Contents Preface 1 Introduction 1.1 How to use this book 2 The Nature of Complexity 2.1 Complexity defined 2.2 Symptoms of complexity 2.3 Causes of complexity 2.4 Complexity is incremental 2.5 Conclusion 3 Working Code Isn’t Enough 3.1 Tactical programming 3.2 Strategic programming 3.3 How much to invest? 3.4 Startups and investment 3.5 Conclusion 4 Modules Should Be Deep 4.1 Modular design 4.2 What’s in an interface? 4.3 Abstractions 4.4 Deep modules 4.5 Shallow modules 4.6 Classitis 4.7 Examples: Java and Unix I/O 4.8 Conclusion
  • 9. 5 Information Hiding (and Leakage) 5.1 Information hiding 5.2 Information leakage 5.3 Temporal decomposition 5.4 Example: HTTP server 5.5 Example: too many classes 5.6 Example: HTTP parameter handling 5.7 Example: defaults in HTTP responses 5.8 Information hiding within a class 5.9 Taking it too far 5.10 Conclusion 6 General-Purpose Modules are Deeper 6.1 Make classes somewhat general-purpose 6.2 Example: storing text for an editor 6.3 A more general-purpose API 6.4 Generality leads to better information hiding 6.5 Questions to ask yourself 6.6 Conclusion 7 Different Layer, Different Abstraction 7.1 Pass-through methods 7.2 When is interface duplication OK? 7.3 Decorators 7.4 Interface versus implementation 7.5 Pass-through variables 7.6 Conclusion 8 Pull Complexity Downwards 8.1 Example: editor text class 8.2 Example: configuration parameters 8.3 Taking it too far 8.4 Conclusion
  • 10. 9 Better Together Or Better Apart? 9.1 Bring together if information is shared 9.2 Bring together if it will simplify the interface 9.3 Bring together to eliminate duplication 9.4 Separate general-purpose and special-purpose code 9.5 Example: insertion cursor and selection 9.6 Example: separate class for logging 9.7 Example: editor undo mechanism 9.8 Splitting and joining methods 9.9 Conclusion 10 Define Errors Out Of Existence 10.1 Why exceptions add complexity 10.2 Too many exceptions 10.3 Define errors out of existence 10.4 Example: file deletion in Windows 10.5 Example: Java substring method 10.6 Mask exceptions 10.7 Exception aggregation 10.8 Just crash? 10.9 Design special cases out of existence 10.10 Taking it too far 10.11 Conclusion 11 Design it Twice 12 Why Write Comments? The Four Excuses 12.1 Good code is self-documenting 12.2 I don’t have time to write comments 12.3 Comments get out of date and become misleading 12.4 All the comments I have seen are worthless 12.5 Benefits of well-written comments 13 Comments Should Describe Things that Aren’t Obvious from the Code
  • 11. 13.1 Pick conventions 13.2 Don’t repeat the code 13.3 Lower-level comments add precision 13.4 Higher-level comments enhance intuition 13.5 Interface documentation 13.6 Implementation comments: what and why, not how 13.7 Cross-module design decisions 13.8 Conclusion 13.9 Answers to questions from Section 13.5 14 Choosing Names 14.1 Example: bad names cause bugs 14.2 Create an image 14.3 Names should be precise 14.4 Use names consistently 14.5 A different opinion: Go style guide 14.6 Conclusion 15 Write The Comments First 15.1 Delayed comments are bad comments 15.2 Write the comments first 15.3 Comments are a design tool 15.4 Early comments are fun comments 15.5 Are early comments expensive? 15.6 Conclusion 16 Modifying Existing Code 16.1 Stay strategic 16.2 Maintaining comments: keep the comments near the code 16.3 Comments belong in the code, not the commit log 16.4 Maintaining comments: avoid duplication 16.5 Maintaining comments: check the diffs 16.6 Higher-level comments are easier to maintain
  • 12. 17 Consistency 17.1 Examples of consistency 17.2 Ensuring consistency 17.3 Taking it too far 17.4 Conclusion 18 Code Should be Obvious 18.1 Things that make code more obvious 18.2 Things that make code less obvious 18.3 Conclusion 19 Software Trends 19.1 Object-oriented programming and inheritance 19.2 Agile development 19.3 Unit tests 19.4 Test-driven development 19.5 Design patterns 19.6 Getters and setters 19.7 Conclusion 20 Designing for Performance 20.1 How to think about performance 20.2 Measure before modifying 20.3 Design around the critical path 20.4 An example: RAMCloud Buffers 20.5 Conclusion 21 Conclusion Index Summary of Design Principles Summary of Red Flags
  • 13. Preface People have been writing programs for electronic computers for more than 80 years, but there has been surprisingly little conversation about how to design those programs or what good programs should look like. There has been considerable discussion about software development processes such as agile development and about development tools such as debuggers, version control systems, and test coverage tools. There has also been extensive analysis of programming techniques such as object-oriented programming and functional programming, and of design patterns and algorithms. All of these discussions have been valuable, but the core problem of software design is still largely untouched. David Parnas’ classic paper “On the Criteria to be used in Decomposing Systems into Modules” appeared in 1971, but the state of the art in software design has not progressed much beyond that paper in the ensuing 45 years. The most fundamental problem in computer science is problem decomposition: how to take a complex problem and divide it up into pieces that can be solved independently. Problem decomposition is the central design task that programmers face every day, and yet, other than the work described here, I have not been able to identify a single class in any university where problem decomposition is a central topic. We teach for loops and object-oriented programming, but not software design. In addition, there is a huge variation in quality and productivity among programmers, but we have made little attempt to understand what makes the best programmers so much better or to teach those skills in our classes. I have talked with several people I consider to be great programmers, but most of them had difficulty articulating specific techniques that give them their advantage. Many people assume that software design skill is an innate talent that cannot be taught. However, there is quite a bit of scientific evidence that outstanding performance in many fields is related more to high-quality practice than innate ability (see, for example, Talent is Overrated by Geoff Colvin).
  • 14. For many years these issues have perplexed and frustrated me. I have wondered whether software design can be taught, and I have hypothesized that design skill is what separates great programmers from average ones. I finally decided that the only way to answer these questions was to attempt to teach a course on software design. The result is CS 190 at Stanford University. In this class I put forth a set of principles of software design. Students then work through a series of projects to assimilate and practice the principles. The class is taught in a fashion similar to a traditional English writing class. In an English class, students use an iterative process where they write a draft, get feedback, and then rewrite to make improvements. In CS 190, students develop a substantial piece of software from scratch. We then go through extensive code reviews to identify design problems, and students revise their projects to fix the problems. This allows students to see how their code can be improved by applying design principles. I have now taught the software design class three times, and this book is based on the design principles that emerged from the class. The principles are fairly high level and border on the philosophical (“Define errors out of existence”), so it is hard for students to understand the ideas in the abstract. Students learn best by writing code, making mistakes, and then seeing how their mistakes and the subsequent fixes relate to the principles. At this point you may well be wondering: what makes me think I know all the answers about software design? To be honest, I don’t. There were no classes on software design when I learned to program, and I never had a mentor to teach me design principles. At the time I learned to program, code reviews were virtually nonexistent. My ideas about software design come from personal experience writing and reading code. Over my career I have written about 250,000 lines of code in a variety of languages. I’ve worked on teams that created three operating systems from scratch, multiple file and storage systems, infrastructure tools such as debuggers, build systems, and GUI toolkits, a scripting language, and interactive editors for text, drawings, presentations, and integrated circuits. Along the way I’ve experienced firsthand the problems of large systems and experimented with various design techniques. In addition, I’ve read a considerable amount of code written by other people, which has exposed me to a variety of approaches, both good and bad.
  • 15. Out of all of this experience, I’ve tried to extract common threads, both about mistakes to avoid and techniques to use. This book is a reflection of my experiences: every problem described here is one that I have experienced personally, and every suggested technique is one that I have used successfully in my own coding. I don’t expect this book to be the final word on software design; I’m sure there are valuable techniques that I’ve missed, and some of my suggestions may turn out to be bad ideas in the long run. However, I hope that the book will start a conversation about software design. Compare the ideas in this book with your own experiences and decide for yourself whether the approaches described here really do reduce software complexity. This book is an opinion piece, so some readers will disagree with some of my suggestions. If you do disagree, try to understand why. I’m interested in hearing about things that work for you, things that don’t work, and any other ideas you may have about software design. I hope that the ensuing conversations will improve our collective understanding of software design. I will incorporate what I learn in future editions of this book. The best way to communicate with me about the book is to send email to the following address: [email protected] I’m interested in hearing specific feedback about the book, such as bugs or suggestions for improvement, as well as general thoughts and experiences related to software design. I’m particularly interested in compelling examples that I can use in future editions of the book. The best examples illustrate an important design principle and are simple enough to explain in a paragraph or two. If you would like to see what other people are saying on the email address and participate in discussions, you can join the Google Group software-design-book. If for some reason the software-design-book Google Group should disappear in the future, search on the Web for my home page; it will contain updated instructions for how to communicate about the book. Please don’t send book-related email to my personal email address.
  • 16. I recommend that you take the suggestions in this book with a grain of salt. The overall goal is to reduce complexity; this is more important than any particular principle or idea you read here. If you try an idea from this book and find that it doesn’t actually reduce complexity, then don’t feel obligated to keep using it (but, do let me know about your experience; I’d like to get feedback on what works and what doesn’t). Many people have offered criticisms or made suggestions that improved the quality of the book. The following people offered helpful comments on various drafts of the book: Jeff Dean, Sanjay Ghemawat, John Hartman, Brian Kernighan, James Koppel, Amy Ousterhout, Kay Ousterhout, Rob Pike, Partha Ranganathan, Keith Schwartz, and Alex Snaps. Christos Kozyrakis suggested the terms “deep” and “shallow” for classes and interfaces, replacing previous terms “thick” and “thin”, which were somewhat ambiguous. I am indebted to the students in CS 190; the process of reading their code and discussing it with them has helped to crystallize my thoughts about design.
  • 17. Chapter 1 Introduction (It’s All About Complexity) Writing computer software is one of the purest creative activities in the history of the human race. Programmers aren’t bound by practical limitations such as the laws of physics; we can create exciting virtual worlds with behaviors that could never exist in the real world. Programming doesn’t require great physical skill or coordination, like ballet or basketball. All programming requires is a creative mind and the ability to organize your thoughts. If you can visualize a system, you can probably implement it in a computer program. This means that the greatest limitation in writing software is our ability to understand the systems we are creating. As a program evolves and acquires more features, it becomes complicated, with subtle dependencies between its components. Over time, complexity accumulates, and it becomes harder and harder for programmers to keep all of the relevant factors in their minds as they modify the system. This slows down development and leads to bugs, which slow development even more and add to its cost. Complexity increases inevitably over the life of any program. The larger the program, and the more people that work on it, the more difficult it is to manage complexity. Good development tools can help us deal with complexity, and many great tools have been created over the last several decades. But there is a limit to what we can do with tools alone. If we want to make it easier to write software, so that we can build more powerful systems more cheaply, we must find ways to make software simpler. Complexity will still increase over time, in spite of our best efforts, but simpler designs allow us to build larger and more powerful systems before complexity becomes overwhelming.
  • 18. There are two general approaches to fighting complexity, both of which will be discussed in this book. The first approach is to eliminate complexity by making code simpler and more obvious. For example, complexity can be reduced by eliminating special cases or using identifiers in a consistent fashion. The second approach to complexity is to encapsulate it, so that programmers can work on a system without being exposed to all of its complexity at once. This approach is called modular design. In modular design, a software system is divided up into modules, such as classes in an object-oriented language. The modules are designed to be relatively independent of each other, so that a programmer can work on one module without having to understand the details of other modules. Because software is so malleable, software design is a continuous process that spans the entire lifecycle of a software system; this makes software design different from the design of physical systems such as buildings, ships, or bridges. However, software design has not always been viewed this way. For much of the history of programming, design was concentrated at the beginning of a project, as it is in other engineering disciplines. The extreme of this approach is called the waterfall model, in which a project is divided into discrete phases such as requirements definition, design, coding, testing, and maintenance. In the waterfall model, each phase completes before the next phase starts; in many cases different people are responsible for each phase. The entire system is designed at once, during the design phase. The design is frozen at the end of this phase, and the role of the subsequent phases is to flesh out and implement that design. Unfortunately, the waterfall model rarely works well for software. Software systems are intrinsically more complex than physical systems; it isn’t possible to visualize the design for a large software system well enough to understand all of its implications before building anything. As a result, the initial design will have many problems. The problems do not become apparent until implementation is well underway. However, the waterfall model is not structured to accommodate major design changes at this point (for example, the designers may have moved on to other projects). Thus, developers try to patch around the problems without changing the overall design. This results in an explosion of complexity.
  • 19. Because of these issues, most software development projects today use an incremental approach such as agile development, in which the initial design focuses on a small subset of the overall functionality. This subset is designed, implemented, and then evaluated. Problems with the original design are discovered and corrected, then a few more features are designed, implemented and evaluated. Each iteration exposes problems with the existing design, which are fixed before the next set of features is designed. By spreading out the design in this way, problems with the initial design can be fixed while the system is still small; later features benefit from experience gained during the implementation of earlier features, so they have fewer problems. The incremental approach works for software because software is malleable enough to allow significant design changes partway through implementation. In contrast, major design changes are much more challenging for physical systems: for example, it would not be practical to change the number of towers supporting a bridge in the middle of construction. Incremental development means that software design is never done. Design happens continuously over the life of a system: developers should always be thinking about design issues. Incremental development also means continuous redesign. The initial design for a system or component is almost never the best one; experience inevitably shows better ways to do things. As a software developer, you should always be on the lookout for opportunities to improve the design of the system you are working on, and you should plan on spending some fraction of your time on design improvements. If software developers should always be thinking about design issues, and reducing complexity is the most important element of software design, then software developers should always be thinking about complexity. This book is about how to use complexity to guide the design of software throughout its lifetime. This book has two overall goals. The first is to describe the nature of software complexity: what does “complexity” mean, why does it matter, and how can you recognize when a program has unnecessary complexity? The book’s second, and more challenging, goal is to present techniques you can use during the software development process to minimize complexity.
  • 20. Unfortunately, there isn’t a simple recipe that will guarantee great software designs. Instead, I will present a collection of higher-level concepts that border on the philosophical, such as “classes should be deep” or “define errors out of existence.” These concepts may not immediately identify the best design, but you can use them to compare design alternatives and guide your exploration of the design space. 1.1 How to use this book Many of the design principles described here are somewhat abstract, so they may be hard to appreciate without looking at actual code. It has been a challenge to find examples that are small enough to include in the book, yet large enough to illustrate problems with real systems (if you encounter good examples, please send them to me). Thus, this book may not be sufficient by itself for you to learn how to apply the principles. The best way to use this book is in conjunction with code reviews. When you read other people’s code, think about whether it conforms to the concepts discussed here and how that relates to the complexity of the code. It’s easier to see design problems in someone else’s code than your own. You can use the red flags described here to identify problems and suggest improvements. Reviewing code will also expose you to new design approaches and programming techniques. One of the best ways to improve your design skills is to learn to recognize red flags: signs that a piece of code is probably more complicated than it needs to be. Over the course of this book I will point out red flags that suggest problems related to each major design issue; the most important ones are summarized at the back of the book. You can then use these when you are coding: when you see a red flag, stop and look for an alternate design that eliminates the problem. When you first try this approach, you may have to try several design alternatives before you find one that eliminates the red flag. Don’t give up easily: the more alternatives you try before fixing the problem, the more you will learn. Over time, you will find that your code has fewer and fewer red flags, and your designs are cleaner and cleaner. Your experience will also show you other red flags that you can use to identify design problems (I’d be happy to hear about these).
  • 21. When applying the ideas from this book, it’s important to use moderation and discretion. Every rule has its exceptions, and every principle has its limits. If you take any design idea to its extreme, you will probably end up in a bad place. Beautiful designs reflect a balance between competing ideas and approaches. Several chapters have sections titled “Taking it too far,” which describe how to recognize when you are overdoing a good thing. Almost all of the examples in this book are in Java or C++, and much of the discussion is in terms of designing classes in an object-oriented language. However, the ideas apply in other domains as well. Almost all of the ideas related to methods can also be applied to functions in a language without object-oriented features, such as C. The design ideas also apply to modules other than classes, such as subsystems or network services. With this background, let’s discuss in more detail what causes complexity, and how to make software systems simpler.
  • 22. Chapter 2 The Nature of Complexity This book is about how to design software systems to minimize their complexity. The first step is to understand the enemy. Exactly what is “complexity”? How can you tell if a system is unnecessarily complex? What causes systems to become complex? This chapter will address those questions at a high level; subsequent chapters will show you how to recognize complexity at a lower level, in terms of specific structural features. The ability to recognize complexity is a crucial design skill. It allows you to identify problems before you invest a lot of effort in them, and it allows you to make good choices among alternatives. It is easier to tell whether a design is simple than it is to create a simple design, but once you can recognize that a system is too complicated, you can use that ability to guide your design philosophy towards simplicity. If a design appears complicated, try a different approach and see if that is simpler. Over time, you will notice that certain techniques tend to result in simpler designs, while others correlate with complexity. This will allow you to produce simpler designs more quickly. This chapter also lays out some basic assumptions that provide a foundation for the rest of the book. Later chapters take the material of this chapter as given and use it to justify a variety of refinements and conclusions. 2.1 Complexity defined For the purposes of this book, I define “complexity” in a practical way. Complexity is anything related to the structure of a software system that makes it hard to understand and modify the system. Complexity can take many forms. For example, it might be hard to understand how a piece of code works; it might take a lot of effort to implement a small improvement, or it
  • 23. might not be clear which parts of the system must be modified to make the improvement; it might be difficult to fix one bug without introducing another. If a software system is hard to understand and modify, then it is complicated; if it is easy to understand and modify, then it is simple. You can also think of complexity in terms of cost and benefit. In a complex system, it takes a lot of work to implement even small improvements. In a simple system, larger improvements can be implemented with less effort. Complexity is what a developer experiences at a particular point in time when trying to achieve a particular goal. It doesn’t necessarily relate to the overall size or functionality of the system. People often use the word “complex” to describe large systems with sophisticated features, but if such a system is easy to work on, then, for the purposes of this book, it is not complex. Of course, almost all large and sophisticated software systems are in fact hard to work on, so they also meet my definition of complexity, but this need not necessarily be the case. It is also possible for a small and unsophisticated system to be quite complex. Complexity is determined by the activities that are most common. If a system has a few parts that are very complicated, but those parts almost never need to be touched, then they don’t have much impact on the overall complexity of the system. To characterize this in a crude mathematical way: The overall complexity of a system (C) is determined by the complexity of each part p (cp) weighted by the fraction of time developers spend working on that part (tp). Isolating complexity in a place where it will never be seen is almost as good as eliminating the complexity entirely. Complexity is more apparent to readers than writers. If you write a piece of code and it seems simple to you, but other people think it is complex, then it is complex. When you find yourself in situations like this, it’s worth probing the other developers to find out why the code seems complex to them; there are probably some interesting lessons to learn from the disconnect between your opinion and theirs. Your job as a developer is not
  • 24. just to create code that you can work with easily, but to create code that others can also work with easily. 2.2 Symptoms of complexity Complexity manifests itself in three general ways, which are described in the paragraphs below. Each of these manifestations makes it harder to carry out development tasks. Change amplification: The first symptom of complexity is that a seemingly simple change requires code modifications in many different places. For example, consider a Web site containing several pages, each of which displays a banner with a background color. In many early Web sites, the color was specified explicitly on each page, as shown in Figure 2.1(a). In order to change the background for such a Web site, a developer might have to modify every existing page by hand; this would be nearly impossible for a large site with thousands of pages. Fortunately, modern Web sites use an approach like that in Figure 2.1(b), where the banner color is specified once in a central place, and all of the individual pages reference that shared value. With this approach, the banner color of the entire Web site can be changed with a single modification. One of the goals of good design is to reduce the amount of code that is affected by each design decision, so design changes don’t require very many code modifications. Cognitive load: The second symptom of complexity is cognitive load, which refers to how much a developer needs to know in order to complete a task. A higher cognitive load means that developers have to spend more time learning the required information, and there is a greater risk of bugs because they have missed something important. For example, suppose a function in C allocates memory, returns a pointer to that memory, and assumes that the caller will free the memory. This adds to the cognitive load of developers using the function; if a developer fails to free the memory, there will be a memory leak. If the system can be restructured so that the caller doesn’t need to worry about freeing the memory (the same module that allocates the memory also takes responsibility for freeing it), it will reduce the cognitive load. Cognitive load arises in many ways, such as APIs with many methods, global variables, inconsistencies, and dependencies between modules.
  • 25. System designers sometimes assume that complexity can be measured by lines of code. They assume that if one implementation is shorter than another, then it must be simpler; if it only takes a few lines of code to make a change, then the change must be easy. However, this view ignores the costs associated with cognitive load. I have seen frameworks that allowed applications to be written with only a few lines of code, but it was extremely difficult to figure out what those lines were. Sometimes an approach that requires more lines of code is actually simpler, because it reduces cognitive load. Figure 2.1: Each page in a Web site displays a colored banner. In (a) the background color for the banner is specified explicitly in each page. In (b) a shared variable holds the background color and each page references that variable. In (c) some pages display an additional color for emphasis, which is a darker shade of the banner background color; if the background color changes, the emphasis color must also change. Unknown unknowns: The third symptom of complexity is that it is not obvious which pieces of code must be modified to complete a task, or what information a developer must have to carry out the task successfully. Figure 2.1(c) illustrates this problem. The Web site uses a central variable to determine the banner background color, so it appears to be easy to change. However, a few Web pages use a darker shade of the background color for emphasis, and that darker color is specified explicitly in the individual pages. If the background color changes, then the the emphasis color must change to match. Unfortunately, developers are unlikely to realize this, so they may change the central bannerBg variable without updating the emphasis color.
  • 26. Even if a developer is aware of the problem, it won’t be obvious which pages use the emphasis color, so the developer may have to search every page in the Web site. Of the three manifestations of complexity, unknown unknowns are the worst. An unknown unknown means that there is something you need to know, but there is no way for you to find out what it is, or even whether there is an issue. You won’t find out about it until bugs appear after you make a change. Change amplification is annoying, but as long as it is clear which code needs to be modified, the system will work once the change has been completed. Similarly, a high cognitive load will increase the cost of a change, but if it is clear which information to read, the change is still likely to be correct. With unknown unknowns, it is unclear what to do or whether a proposed solution will even work. The only way to be certain is to read every line of code in the system, which is impossible for systems of any size. Even this may not be sufficient, because a change may depend on a subtle design decision that was never documented. One of the most important goals of good design is for a system to be obvious. This is the opposite of high cognitive load and unknown unknowns. In an obvious system, a developer can quickly understand how the existing code works and what is required to make a change. An obvious system is one where a developer can make a quick guess about what to do, without thinking very hard, and yet be confident that the guess is correct. Chapter 18 discusses techniques for making code more obvious. 2.3 Causes of complexity Now that you know the high-level symptoms of complexity and why complexity makes software development difficult, the next step is to understand what causes complexity, so that we can design systems to avoid the problems. Complexity is caused by two things: dependencies and obscurity. This section discusses these factors at a high level; subsequent chapters will discuss how they relate to lower-level design decisions. For the purposes of this book, a dependency exists when a given piece of code cannot be understood and modified in isolation; the code relates in some way to other code, and the other code must be considered and/or modified if
  • 27. the given code is changed. In the Web site example of Figure 2.1(a), the background color creates dependencies between all of the pages. All of the pages need to have the same background, so if the background is changed for one page, then it must be changed for all of them. Another example of dependencies occurs in network protocols. Typically there is separate code for the sender and receiver for the protocol, but they must each conform to the protocol; changing the code for the sender almost always requires corresponding changes at the receiver, and vice versa. The signature of a method creates a dependency between the implementation of that method and the code that invokes it: if a new parameter is added to a method, all of the invocations of that method must be modified to specify that parameter. Dependencies are a fundamental part of software and can’t be completely eliminated. In fact, we intentionally introduce dependencies as part of the software design process. Every time you write a new class you create dependencies around the API for that class. However, one of the goals of software design is to reduce the number of dependencies and to make the dependencies that remain as simple and obvious as possible. Consider the Web site example. In the old Web site with the background specified separately on each page, all of the Web pages were dependent on each other. The new Web site fixed this problem by specifying the background color in a central place and providing an API that individual pages use to retrieve that color when they are rendered. The new Web site eliminated the dependency between the pages, but it created a new dependency around the API for retrieving the background color. Fortunately, the new dependency is more obvious: it is clear that each individual Web page depends on the bannerBg color, and a developer can easily find all the places where the variable is used by searching for its name. Furthermore, compilers help to manage API dependencies: if the name of the shared variable changes, compilation errors will occur in any code that still uses the old name. The new Web site replaced a nonobvious and difficult-to-manage dependency with a simpler and more obvious one. The second cause of complexity is obscurity. Obscurity occurs when important information is not obvious. A simple example is a variable name that is so generic that it doesn’t carry much useful information (e.g., time). Or, the documentation for a variable might not specify its units, so the only
  • 28. way to find out is to scan code for places where the variable is used. Obscurity is often associated with dependencies, where it is not obvious that a dependency exists. For example, if a new error status is added to a system, it may be necessary to add an entry to a table holding string messages for each status, but the existence of the message table might not be obvious to a programmer looking at the status declaration. Inconsistency is also a major contributor to obscurity: if the same variable name is used for two different purposes, it won’t be obvious to developer which of these purposes a particular variable serves. In many cases, obscurity comes about because of inadequate documentation; Chapter 13 deals with this topic. However, obscurity is also a design issue. If a system has a clean and obvious design, then it will need less documentation. The need for extensive documentation is often a red flag that the design isn’t quite right. The best way to reduce obscurity is by simplifying the system design. Together, dependencies and obscurity account for the three manifestations of complexity described in Section 2.2. Dependencies lead to change amplification and a high cognitive load. Obscurity creates unknown unknowns, and also contributes to cognitive load. If we can find design techniques that minimize dependencies and obscurity, then we can reduce the complexity of software. 2.4 Complexity is incremental Complexity isn’t caused by a single catastrophic error; it accumulates in lots of small chunks. A single dependency or obscurity, by itself, is unlikely to affect significantly the maintainability of a software system. Complexity comes about because hundreds or thousands of small dependencies and obscurities build up over time. Eventually, there are so many of these small issues that every possible change to the system is affected by several of them. The incremental nature of complexity makes it hard to control. It’s easy to convince yourself that a little bit of complexity introduced by your current change is no big deal. However, if every developer takes this approach for every change, complexity accumulates rapidly. Once complexity has accumulated, it is hard to eliminate, since fixing a single dependency or
  • 29. obscurity will not, by itself, make a big difference. In order to slow the growth of complexity, you must adopt a “zero tolerance” philosophy, as discussed in Chapter 3. 2.5 Conclusion Complexity comes from an accumulation of dependencies and obscurities. As complexity increases, it leads to change amplification, a high cognitive load, and unknown unknowns. As a result, it takes more code modifications to implement each new feature. In addition, developers spend more time acquiring enough information to make the change safely and, in the worst case, they can’t even find all the information they need. The bottom line is that complexity makes it difficult and risky to modify an existing code base.
  • 30. Chapter 3 Working Code Isn’t Enough (Strategic vs. Tactical Programming) One of the most important elements of good software design is the mindset you adopt when you approach a programming task. Many organizations encourage a tactical mindset, focused on getting features working as quickly as possible. However, if you want a good design, you must take a more strategic approach where you invest time to produce clean designs and fix problems. This chapter discusses why the strategic approach produces better designs and is actually cheaper than the tactical approach over the long run. 3.1 Tactical programming Most programmers approach software development with a mindset I call tactical programming. In the tactical approach, your main focus is to get something working, such as a new feature or a bug fix. At first glance this seems totally reasonable: what could be more important than writing code that works? However, tactical programming makes it nearly impossible to produce a good system design. The problem with tactical programming is that it is short-sighted. If you’re programming tactically, you’re trying to finish a task as quickly as possible. Perhaps you have a hard deadline. As a result, planning for the future isn’t a priority. You don’t spend much time looking for the best design; you just want to get something working soon. You tell yourself that it’s OK to add a bit of complexity or introduce a small kludge or two, if that allows the current task to be completed more quickly.
  • 31. This is how systems become complicated. As discussed in the previous chapter, complexity is incremental. It’s not one particular thing that makes a system complicated, but the accumulation of dozens or hundreds of small things. If you program tactically, each programming task will contribute a few of these complexities. Each of them probably seems like a reasonable compromise in order to finish the current task quickly. However, the complexities accumulate rapidly, especially if everyone is programming tactically. Before long, some of the complexities will start causing problems, and you will begin to wish you hadn’t taken those early shortcuts. But, you will tell yourself that it’s more important to get the next feature working than to go back and refactor existing code. Refactoring may help out in the long run, but it will definitely slow down the current task. So, you look for quick patches to work around any problems you encounter. This just creates more complexity, which then requires more patches. Pretty soon the code is a mess, but by this point things are so bad that it would take months of work to clean it up. There’s no way your schedule can tolerate that kind of delay, and fixing one or two of the problems doesn’t seem like it will make much difference, so you just keep programming tactically. If you have worked on a large software project for very long, I suspect you have seen tactical programming at work and have experienced the problems that result. Once you start down the tactical path, it’s difficult to change. Almost every software development organization has at least one developer who takes tactical programming to the extreme: a tactical tornado. The tactical tornado is a prolific programmer who pumps out code far faster than others but works in a totally tactical fashion. When it comes to implementing a quick feature, nobody gets it done faster than the tactical tornado. In some organizations, management treats tactical tornadoes as heroes. However, tactical tornadoes leave behind a wake of destruction. They are rarely considered heroes by the engineers who must work with their code in the future. Typically, other engineers must clean up the messes left behind by the tactical tornado, which makes it appear that those engineers (who are the real heroes) are making slower progress than the tactical tornado.
  • 32. 3.2 Strategic programming The first step towards becoming a good software designer is to realize that working code isn’t enough. It’s not acceptable to introduce unnecessary complexities in order to finish your current task faster. The most important thing is the long-term structure of the system. Most of the code in any system is written by extending the existing code base, so your most important job as a developer is to facilitate those future extensions. Thus, you should not think of “working code” as your primary goal, though of course your code must work. Your primary goal must be to produce a great design, which also happens to work. This is strategic programming. Strategic programming requires an investment mindset. Rather than taking the fastest path to finish your current project, you must invest time to improve the design of the system. These investments will slow you down a bit in the short term, but they will speed you up in the long term, as illustrated in Figure 3.1. Some of the investments will be proactive. For example, it’s worth taking a little extra time to find a simple design for each new class; rather than implementing the first idea that comes to mind, try a couple of alternative designs and pick the cleanest one. Try to imagine a few ways in which the system might need to be changed in the future and make sure that will be easy with your design. Writing good documentation is another example of a proactive investment. Other investments will be reactive. No matter how much you invest up front, there will inevitably be mistakes in your design decisions. Over time, these mistakes will become obvious. When you discover a design problem, don’t just ignore it or patch around it; take a little extra time to fix it. If you program strategically, you will continually make small improvements to the system design. This is the opposite of tactical programming, where you are continually adding small bits of complexity that cause problems in the future. 3.3 How much to invest? So, what is the right amount of investment? A huge up-front investment, such as trying to design the entire system, won’t be effective. This is the waterfall method, and we know it doesn’t work. The ideal design tends to emerge in
  • 33. bits and pieces, as you get experience with the system. Thus, the best approach is to make lots of small investments on a continual basis. I suggest spending about 10–20% of your total development time on investments. This amount is small enough that it won’t impact your schedules significantly, but large enough to produce significant benefits over time. Your initial projects will thus take 10–20% longer than they would in a purely tactical approach. That extra time will result in a better software design, and you will start experiencing the benefits within a few months. It won’t be long before you’re developing at least 10–20% faster than you would if you had programmed tactically. At this point your investments become free: the benefits from your past investments will save enough time to cover the cost of future investments. You will quickly recover the cost of the initial investment. Figure 3.1 illustrates this phenomenon. Figure 3.1: At the beginning, a tactical approach to programming will make progress more quickly than a strategic approach. However, complexity accumulates more rapidly under the tactical approach, which reduces productivity. Over time, the strategic approach results in greater progress. Note: this figure is intended only as a qualitative illustration; I am not aware of any empirical measurements of the precise shapes of the curves. Conversely, if you program tactically, you will finish your first projects 10–20% faster, but over time your development speed will slow as complexity accumulates. It won’t be long before you’re programming at least 10–20% slower. You will quickly give back all of the time you saved at the beginning, and for the rest of system’s lifetime you will be developing more slowly than if you had taken the strategic approach. If you haven’t ever worked in a badly degraded code base, talk to someone who has; they will tell you that poor code quality slows development by at least 20%. 3.4 Startups and investment
  • 34. In some environments there are strong forces working against the strategic approach. For example, early-stage startups feel tremendous pressure to get their early releases out quickly. In these companies, it might seem that even a 10–20% investment isn’t affordable. As a result, many startups take a tactical approach, spending little effort on design and even less on cleanup when problems pop up. They rationalize this with the thought that, if they are successful, they’ll have enough money to hire extra engineers to clean things up. If you are in a company leaning in this direction, you should realize that once a code base turns to spaghetti, it is nearly impossible to fix. You will probably pay high development costs for the life of the product. Furthermore, the payoff for good (or bad) design comes pretty quickly, so there’s a good chance that the tactical approach won’t even speed up your first product release. Another thing to consider is that one of the most important factors for success of a company is the quality of its engineers. The best way to lower development costs is to hire great engineers: they don’t cost much more than mediocre engineers but have tremendously higher productivity. However, the best engineers care deeply about good design. If your code base is a wreck, word will get out, and this will make it harder for you to recruit. As a result, you are likely to end up with mediocre engineers. This will increase your future costs and probably cause the system structure to degrade even more. Facebook is an example of a startup that encouraged tactical programming. For many years the company’s motto was “Move fast and break things.” New engineers fresh out of college were encouraged to dive immediately into the company’s code base; it was normal for engineers to push commits into production in their first week on the job. On the positive side, Facebook developed a reputation as a company that empowered its employees. Engineers had tremendous latitude, and there were few rules and restrictions to get in their way. Facebook has been spectacularly successful as a company, but its code base suffered because of the company’s tactical approach; much of the code was unstable and hard to understand, with few comments or tests, and painful to work with. Over time the company realized that its culture was unsustainable. Eventually, Facebook changed its motto to “Move fast with
  • 35. solid infrastructure” to encourage its engineers to invest more in good design. It remains to be seen whether Facebook can successfully clean up the problems that accumulated over years of tactical programming. In fairness to Facebook, I should point out that Facebook’s code probably isn’t much worse than average among startups. Tactical programming is commonplace among startups; Facebook just happens to be a particularly visible example. Fortunately, it is also possible to succeed in Silicon Valley with a strategic approach. Google and VMware grew up around the same time as Facebook, but both of these companies embraced a more strategic approach. Both companies placed a heavy emphasis on high quality code and good design, and both companies built sophisticated products that solved complex problems with reliable software systems. The companies’ strong technical cultures became well known in Silicon Valley. Few other companies could compete with them for hiring the top technical talent. These examples show that a company can succeed with either approach. However, it’s a lot more fun to work in a company that cares about software design and has a clean code base. 3.5 Conclusion Good design doesn’t come for free. It has to be something you invest in continually, so that small problems don’t accumulate into big ones. Fortunately, good design eventually pays for itself, and sooner than you might think. It’s crucial to be consistent in applying the strategic approach and to think of investment as something to do today, not tomorrow. When you get in a crunch it will be tempting to put off cleanups until after the crunch is over. However, this is a slippery slope; after the current crunch there will almost certainly be another one, and another after that. Once you start delaying design improvements, it’s easy for the delays to become permanent and for your culture to slip into the tactical approach. The longer you wait to address design problems, the bigger they become; the solutions become more intimidating, which makes it easy to put them off even more. The most
  • 36. effective approach is one where every engineer makes continuous small investments in good design.
  • 37. Chapter 4 Modules Should Be Deep One of the most important techniques for managing software complexity is to design systems so that developers only need to face a small fraction of the overall complexity at any given time. This approach is called modular design, and this chapter presents its basic principles. 4.1 Modular design In modular design, a software system is decomposed into a collection of modules that are relatively independent. Modules can take many forms, such as classes, subsystems, or services. In an ideal world, each module would be completely independent of the others: a developer could work in any of the modules without knowing anything about any of the other modules. In this world, the complexity of a system would be the complexity of its worst module. Unfortunately, this ideal is not achievable. Modules must work together by calling each others’s functions or methods. As a result, modules must know something about each other. There will be dependencies between the modules: if one module changes, other modules may need to change to match. For example, the arguments for a method create a dependency between the method and any code that invokes the method. If the required arguments change, all invocations of the method must be modified to conform to the new signature. Dependencies can take many other forms, and they can be quite subtle. The goal of modular design is to minimize the dependencies between modules. In order to manage dependencies, we think of each module in two parts: an interface and an implementation. The interface consists of everything that a developer working in a different module must know in order to use the
  • 38. given module. Typically, the interface describes what the module does but not how it does it. The implementation consists of the code that carries out the promises made by the interface. A developer working in a particular module must understand the interface and implementation of that module, plus the interfaces of any other modules invoked by the given module. A developer should not need to understand the implementations of modules other than the one he or she is working in. Consider a module that implements balanced trees. The module probably contains sophisticated code for ensuring that the tree remains balanced. However, this complexity is not visible to users of the module. Users see a relatively simple interface for invoking operations to insert, remove, and fetch nodes in the tree. To invoke an insert operation, the caller need only provide the key and value for the new node; the mechanisms for traversing the tree and splitting nodes are not visible in the interface. For the purposes of this book, a module is any unit of code that has an interface and an implementation. Each class in an object-oriented programming language is a module. Methods within a class, or functions in a language that isn’t object-oriented, can also be thought of as modules: each of these has an interface and an implementation, and modular design techniques can be applied to them. Higher-level subsystems and services are also modules; their interfaces may take different forms, such as kernel calls or HTTP requests. Much of the discussion about modular design in this book focuses on designing classes, but the techniques and concepts apply to other kinds of modules as well. The best modules are those whose interfaces are much simpler than their implementations. Such modules have two advantages. First, a simple interface minimizes the complexity that a module imposes on the rest of the system. Second, if a module is modified in a way that does not change its interface, then no other module will be affected by the modification. If a module’s interface is much simpler than its implementation, there will be many aspects of the module that can be changed without affecting other modules. 4.2 What’s in an interface?
  • 39. The interface to a module contains two kinds of information: formal and informal. The formal parts of an interface are specified explicitly in the code, and some of these can be checked for correctness by the programming language. For example, the formal interface for a method is its signature, which includes the names and types of its parameters, the type of its return value, and information about exceptions thrown by the method. Most programming languages ensure that each invocation of a method provides the right number and types of arguments to match its signature. The formal interface for a class consists of the signatures for all of its public methods, plus the names and types of any public variables. Each interface also includes informal elements. These are not specified in a way that can be understood or enforced by the programming language. The informal parts of an interface include its high-level behavior, such as the fact that a function deletes the file named by one of its arguments. If there are constraints on the usage of a class (perhaps one method must be called before another), these are also part of the class’s interface. In general, if a developer needs to know a particular piece of information in order to use a module, then that information is part of the module’s interface. The informal aspects of an interface can only be described using comments, and the programming language cannot ensure that the description is complete or accurate1. For most interfaces the informal aspects are larger and more complex than the formal aspects. One of the benefits of a clearly specified interface is that it indicates exactly what developers need to know in order to use the associated module. This helps to eliminate the “unknown unknowns” problem described in Section 2.2. 4.3 Abstractions The term abstraction is closely related to the idea of modular design. An abstraction is a simplified view of an entity, which omits unimportant details. Abstractions are useful because they make it easier for us to think about and manipulate complex things. In modular programming, each module provides an abstraction in form of its interface. The interface presents a simplified view of the module’s
  • 40. functionality; the details of the implementation are unimportant from the standpoint of the module’s abstraction, so they are omitted from the interface. In the definition of abstraction, the word “unimportant” is crucial. The more unimportant details that are omitted from an abstraction, the better. However, a detail can only be omitted from an abstraction if it is unimportant. An abstraction can go wrong in two ways. First, it can include details that are not really important; when this happens, it makes the abstraction more complicated than necessary, which increases the cognitive load on developers using the abstraction. The second error is when an abstraction omits details that really are important. This results in obscurity: developers looking only at the abstraction will not have all the information they need to use the abstraction correctly. An abstraction that omits important details is a false abstraction: it might appear simple, but in reality it isn’t. The key to designing abstractions is to understand what is important, and to look for designs that minimize the amount of information that is important. As an example, consider a file system. The abstraction provided by a file system omits many details, such as the mechanism for choosing which blocks on a storage device to use for the data in a given file. These details are unimportant to users of the file system (as long as the system provides adequate performance). However, some of the details of a file system’s implementation are important to users. Most file systems cache data in main memory, and they may delay writing new data to the storage device in order to improve performance. Some applications, such as databases, need to know exactly when data is written through to storage, so they can ensure that data will be preserved after system crashes. Thus, the rules for flushing data to secondary storage must be visible in the file system’s interface. We depend on abstractions to manage complexity not just in programming, but pervasively in our everyday lives. A microwave oven contains complex electronics to convert alternating current into microwave radiation and distribute that radiation throughout the cooking cavity. Fortunately, users see a much simpler abstraction, consisting of a few buttons to control the timing and intensity of the microwaves. Cars provide a simple abstraction that allows us to drive them without understanding the mechanisms for electrical motors, battery power management, anti-lock brakes, cruise control, and so on.
  • 41. 4.4 Deep modules The best modules are those that provide powerful functionality yet have simple interfaces. I use the term deep to describe such modules. To visualize the notion of depth, imagine that each module is represented by a rectangle, as shown in Figure 4.1. The area of each rectangle is proportional to the functionality implemented by the module. The top edge of a rectangle represents the module’s interface; the length of that edge indicates the complexity of the interface. The best modules are deep: they have a lot of functionality hidden behind a simple interface. A deep module is a good abstraction because only a small fraction of its internal complexity is visible to its users. Figure 4.1: Deep and shallow modules. The best modules are deep: they allow a lot of functionality to be accessed through a simple interface. A shallow module is one with a relatively complex interface, but not much functionality: it doesn’t hide much complexity. Module depth is a way of thinking about cost versus benefit. The benefit provided by a module is its functionality. The cost of a module (in terms of system complexity) is its interface. A module’s interface represents the complexity that the module imposes on the rest of the system: the smaller and simpler the interface, the less complexity that it introduces. The best modules are those with the greatest benefit and the least cost. Interfaces are good, but more, or larger, interfaces are not necessarily better! The mechanism for file I/O provided by the Unix operating system and its descendants, such as Linux, is a beautiful example of a deep interface. There are only five basic system calls for I/O, with simple signatures: int open(const char* path, int flags, mode_t permissions); ssize_t read(int fd, void* buffer, size_t count);
  • 42. ssize_t write(int fd, const void* buffer, size_t count); off_t lseek(int fd, off_t offset, int referencePosition); int close(int fd); The open system call takes a hierarchical file name such as /a/b/c and returns an integer file descriptor, which is used to reference the open file. The other arguments for open provide optional information such as whether the file is being opened for reading or writing, whether a new file should be created if there is no existing file, and access permissions for the file, if a new file is created. The read and write system calls transfer information between buffer areas in the application’s memory and the file; close ends the access to the file. Most files are accessed sequentially, so that is the default; however, random access can be achieved by invoking the lseek system call to change the current access position. A modern implementation of the Unix I/O interface requires hundreds of thousands of lines of code, which address complex issues such as: How are files represented on disk in order to allow efficient access? How are directories stored, and how are hierarchical path names processed to find the files they refer to? How are permissions enforced, so that one user cannot modify or delete another user’s files? How are file accesses implemented? For example, how is functionality divided between interrupt handlers and background code, and how do these two elements communicate safely? What scheduling policies are used when there are concurrent accesses to multiple files? How can recently accessed file data be cached in memory in order to reduce the number of disk accesses? How can a variety of different secondary storage devices, such as disks and flash drives, be incorporated into a single file system? All of these issues, and many more, are handled by the Unix file system implementation; they are invisible to programmers who invoke the system calls. Implementations of the Unix I/O interface have evolved radically over the years, but the five basic kernel calls have not changed.
  • 43. Another example of a deep module is the garbage collector in a language such as Go or Java. This module has no interface at all; it works invisibly behind the scenes to reclaim unused memory. Adding garbage collection to a system actually shrinks its overall interface, since it eliminates the interface for freeing objects. The implementation of a garbage collector is quite complex, but that complexity is hidden from programmers using the language. Deep modules such as Unix I/O and garbage collectors provide powerful abstractions because they are easy to use, yet they hide significant implementation complexity. 4.5 Shallow modules On the other hand, a shallow module is one whose interface is relatively complex in comparison to the functionality that it provides. For example, a class that implements linked lists is shallow. It doesn’t take much code to manipulate a linked list (inserting or deleting an element takes only a few lines), so the linked list abstraction doesn’t hide very many details. The complexity of a linked list interface is nearly as great as the complexity of its implementation. Shallow classes are sometimes unavoidable, but they don’t provide help much in managing complexity. Here is an extreme example of a shallow method, taken from a project in a software design class: private void addNullValueForAttribute(String attribute) { data.put(attribute, null); } From the standpoint of managing complexity, this method makes things worse, not better. The method offers no abstraction, since all of its functionality is visible through its interface. For example, callers probably need to know that the attribute will be stored in the data variable. It is no simpler to think about the interface than to think about the full implementation. If the method is documented properly, the documentation will be longer than the method’s code. It even takes more keystrokes to invoke the method than it would take for a caller to manipulate the data
  • 44. variable directly. The method adds complexity (in the form of a new interface for developers to learn) but provides no compensating benefit. Red Flag: Shallow Module A shallow module is one whose interface is complicated relative to the functionality it provides. Shallow modules don’t help much in the battle against complexity, because the benefit they provide (not having to learn about how they work internally) is negated by the cost of learning and using their interfaces. Small modules tend to be shallow. 4.6 Classitis Unfortunately, the value of deep classes is not widely appreciated today. The conventional wisdom in programming is that classes should be small, not deep. Students are often taught that the most important thing in class design is to break up larger classes into smaller ones. The same advice is often given about methods: “Any method longer than N lines should be divided into multiple methods” (N can be as low as 10). This approach results in large numbers of shallow classes and methods, which add to overall system complexity. The extreme of the “classes should be small” approach is a syndrome I call classitis, which stems from the mistaken view that “classes are good, so more classes are better.” In systems suffering from classitis, developers are encouraged to minimize the amount of functionality in each new class: if you want more functionality, introduce more classes. Classitis may result in classes that are individually simple, but it increases the complexity of the overall system. Small classes don’t contribute much functionality, so there have to be a lot of them, each with its own interface. These interfaces accumulate to create tremendous complexity at the system level. Small classes also result in a verbose programming style, due to the boilerplate required for each class. 4.7 Examples: Java and Unix I/O
  • 45. One of the most visible examples of classitis today is the Java class library. The Java language doesn’t require lots of small classes, but a culture of classitis seems to have taken root in the Java programming community. For example, to open a file in order to read serialized objects from it, you must create three different objects: FileInputStream fileStream = new FileInputStream(fileName); BufferedInputStream bufferedStream = new BufferedInputStream(fileStream); ObjectInputStream objectStream = new ObjectInputStream(bufferedStream); A FileInputStream object provides only rudimentary I/O: it is not capable of performing buffered I/O, nor can it read or write serialized objects. The BufferedInputStream object adds buffering to a FileInputStream, and the ObjectInputStream adds the ability to read and write serialized objects. The first two objects in the code above, fileStream and bufferedStream, are never used once the file has been opened; all future operations use objectStream. It is particularly annoying (and error-prone) that buffering must be requested explicitly by creating a separate BufferedInputStream object; if a developer forgets to create this object, there will be no buffering and I/O will be slow. Perhaps the Java developers would argue that not everyone wants to use buffering for file I/O, so it shouldn’t be built into the base mechanism. They might argue that it’s better to keep buffering separate, so people can choose whether or not to use it. Providing choice is good, but interfaces should be designed to make the common case as simple as possible (see the formula on page 6). Almost every user of file I/O will want buffering, so it should be provided by default. For those few situations where buffering is not desirable, the library can provide a mechanism to disable it. Any mechanism for disabling buffering should be cleanly separated in the interface (for example, by providing a different constructor for FileInputStream, or through a method that disables or replaces the buffering mechanism), so that most developers do not even need to be aware of its existence.
  • 46. In contrast, the designers of the Unix system calls made the common case simple. For example, they recognized that sequential I/O is most common, so they made that the default behavior. Random access is still relatively easy to do, using the lseek system call, but a developer doing only sequential access need not be aware of that mechanism. If an interface has many features, but most developers only need to be aware of a few of them, the effective complexity of that interface is just the complexity of the commonly used features. 4.8 Conclusion By separating the interface of a module from its implementation, we can hide the complexity of the implementation from the rest of the system. Users of a module need only understand the abstraction provided by its interface. The most important issue in designing classes and other modules is to make them deep, so that they have simple interfaces for the common use cases, yet still provide significant functionality. This maximizes the amount of complexity that is concealed. 1There exist languages, mostly in the research community, where the overall behavior of a method or function can be described formally using a specification language. The specification can be checked automatically to ensure that it matches the implementation. An interesting question is whether such a formal specification could replace the informal parts of an interface. My current opinion is that an interface described in English is likely to be more intuitive and understandable for developers than one written in a formal specification language.
  • 47. Chapter 5 Information Hiding (and Leakage) Chapter 4 argued that modules should be deep. This chapter, and the next few that follow, discuss techniques for creating deep modules. 5.1 Information hiding The most important technique for achieving deep modules is information hiding. This technique was first described by David Parnas1. The basic idea is that each module should encapsulate a few pieces of knowledge, which represent design decisions. The knowledge is embedded in the module’s implementation but does not appear in its interface, so it is not visible to other modules. The information hidden within a module usually consists of details about how to implement some mechanism. Here are some examples of information that might be hidden within a module: How to store information in a B-tree, and how to access it efficiently. How to identify the physical disk block corresponding to each logical block within a file. How to implement the TCP network protocol. How to schedule threads on a multi-core processor. How to parse JSON documents. The hidden information includes data structures and algorithms related to the mechanism. It can also include lower-level details such as the size of a page, and it can include higher-level concepts that are more abstract, such as an assumption that most files are small. Information hiding reduces complexity in two ways. First, it simplifies the interface to a module. The interface reflects a simpler, more abstract view of the module’s functionality and hides the details; this reduces the cognitive
  • 48. load on developers who use the module. For instance, a developer using a B- tree class need not worry about the ideal fanout for nodes in the tree or how to keep the tree balanced. Second, information hiding makes it easier to evolve the system. If a piece of information is hidden, there are no dependencies on that information outside the module containing the information, so a design change related to that information will affect only the one module. For example, if the TCP protocol changes (to introduce a new mechanism for congestion control, for instance), the protocol’s implementation will have to be modified, but no changes should be needed in higher-level code that uses TCP to send and receive data. When designing a new module, you should think carefully about what information can be hidden in that module. If you can hide more information, you should also be able to simplify the module’s interface, and this makes the module deeper. Note: hiding variables and methods in a class by declaring them private isn’t the same thing as information hiding. Private elements can help with information hiding, since they make it impossible for the items to be accessed directly from outside the class. However, information about the private items can still be exposed through public methods such as getter and setter methods. When this happens the nature and usage of the variables are just as exposed as if the variables were public. The best form of information hiding is when information is totally hidden within a module, so that it is irrelevant and invisible to users of the module. However, partial information hiding also has value. For example, if a particular feature or piece of information is only needed by a few of a class’s users, and it is accessed through separate methods so that it isn’t visible in the most common use cases, then that information is mostly hidden. Such information will create fewer dependencies than information that is visible to every user of the class. 5.2 Information leakage The opposite of information hiding is information leakage. Information leakage occurs when a design decision is reflected in multiple modules. This creates a dependency between the modules: any change to that design
  • 49. decision will require changes to all of the involved modules. If a piece of information is reflected in the interface for a module, then by definition it has been leaked; thus, simpler interfaces tend to correlate with better information hiding. However, information can be leaked even if it doesn’t appear in a module’s interface. Suppose two classes both have knowledge of a particular file format (perhaps one class reads files in that format and the other class writes them). Even if neither class exposes that information in its interface, they both depend on the file format: if the format changes, both classes will need to be modified. Back-door leakage like this is more pernicious than leakage through an interface, because it isn’t obvious. Information leakage is one of the most important red flags in software design. One of the best skills you can learn as a software designer is a high level of sensitivity to information leakage. If you encounter information leakage between classes, ask yourself “How can I reorganize these classes so that this particular piece of knowledge only affects a single class?” If the affected classes are relatively small and closely tied to the leaked information, it may make sense to merge them into a single class. Another possible approach is to pull the information out of all of the affected classes and create a new class that encapsulates just that information. However, this approach will be effective only if you can find a simple interface that abstracts away from the details; if the new class exposes most of the knowledge through its interface, then it won’t provide much value (you’ve simply replaced back-door leakage with leakage through an interface). Red Flag: Information Leakage Information leakage occurs when the same knowledge is used in multiple places, such as two different classes that both understand the format of a particular type of file. 5.3 Temporal decomposition One common cause of information leakage is a design style I call temporal decomposition. In temporal decomposition, the structure of a system
  • 50. corresponds to the time order in which operations will occur. Consider an application that reads a file in a particular format, modifies the contents of the file, and then writes the file out again. With temporal decomposition, this application might be broken into three classes: one to read the file, another to perform the modifications, and a third to write out the new version. Both the file reading and file writing steps have knowledge about the file format, which results in information leakage. The solution is to combine the core mechanisms for reading and writing files into a single class. This class will get used during both the reading and writing phases of the application. It’s easy to fall into the trap of temporal decomposition, because the order in which operations must occur is often on your mind when you code. However, most design decisions manifest themselves at several different times over the life of the application; as a result, temporal decomposition often results in information leakage. Order usually does matter, so it will be reflected somewhere in the application. However, it shouldn’t be reflected in the module structure unless that structure is consistent with information hiding (perhaps the different stages use totally different information). When designing modules, focus on the knowledge that’s needed to perform each task, not the order in which tasks occur. Red Flag: Temporal Decomposition In temporal decomposition, execution order is reflected in the code structure: operations that happen at different times are in different methods or classes. If the same knowledge is used at different points in execution, it gets encoded in multiple places, resulting in information leakage. 5.4 Example: HTTP server To illustrate the issues in information hiding, let’s consider the design decisions made by students implementing the HTTP protocol in a software design course. It’s useful to see both the things they did well and they areas where they had problems.
  • 51. HTTP is a mechanism used by Web browsers to communicate with Web servers. When a user clicks on a link in a Web browser or submits a form, the browser uses HTTP to send a request over the network to a Web server. Once the server has processed the request, it sends a response back to the browser; the response normally contains a new Web page to display. The HTTP protocol specifies the format of requests and responses, both of which are represented textually. Figure 5.1 shows a sample HTTP request describing a form submission. The students in the course were asked to implement one or more classes to make it easy for Web servers to receive incoming HTTP requests and send responses. Figure 5.1: A POST request in the HTTP protocol consists of text sent over a TCP socket. Each request contains an initial line, a collection of headers terminated by an empty line, and an optional body. The initial line contains the request type (POST is used for submitting form data), a URL indicating an operation (/comments/create) and optional parameters (photo_id has the value 246), and the HTTP protocol version used by the sender. Each header line consists of a name such as Content- Length followed by its value. For this request, the body contains additional parameters (comment and priority). 5.5 Example: too many classes The most common mistake made by students was to divide their code into a large number of shallow classes, which led to information leakage between the classes. One team used two different classes for receiving HTTP requests; the first class read the request from the network connection into a string, and the second class parsed the string. This is an example of a temporal decomposition (“first we read the request, then we parse it”). Information leakage occurred because an HTTP request can’t be read without parsing much of the message; for example, the Content-Length header specifies the length of the request body, so the headers must be parsed in order to compute the total request length. As a result, both classes needed to understand most
  • 52. of the structure of HTTP requests, and parsing code was duplicated in both classes. This approach also created extra complexity for callers, who had to invoke two methods in different classes, in a particular order, to receive a request. Because the classes shared so much information, it would have been better to merge them into a single class that handles both request reading and parsing. This provides better information hiding, since it isolates all knowledge of the request format in one class, and it also provides a simpler interface to callers (just one method to invoke). This example illustrates a general theme in software design: information hiding can often be improved by making a class slightly larger. One reason for doing this is to bring together all of the code related to a particular capability (such as parsing an HTTP request), so that the resulting class contains everything related to that capability. A second reason for increasing the size of a class is to raise the level of the interface; for example, rather than having separate methods for each of three steps of a computation, have a single method that performs the entire computation. This can result in a simpler interface. Both of these benefits apply in the example of the previous paragraph: combining the classes brings together all of the code related to parsing an HTTP request, and it replaces two externally-visible methods with one. The combined class is deeper than the original classes. Of course, it is possible to take the notion of larger classes too far (such as a single class for the entire application). Chapter 9 will discuss conditions under which it makes sense to separate code into multiple smaller classes. 5.6 Example: HTTP parameter handling After an HTTP request has been received by a server, the server needs to access some of the information from the request. The code that handles the request in Figure 5.1 might need to know the value of the photo_id parameter. Parameters can be specified in the first line of the request (photo_id in Figure 5.1) or, sometimes, in the body (comment and priority in Figure 5.1). Each parameter has a name and a value. The values of parameters use a special encoding called URL encoding; for example, in the value for comment in Figure 5.1, “+” is used to represent a space character,
  • 53. and “%21” is used instead of “!”. In order to process a request, the server will need the values for some of the parameters, and it will want them in unencoded form. Most of the student projects made two good choices with respect to parameter handling. First, they recognized that server applications don’t care whether a parameter is specified in the header line or the body of the request, so they hid this distinction from callers and merged the parameters from both locations together. Second, they hid knowledge of URL encoding: the HTTP parser decodes parameter values before returning them to the Web server, so that the value of the comment parameter in Figure 5.1 will be returned as “What a cute baby!”, not “What+a+cute+baby%21”). In both of these cases, information hiding resulted in simpler APIs for the code using the HTTP module. However, most of the students used an interface for returning parameters that was too shallow, and this resulted in lost opportunities for information hiding. Most projects used an object of type HTTPRequest to hold the parsed HTTP request, and the HTTPRequest class had a single method like the following one to return parameters: public Map<String, String> getParams() { return this.params; } Rather than returning a single parameter, the method returns a reference to the Map used internally to store all of the parameters. This method is shallow, and it exposes the internal representation used by the HTTPRequest class to store parameters. Any change to that representation will result in a change to the interface, which will require modifications to all callers. When implementations are modified, the changes often involve changes in the representation of key data structures (to improve performance, for example). Thus, it’s important to avoid exposing internal data structures as much as possible. This approach also makes more work for callers: a caller must first invoke getParams, then it must call another method to retrieve a specific parameter from the Map. Finally, callers must realize that they should not modify the Map returned by getParams, since that will affect the internal state of the HTTPRequest.
  • 54. Here is a better interface for retrieving parameter values: public String getParameter(String name) { ... } public int getIntParameter(String name) { ... } getParameter returns a parameter value as a string. It provides a slightly deeper interface than getParams above; more importantly, it hides the internal representation of parameters. getIntParameter converts the value of a parameter from its string form in the HTTP request to an integer (e.g., the photo_id parameter in Figure 5.1). This saves the caller from having to request string-to-integer conversion separately, and hides that mechanism from the caller. Additional methods for other data types, such as getDoubleParameter, could be defined if needed. (All of these methods will throw exceptions if the desired parameter doesn’t exist, or if it can’t be converted to the requested type; the exception declarations have been omitted in the code above). 5.7 Example: defaults in HTTP responses The HTTP projects also had to provide support for generating HTTP responses. The most common mistake students made in this area was inadequate defaults. Each HTTP response must specify an HTTP protocol version; one team required callers to specify this version explicitly when creating a response object. However, the response version must correspond to that in the request object, and the request must already be passed as an argument when sending the response (it indicates where to send the response). Thus, it makes more sense for the HTTP classes to provide the response version automatically. The caller is unlikely to know what version to specify, and if the caller does specify a value, it probably results in information leakage between the HTTP library and the caller. HTTP responses also include a Date header specifying the time when the response was sent; the HTTP library should provide a sensible default for this as well. Defaults illustrate the principle that interfaces should be designed to make the common case as simple as possible. They are also an example of partial information hiding: in the normal case, the caller need not be aware of the existence of the defaulted item. In the rare cases where a caller needs to
  • 55. Another Random Document on Scribd Without Any Related Topics
  • 59. The Project Gutenberg eBook of The Legal Position of the Clergy
  • 60. This ebook is for the use of anyone anywhere in the United States and most other parts of the world at no cost and with almost no restrictions whatsoever. You may copy it, give it away or re-use it under the terms of the Project Gutenberg License included with this ebook or online at www.gutenberg.org. If you are not located in the United States, you will have to check the laws of the country where you are located before using this eBook. Title: The Legal Position of the Clergy Author: Philip Vernon Smith Release date: August 28, 2012 [eBook #40606] Most recently updated: October 23, 2024 Language: English Credits: Produced by David Clarke, Ian Swainson and the Online Distributed Proofreading Team at http://www.pgdp.net *** START OF THE PROJECT GUTENBERG EBOOK THE LEGAL POSITION OF THE CLERGY ***
  • 61. Handbooks for the Clergy EDITED BY ARTHUR W. ROBINSON, B.D. VICAR OF ALLHALLOWS BARKING BY THE TOWER THE LEGAL POSITION OF THE CLERGY
  • 62. THE LEGAL POSITION OF THE CLERGY BY P. V. SMITH, LL.D. CHANCELLOR OF THE DIOCESE OF MANCHESTER AUTHOR OF "THE LAW OF CHURCHWARDENS AND SIDESMEN IN THE TWENTIETH CENTURY," ETC. LONGMANS, GREEN, AND CO. 39 PATERNOSTER ROW, LONDON NEW YORK AND BOMBAY 1905
  • 64. PREFACE In the following pages an endeavour has been made to give a succinct sketch of the legal position of the parish clergy of the Church of England in respect both of spiritualities and of temporalities. The book, being intended for their use, does not touch upon the subject of ordination by which they acquired the status of deacons or priests. Nor does it deal with the episcopate or the non- parochial clergy, except so far as these subjects are connected with the parochial system. Like all other human arrangements, our English Church law is, of course, far from being ideally perfect. It may be safely affirmed that there has never been either a Church or a State in which the law has actually been what it ideally ought to have been. It is important to recognise the difference between the two positions; for there has sometimes been a disposition on the part of individuals to confuse them, and to treat what they consider to be the ideal law, as if it were the actual law, and as if, as such, it demanded their loyal obedience. Such an attitude, whether in ecclesiastical or civil matters, is anarchical in its tendency; for it sets up private judgment instead of the constituted authority as the criterion of what ought or ought not to be done. It can only be justified where the actual law is absolutely inconsistent with the fundamental principles of morality or of Christian truth. The object of the present treatise is to state succinctly what the law is,—not what it ought to be; and no opinion is expressed or suggestion offered as to points in which amendment would be proper or expedient. Within the limited compass of the book it is obviously impossible to enter into details; and the reader who desires information as to these will find them in the authorities to which reference is made. It must also be borne in mind that the general law on the subject of
  • 65. P. V. SMITH. buildings, property, and pecuniary rights is, in various places, modified by special local enactments or customs. These can only be ascertained on the spot, or by consulting the Acts of Parliament in which they are embodied or recorded. One other word of caution is desirable. In explaining the legal position of the parochial clergy, it is, of course, necessary to indicate the exact limits of their rights. If they venture beyond these limits, they are manifestly in the wrong. But no community, either ecclesiastical or civil, could maintain its well-being, or even its coherence, if every individual were on all occasions to take advantage of the full tether of his legal rights. It will frequently be wise and proper for the clergy, in their relations with their ecclesiastical superiors or with the lay officials and other laity of the parish, not to adopt the most uncompromising attitude which the letter of the law permits to them. The dictates of love and of Christian forbearance, and of consideration for the claims of others, as well as of expediency, will not warrant the infringement by an individual of the ordinances of either the Church or the State. But they will more than justify him in refraining from taking up a position of defiance which these ordinances may strictly entitle him to assume. Easter, 1905.
  • 66. pages xxi-xiv pages 1-24 CONTENTS List of Abbreviations CHAPTER I General Legal Position 1.Spiritual, ecclesiastical, and civil status of the clergy. 2. Sources of Church law. 3. Written and unwritten law—Foreign Canon law—Pre- Reformation Canons—Acts of Parliament—Canons of 1603—Canons of 1640—Other canons. 4. Decisions of Church courts—Distinction between judicial and legislative action. 5. Legal status of the ancient Parish—Rector or Parson—Patronage or Advowson—Vicar—Perpetual curate. 6. Dissolution of the Monasteries—Impropriate rectories— New churches and ecclesiastical parishes—Assistant parochial clergy —Titular vicars—Incumbent—Curate. 7. Minister in charge—Lecturer. 8. Status of clergy ordained elsewhere than in England or Ireland, or ordained for service in the colonies or foreign countries—Scottish clergy. 9. Benefices—Beneficed and unbeneficed clergy. 10. Bishops, their relation to the clergy—Suffragan bishops—Chancellors. 11. Archdeacons. 12. Rural Deans. 13. Judicial procedure—Church Discipline Act, 1840—Public Worship Regulation Act, 1874—Clergy Discipline Act, 1892. 14. Abstinence of Clergy from secular pursuits. 15. Civil exemptions—Municipal and Parliamentary qualifications and disqualifications. 16. Restrictions as to labour, business, and trade— Lawful exceptions—Penalties for unlawful trading. 17. Protection in performance of religious rites—Act against brawling. 18. Indelibility of Orders—Relinquishment of clerical status
  • 67. CHAPTER II Beneficed Clergy 1. Admission by bishop on presentation of patron—Lapse to bishop, archbishop, or Crown. 2. Transfers of advowsons or rights of presentation—Next presentations—Power of patron to present himself—Restrictions under Benefices Act, 1898. 3. Qualification for admission—Grounds for refusal by bishop—Testimony as to fitness. 4. Procedure in case of refusal by bishop. 5. Publication of notice of intended admission. 6. Mode of admission—Institution—Licence— Collation—Declarations of assent and against simony—Oaths of allegiance and canonical obedience—Reading of Thirty-nine Articles. 7. Effect of admission—Induction. 8. Fees on admission. 9. Cure of Souls—Duties laid down in Ordination Service—Residence—Divine service—Marriages—Burials—Private ministrations. 10. Exclusive right of administration—Superior right of bishop—Modern comity as between town parishes. 11. Private ministrations—Service in unconsecrated buildings—Meetings for worship. 12. Private chapels —Chapels of institutions—Unconsecrated proprietary chapels. 13. Formation of new parishes—Approval or otherwise of incumbent. 14. Holding of two benefices. 15. Neglect of duty—Commission of inquiry—Procedure on adverse report of Commission. 16. Residence on benefice—Forfeitures for non-residence—Bishop's licence of non- residence—Grounds for licence. 17. Monition, sequestration, and avoidance of benefice for non-residence. 18. Performance of duties where incumbent is non-resident. 19. Restrictions on interfering with duties during period of non-residence. 20. Reckoning of time as to residence. 21. Vacation of benefice by death, resignation, admission to other preferment, or deprivation. 22. Resignation; unconditional except upon an exchange—Engagement to resign illegal except under Clergy Resignation Bonds Act, 1828—Corrupt resignations and exchanges—Pensions under Incumbents Resignation Acts. 23. Vacation of benefice on admission to other preferment. 24.
  • 68. pages 25-54 pages 55-64 Deprivation ipso facto—Declaration of vacancy by bishop on conviction of incumbent in certain cases—Sentences of deprivation under Acts of 1840 and 1892 CHAPTER III Unbeneficed Clergy 1. Classes of unbeneficed clergy—Bishop's licence—Declaration of assent—Examination and admission by bishop—Discretion of bishop —Revocation of licence. 2. Curates or ministers in charge—(a) On vacancy of benefice—(b) On sequestration of benefice for incumbent's bankruptcy or debt—(c) On incumbent's non-residence —(d) On incumbent's neglect of duties—(e) On formation of Peel district. 3. Assistant curates—Stipend—Notice to quit or relinquish curacy—Discretion of incumbent as to employment—Appointment where duties are inadequately performed; or where circumstances of parish require it. 4. Performance of duty by other clergy—Discretion of incumbent—Licence of bishop—Production of licence and entry of names of preachers in a book. 5. Lecturers and preachers— Performance of other ministerial duties CHAPTER IV Laity of the Parish 1. Relations between incumbent and lay officials. 2. The vestry— Constitution, meetings, and voting in ancient parishes, and in new parishes—Vestries Act, 1818—Present functions—Select vestries. 3. Churchwardens—Election in ancient and new parishes—Admission. 4. Parson's or vicar's and people's wardens—Duties: (a) Care of fabric and ornaments of the church and of the churchyard—(b) Seating of parishioners—(c) Provision of requisites for service—(d)
  • 69. pages 65-79 Maintenance of order in church and churchyard—(e) Collection and concurrence in disposal of offertory money—(f) Charge of church and benefice during vacancy, if appointed sequestrators— Restrictions on powers. 5. Sidesmen. 6. Church trustees. 7. Parish clerk—Appointment and removal. 8. Sexton. 9. Beadle. 10. Organist and choristers. 11. Officiating of lay readers and other laymen. 12. Other lay work—Visiting of poor and sick—Sunday schools—Church elementary schools. 13. Parochial church councils CHAPTER V Divine Service 1. Duty of clergy as to uniformity of service—Divergence by lawful authority—Liberty under Act of 1872. 2. Morning and Evening Prayer —Litany—Bishop 0.5em;">may order two full services, and a third service, with sermon. 3. Notices during Divine service—Notices on church door—Banns. 4. Offertory—Other collections in a church or chapel—Duty of incumbent as to money entrusted to him. 5. Questions as to the legality of various church ornaments, vestments, and ceremonies—Legal decisions as to (A) Stone Holy Table—Crucifix —Cross—Candlesticks—Flower-vases—Pictures—Sculptures— Credence table—Second Holy Table—Chancel gates—Baldacchino— Voice of parishioners in vestry—(B) Attire of clergy at Holy Communion—Surplice—Hood—Albe—Vestment or chasuble—Tunicle —Stole—Chaplain's scarf—Biretta—Black gown—(C) Incense— Processions with lighted candles—Lighted candles at Holy Communion—Mixed chalice—Wafers—Agnus Dei and other hymns— Position of minister—Genuflexions—Elevation—Sign of the Cross— Ablutions—Reservation. 6. Baptism not to be refused—Time for the ceremony—Private baptism in urgent cases—Godparents—Reception in church after private baptism—Conditional baptism—Immersion or affusion—Notice to bishop in cases of adult baptism—Deacon may baptize—Lay baptism. 7. Times for and notice of Holy Communion—
  • 70. pages 80-99 Communion not to be unlawfully refused—Who are to be repelled from it—Procedure in such cases—Jenkins v. Cook—Persons coming from other parishes—Persons attending dissenting places of worship —Persons baptized in another communion and not confirmed. 8. Sermons and homilies—Provisions of rubrics, Canons, and Acts of Parliament. 9. Catechising. 10. Churching of women CHAPTER VI Marriage 1. Duty of minister to solemnise marriage between persons legally competent—Unlawful solemnisation, when a felony—Marriage, when void. 2. Original places for banns and marriages—Churches of new parishes—Licences for banns and marriages in chapels—Parishes having no regular services in parish church—Where parish church is being rebuilt or repaired—No reconsecration necessary where church is rebuilt or enlarged and position of Holy Table altered. 3. Persons legally competent to intermarry—Religion or absence of religion of the parties no ground for refusal to solemnise marriage. 4. Minimum age—Consent of parents or guardians in case of unions—Marriage without consent, in absence of notice—Marriage below lawful age. 5. Marriage of lunatic or non compos, void. 6. Absence, unheard of, for seven years—Relief from punishment for bigamy—Invalidity of remarriage. 7 Divorce abroad—Divorce in England under Act of 1857 —Remarriage of divorced persons. 8. Marriage of foreigners— Requirements of laws of foreign States—Precautions to be observed. 9. Prohibited degrees of kindred and affinity. 10. Publication of banns—Time and form—Seven days' notice—Publication and marriage without notice and due inquiry—Publication where parties dwell in different parishes or districts—Where one dwells in Scotland, or in Ireland—What constitutes dwelling—Correct names to be published—Status need not be published—Publication to be from book and signed—Forbidding of banns. 11. Marriage, with consent of
  • 71. pages 100-120 minister, on registrar's certificate—Not permitted on registrar's licence. 12. Marriage on licence of bishop or Archbishop of Canterbury—Grant of bishop's licence—Previous affidavit before surrogate—Duty of minister on production of licence—Names in licence—Grant of licence a favour and not a right. 13. Marriage, where and when to be solemnised—Priest or deacon may marry— Penalty for solemnising marriage at improper place or time. 14. Reading of service after marriage at a registry office—Second solemnisation of marriage. 15. Fees for banns, certificate of banns, and marriage. 16. Marriage register books—Certificate of marriage. 17. Presumption of marriage of persons coming to Holy Communion —Proof of no marriage—Validity of marriage governed by law of place of solemnisation—Capacity to contract marriage governed by law of domicile—-Marriage between British subjects in a foreign country or on board ship CHAPTER VII Burial 1. Right of burial by clergyman of the parish where death occurs— Bells to be rung—Burial in case of death in another parish—Relief in case interment is refused—No right to particular hour or spot of burial—Incumbent or churchwardens cannot sell or grant grave- spaces in perpetuity or brick graves—Reservation of exclusive right of burial on grant of addition to churchyard—Faculty for exclusive grave space in other cases—Burial of non-parishioners not dying within the parish. 2. Burial of bodies cast up by the sea or tidal or navigable water. 3. Burial of person dying unbaptized or excommunicate and of felo de se—Burial of child of dissenter or person who has received lay baptism—Interment cannot be required without convenient warning. 4. Bringing of corpse into church and burial under church. 5. Fees—Prepayment not enforceable— Customary amount—On burial of non-parishioners—Tables of fees—
  • 72. pages 121-134 pages 135-140 Special fees for brick graves, iron coffins, and other extras—Fees and rights of burial where new ecclesiastical parish has its own burial ground. 6. Use of Burial Service in unconsecrated ground—Use of special form—Permission of burial without Church rites and with or without some other service on notice under Act of 1880—Day and time for burial—Fee. 7. Delivery of registrar's certificate of death or order of coroner at funeral. 8. Fees on interments in cemeteries under Cemeteries Clauses Act, 1847. 9. Burial Acts—Consecrated and unconsecrated parts of burial grounds—Chapels—Fees of incumbents, clerks, and sextons—Sale of rights to vaults and monuments—Burial Act, 1900—Tables of fees—Restrictions on future fees to incumbents, churchwardens, and sextons—Commutation of fees. 10. Cremation—Burial of cremated remains. 11. Faculty for removal of body from one unconsecrated place of interment to another—Licence of Home Secretary for removal in other cases CHAPTER VIII Private Ministrations 1. Visitation and Communion of the Sick—-Canon 67—Order for the Visitation—Confession and absolution of the sick—Regulations as to Communion. 2. Preparation for Confirmation. 3. Spiritual advice and comfort—Confession—Absolution. 4. Ordinary visitation and intercourse CHAPTER IX Temporalities 1. Possessions and revenues of benefices of ancient parishes and new ecclesiastical parishes. 2. Incumbent a corporation sole—
  • 73. Restrictions on his acquisition and holding of landed property— Licence in mortmain—Mortmain and Charitable Uses Acts—School Sites Acts—Inability to hold as a corporation land upon trusts. 3. Freehold of church and churchyard of ancient parish in rector— Chancel repairable by rector—Enforcement of repairs—Possession and custody of church in incumbent and churchwardens—Right of incumbent to keys and control of organ and bells—Canon 88—Right of rector to profits of soil of churchyard—Felling of trees in churchyard—Freehold of church and churchyard of new parish in incumbent—Exemption from rates and contributions to making new streets—Removal of part of church as a dangerous structure. 4. Rights of bishop and parishioners in church and churchyard—Power of incumbent as to ordinary tombstones and inscriptions in churchyard—Glass shades for wreaths—Appeal to consistory and higher courts—Faculties for monuments in church and other alterations and additions in church and churchyard—Application by incumbent and churchwardens after resolution of vestry—Consent of rector to alteration in chancel—Faculty for vault or space for exclusive burial—Removal of earth or bones from churchyard, or other desecration—Faculty for diversion of ancient footpath through churchyard, and for throwing part of churchyard into highway— Restoration of wall wilfully thrown down—Easement of light and air over churchyard—Laying out of closed churchyard as a garden and removal of gravestones—Restrictions as to building on closed or disused burial-grounds. 5. Glebe, rectorial and vicarial—Exemption from tithe—Waste—Cultivation of glebe—Cutting down of trees— Opening and working of mines and quarries and gravel pits. 6. Statutory facilities for parsonage houses and other buildings and repair of chancels—Gilbert Acts—Loans by, and mortgages to Queen Anne's Bounty—Purchase of land—Building and improving of farm buildings and labourers' dwellings—Gifts and bequests of parsonage houses and glebe—Sale and exchange of parsonage houses and glebe. 7. Letting of parsonage house where incumbent has licence to reside elsewhere. 8. Farming or letting of glebe—Agricultural, building, and mining leases. 9. Repair of parsonage house and glebe buildings—Ecclesiastical Dilapidations Act, 1871. 10. Diocesan
  • 74. surveyors—Proceedings (a) on vacancies in benefices and (b) in other cases—Exemption from liability for five years after certificate of surveyor. 11. (a) Inspection and report by surveyor on a vacancy— Objections to report—Order of bishop—Debt from late incumbent, or his estate, to new incumbent—Payment of amount recovered to Queen Anne's Bounty—Loan of amount not recovered—Balance to be paid by new incumbent—Dilapidation Account—Liability where a vacancy occurs between inspection of buildings and certificate of completion of works. 12. (b) Inspection of buildings on complaint of archdeacon, rural dean, or patron, or on request of incumbent— Inspection after and during sequestration of benefice—Report— Objections—Decision of bishop—Loans—Dilapidation Account— Execution of repairs—-Charge of cost on income in case of benefice under sequestration—Vacancy before execution of works—Liability of sequestrator spending excessive amount on repairs. 13. Payment of money out of dilapidation account on certificate of surveyor—Liability and duty of incumbent—Rebuilding or remodelling instead of repairing. 14. Insurance of parsonage house, glebe buildings, and chancel against fire—Production of receipts for premiums at visitations—Payment and application of insurance money and reinstatement of buildings in the event of fire—Sequestration of benefice to raise any requisite balance. 15. Exemption from Act of 1871 of buildings let on lease under which tenant is liable— Inspection by surveyor. 16. Faculty or consent of bishop and patron to alterations in buildings—Liability of incumbent for alterations not so sanctioned—Power of bishop to authorise removal of unnecessary buildings—Movable sheds or garden frames. 17. Vacation of benefice —Cesser of rights of former incumbent—Right of widow to two months' residence in parsonage house—Inspection of premises pending settlement of dilapidations—Emblements—Apportionment of rents, tithe rentcharge, and other income. 18. Tithe commutation rentcharge under Act of 1836 and amending Acts—Assessment in lieu of great or rectorial tithes and small or vicarial tithes— Extraordinary tithe rentcharge in respect of hop and other gardens and orchards—Act of 1886—Assessment of tithe rentcharge with regard to prices of wheat, barley, and oats—Variation according to
  • 75. pages 141-168 pages 169-174 septennial average prices. 19. Payment of tithe rentcharge and recovery by distress on appointment of receiver—Recovery from railway company. 20. Dues (i.) ordinary and (ii.) special—Variety by law and custom—Payments on the customary four offering days— Easter offerings—Rights of vicar of new ecclesiastical parish. 21. Mortuaries. 22. Dues for special services or concessions. 23. Pew rents under special or general Acts of Parliament—Under Church Building and New Parishes Acts—Recovery of pew rents. 24. First fruits and tenths—Exemption of small benefices—Number of benefices remaining liable. 25. Income or property tax—On parsonage house, glebe lands, and tithe rentcharge—On landed property in occupation of incumbent—On other stipend, fees, perquisites, and profits—Legal deductions—Test as to whether receipts are or are not liable to tax—Voluntary contributions to minister in respect of his office—Grants from Curates' Augmentation Fund—Grants from Queen Victoria Clergy Fund Index
  • 76. LIST OF ABBREVIATIONS A. C. Law Reports (House of Lords and Privy Council) 1891 onwards. A. & E. Adolphus & Ellis's Reports (King's Bench)1834-41. Add. Addam's Reports (Ecclesiastical) 1822-6. Ambl. Ambler's Reports (Chancery) 1737-83. App. Ca. Law Reports (House of Lords and Privy Council) 1875-90. Atk. Atkyn's Reports (Chancery) 1735-54. Ayl. Par. Ayliffe's Parergon Juris Canonici Anglicani, 1726. B. & C. Barnewall & Cresswell's Reports (King's Bench) 1822-30. B. & Ad. Barnewall & Adolphus' Reports (King's Bench) 1830- 34. B. & Ald. Barnewall & Alderson's Reports (King's Bench) 1818-22. B. & Sm. Best & Smith's Reports (Queen's Bench) 1861-70. Beav. Beavan's Reports (Chancery) 1838-66. Bl. Comm. Blackstone's Commentaries on the Laws of England. Burn. Burn's Ecclesiastical Law, 4 vols. Canon. One of the Constitutions and Canons Ecclesiastical agreed upon in the Canterbury convocation begun in 1603. C. B. Common Bench Reports, 1845-56. C. B. N. S. Common Bench Reports, New Series, 1856-65. C. & K. Carrington & Kirwan's Reports (Nisi Prius) 1843- 1853. C. P. D. Law Reports (Common Pleas Division) 1875-80. Ch. Law Reports, Chancery Division, 1891 onwards.
  • 77. Ch. D. Law Reports, Chancery Division, 1875-90. Cl. & F. Clark & Finnelly's Reports (House of Lords) 1831-46. Clarke, Proxis Francis Clarke's Proxis in Curiis Ecclesiasticis, 1666, 1684. Co. Inst. Coke's Institutes of the Laws of England, Second Part. Co. Litt. Coke upon Littleton (with notes by Hargrave and Butler). Co. Rep. Coke's Reports, 1598-1616. Com. Dig. Comyn's Digest. Cowp. Cowper's Reports (King's Bench) 1774-78. Cripps. Cripps's Law relating to the Church and Clergy, 6th ed., 1886. Cro. Jac. Croke's Reports (temp. James I.) 1603-1625. Curt. Curteis's Ecclesiastical Reports, 1834-44. Degge. Sir Simon Degge's Parson's Counsellor. Dr. & Sm. Drewry & Smale's Reports (Chancery) 1859-65. E. & B. Ellis & Blackburn's Reports (Queen's Bench) 1854-8. Eccl. & Adm. Ecclesiastical & Admiralty Reports (Spinks) 1853-5. El. & El. Ellis & Ellis' Reports (Queen's Bench) 1858-61. Ex. Exchequer Reports, 1847-56. Ex. D. Law Reports (Exchequer Division) 1875-1880. Geary Geary's Law of Marriage and Family Relations (A. & C. Black, 1892). Gibs. Cod. Gibson's Codex Juris Ecclesiastici Anglicani. Hag. Cons. Haggard's Consistory Reports, 1729-1821. Hag. Eccl. Haggard's Ecclesiastical Reports, 1827-1832. H. & C. Hurlstone & Coltman's Reports (Exchequer) 1862- 66. H. L. C. House of Lords Cases, 1847-66. Hob. Hobart's Reports, 1611-20. Ir. Ch. Rep. App. Irish Chancery Reports (Appendix).
  • 78. J. & H. Johnson & Hemming's Reports (Chancery) 1859-62. J. P. Justice of the Peace, 1837 onwards. Johns. John Johnson's Clergyman's Vade Mecum, 6th ed., 1731. Jur. Jurist (Reports) 1837-54. Jur. N. S. Jurist, New Series (Reports) 1855-66. K. B. Law Reports (King's Bench) 1901 onwards. L. J. (Ch., C.P., Ex. Q.B.) Law Journal 1823-31; New Series 1832 onwards (Chancery, Common Pleas, Exchequer, Queen's Bench). L. J. Eccl. Ditto (Ecclesiastical Cases). L. J. M. C. Ditto (Magistrates' Cases). L. J. P. M. & A. Ditto (Probate, Matrimonial, and Admiralty Cases). L. R. A. & E. Law Reports, 1865-75 (Admiralty and Ecclesiastical). L. R. C. P. Ex. Q. B. Ditto (Common Law). L. R. Ch. Ditto (Chancery Appeals). L. R. Eq. Ditto (Equity). L. R. H. L. Ditto (House of Lords). L. R. H. L. Sc. Ditto (Scotch and Divorce Appeals). L. R. P. C. Ditto (Privy Council). L. T. N. S. Law Times (New Series) Reports, 1859 onwards. M. & S. Maule & Selwyn's Reports (King's Bench) 1813-17. M. & W. Meeson & Welsby's Reports (Exchequer) 1836-47. Marsh. Marshall's Reports (Common Pleas) 1813-1816. Mer. Merivale's Reports (Chancery) 1815-17. Moo. P. C. Moore's Privy Council Reports, 1836-62. Moo. P. C. N. S. Ditto, New Series, 1862-73. N. R. New Reports (Equity and Common Law) 1862-65. Not. of Ca. Notes of Cases (Ecclesiastical and Maritime) 1841- 50. P. Law Reports, Probate Division, 1891 onwards.
  • 79. P. D. Law Reports, Probate Division, 1875-90. Phill. Phillimore's Reports (Ecclesiastical) 1809-1821. Phill. Eccl. Law Phillimore's Ecclesiastical Law of the Church of England, 2 vols., 2nd ed., 1895. P. Wms. Peere Williams' Reports (Chancery) 1695-1735. Q. B. Queen's Bench Reports (Adolphus & Ellis) 1841-52. Q. B. Law Reports (Queen's Bench) 1891-1900. Q. B. D. Law Reports (Queen's Bench Division) 1875-1890. Rob. Eccl. Robertson's Reports (Ecclesiastical) 1844-1853. Sc. L. R. Scottish Law Reporter, 1865 onwards. Sm. Churchw. Smith's Law of Churchwardens and Sidesmen in the Twentieth Century (Wells, Gardner, & Co., 2s.). Str. Strange's Reports, 1715-47. Strype's Annals John Strype's Annals of the Reformation (ed. 1824) 4 vols. Sw. & Tr. Swabey & Tristram's Reports (Probate and Divorce) 1858-65. Taun. Taunton's Reports (Common Pleas) 1807-1819. Times Law Rep. Times Law Reports, 1884 onwards. T. R. Durnford & East's Term Reports (King's Bench) 1785-1800. Trist. Cons. Judgm. Tristram's Consistory Judgments, 1872-90. Ventr. Ventris' Reports (King's Bench) 1668-91. Ves. Vesey Junior's Reports (Chancery) 1789-1816. Wats. Watson's Clergyman's Law, 4th ed., 1747. Willes Willes Reports (Common Pleas) 1737-58. Wils. Wilson's Reports (Common Law) 1743-74. W. R. Weekly Reporter, 1853 onwards. Yo. & Jer. Younge & Jervis's Reports (Exchequer) 1826-30.
  • 82. 1. In every country where a Christian Church is permitted to exist, the power and authority of her clergy to exercise their functions will rest upon a triple basis and be subject to twofold restrictions and limitations. In the first place, (i.) they derive their spiritual authority from their ordination, and this authority is independent of the particular Church to which they belong. But, in the next place, they are bound on the one hand (ii.) to obey the regulations of the Church of which they are the ministers, and must also, on the other hand, (iii.) conform to the laws of the country in which they labour. For they can only actively exercise their functions by the licence or permission of the ruling power of that country, and subject to any conditions which it may choose to impose. These principles apply equally whether the Church is what we call established or not. The only difference is that if the Church is established, her own regulations are part of the law of the land; whereas, if she is not established, the law of the land sanctions or suffers the existence of these regulations as a private contract or arrangement between the ministers and other members of the Church. But even in the case of an established Church, her ministers will obviously be restricted in the exercise of their functions by civil regulations which do not form part of the ecclesiastical law. Thus there may be nothing in the law of his Church to prevent a clergyman from holding a religious service or preaching in a crowded thoroughfare. But in England and other civilised countries any attempt to do so would be checked by the existing laws against the obstruction of highways. In the following pages no attempt will be made to point out the non-ecclesiastical laws and limitations to which a parish priest is subject. For though they necessarily affect himself and his spiritual work, they do so only indirectly. They touch him not as a minister or even as a Christian, but as a citizen; and they touch his spiritual work only in so far as that work has a material and civil element.
  • 83. 2. Confining then our attention to the ecclesiastical law under which the parish priest holds his position and acts in this country, we note in the first place, that the Church being here established, this ecclesiastical law is equally the law of the Church and the law of the State. This is true whatever be its origin, and however it came into force; and it has always had this double aspect, since (with the exception of the brief interval of the Commonwealth—a period which is not recognised in our jurisprudence as having had any legal existence) there never has been a time in our history when the Church of England has not been the Established Church of the nation. Portions of our Church system and Church law have had an exclusively ecclesiastical origin, by canon or otherwise, and have been adopted or acquiesced in by the State. Further portions have been created by the joint or concurrent action of the Church and the State. Other portions again have been due to the sole action of the civil legislature, which has received the tacit assent of the Church but has never been confirmed by any formal ecclesiastical ratification. From whichever of these three sources any particular point of our Church law may have been derived, its validity and obligation is the same. It binds the Church and her ministers and members irrespectively of its origin, and is at present in force unless it has either been formally repealed or become obsolete and fallen into desuetude.
  • 84. 3. Again, like our civil law, our ecclesiastical law is in part written and in part unwritten or customary. Foreign canon or conciliar law or papal law is only binding in England so far as it has been received by immemorial custom, and has thus become part of our unwritten law, or has been incorporated into our written law by the ratification of an Act of Parliament, or a canon or constitution of our own Church; and the binding force of the English Pre-Reformation canons, ordinances, and provincial constitutions stands on the same footing. For the Commission authorised by the Act for the Submission of the Clergy of 1533 to examine the English canons and constitutions, and, with the king's assent, declare which of them should be in force and which should be abrogated, was never appointed, although the time for its appointment was extended by Acts of 1535 and 1543, and the scope of its inquiry was extended by the latter Act so as to include foreign canons and ordinances.[1] Consequently the only written Church law is to be found in Acts of Parliament and the Prayer-Book,[2] and in Post-Reformation canons, which, however, except so far as they are confirmed by Act of Parliament, or declare the unwritten law of the Church, are only binding on the clergy.[3] Of these the chief are those known as the Canons of 1603, which were agreed upon at the sitting of the Canterbury Convocation begun in that year, and were separately passed two years afterwards by the York Convocation. Many portions of them are, however, now obsolete; and Canon 36 and the last words of Canon 102 have been superseded by new canons made in 1865-66 and 1888. The Canons of 1640 were passed after the dissolution of Parliament, which, according to the custom of the realm, put an end also to the existence of Convocation, and they have no legal force.[4]
  • 85. 4. Much discussion has arisen upon a fourth source of Church law, namely, the decisions of our ecclesiastical courts. It is important to draw a clear distinction between legislative and judicial functions. A court, whether ecclesiastical or civil, has nothing to do with enacting laws. Its province is confined to interpreting them, when their meaning is obscure or disputed. No doubt, in the course of this interpretation, it will sometimes make law by deciding in a particular way a point on which the legislature has left the matter in doubt, and has not itself clearly laid down the law. Many questions affecting the clergy and the Church have, in fact, been thus determined by our civil as well as by our ecclesiastical tribunals. But if one of our civil courts, in interpreting the civil law, delivers a decision which does not commend itself to the common sense of the nation, it is recognised that the remedy lies not in altering the constitution of the court and endeavouring to obtain a fresh legal decision which shall upset the other, but in obtaining an Act of Parliament expressly over- ruling the unsatisfactory decision. If this is not done, the law may have been technically judge-made, but it is acquiesced in and assented to by Parliament and the nation. The same principle applies to the decisions of ecclesiastical courts. The natural way of getting rid of an obnoxious decision is not by fresh adjudication, but by legislation. Until it has been reversed by one or other of these means, the decision of a court, which de facto possesses ecclesiastical jurisdiction, is binding upon the Church as part of her law for the time being. We have somewhat lost sight of this principle, owing to the extreme difficulty of obtaining any definition or alteration of Church law by a legislative process. But the true remedy lies in a healthy revival of the exercise of ecclesiastical legislation, and not in an endeavour to make the ecclesiastical judicature, whether as now existing or after a reform of the courts, discharge legislative functions which are wholly outside its proper province.
  • 86. 5. The legal position of the parochial clergy depends for its ultimate origin upon the legal status of the ancient Parish. The word is the English form of the Greek παροικία (habitation), and the Latin parochia, an expression originally synonymous with diocese (Gr. διοίκησις, i.e. administration; Lat. diœcesis, used of a district or part of a province in the Roman Empire), and applied to the territory assigned to the jurisdiction of a bishop, which was served by him and a college of clergy under him. But under Archbishop Theodore (668-690) or shortly after his time the process was begun of encouraging the lords of manors and great landowners to build churches for themselves and their dependants, and devote the tithes of their manors or estates to the maintenance of divine worship in these churches, and the performance of religious duties among the residents on the estates. This process was gradually extended throughout the country, and, wherever it was adopted, the tithes were assigned either to the priest for the time being in charge of the church, who was in that case called the rector (governor of the church) or parson (Lat. persona)[5] or to a monastery, the members of which were then expected to serve the church. The manor or estate, including any detached and outlying portions, became the parish of the church, and developed into a territorial unit not only for ecclesiastical but also for many civil purposes. Where the church was served by a single rector, the landowner who had endowed it and his successors after him were given in return the right of nominating to the bishop a clerk in Holy Orders to become rector of the church, or, in other words, they acquired the patronage or advowson[6] of the benefice. The frequent cases of neglect in the service of the parish, where a monastery was rector, led, in the thirteenth century, to the requirement that in such cases a succession of individual priests should be appointed to discharge the duty, with a definite portion of the endowments of the benefice as their stipend for so doing. As a rule the great tithes, being those of corn, grain, hay, and wood, were reserved to the monastery, and were in consequence styled rectorial tithes, while the officiating priest, who was styled a vicar,
  • 87. was endowed with the remaining or small tithes, which consequently were called vicarial. But in a few instances the officiating priest, instead of becoming entitled to the small tithes, only received a fixed monetary stipend. Where this occurred, he was called a perpetual curate. It was the rule that rectories, whether in the hands of a monastery or a succession of individual priests, should be endowed not only with the tithes of the parish, but also with a house and lands, which are called glebe; and sometimes these houses and lands, or a part of the lands, were assigned towards the stipend of the vicar.
  • 88. 6. Towards the close of Henry VIII.'s reign the monasteries were dissolved, and their rectories and the rectorial tithes of the parishes and other endowments attached thereto, and the right of nominating vicars or perpetual curates to the parishes passed, with the rest of the monastic property, in some cases into the hands of the Crown or of private individuals who received grants of them from the Crown, while in other cases they went to the endowment of episcopal sees or of colleges, hospitals, or other public institutions. Whichever happened, the rectory and rectorial tithes became thenceforth impropriate, and the vicar or perpetual curate was left with the vicarial tithes and other endowments, or a stipend, as the case might be, to serve the parish as the beneficed parish priest. Later on, and particularly during the nineteenth century, the growth of the population and the rapid increase of our urban centres, owing to the steady migration from the villages to the towns, has rendered the building of new churches and the creation of new ecclesiastical areas a matter of pressing importance; and the same causes have necessitated the employment in the larger parishes of additional clergy, whether stipendiary or voluntary. In some cases an old parish has been divided into distinct and separate parishes, each of which has received a portion of the old church endowments, and has become a rectory, vicarage, or perpetual curacy, according to the status of the old parish;[7] or a vicarage has been converted into a rectory upon a surrender of the rectorial tithes by the impropriator. [8] But, as a rule, new ecclesiastical districts or parishes have been formed and churches built without resorting to the old endowments; and the Church Building and New Parishes Acts provided that the ministers put in charge of these new districts or parishes and churches should be perpetual curates, and should, like the old rectors, vicars, and perpetual curates, be corporations, with perpetual succession.[9] But in 1868 it was enacted that the incumbent of every parish and new ecclesiastical parish, who was authorised to publish banns, and solemnise marriages, churchings, and baptisms in his church, and was not a rector, should, for the
  • 89. purpose of designation only, be styled a vicar, and his benefice should for the same purpose be styled a vicarage.[10] The modern generic title, which includes every beneficed parish priest, is incumbent. The proper and ancient term for rectors, vicars, and all other parochial clergy, whether beneficed or unbeneficed, is curate, as having the cure of souls within the parish.[11] But in modern practice this term, when used by itself, is generally applied to the unbeneficed or assistant curates in a parish.
  • 90. 7. Two other classes of parochial clergy remain to be mentioned. Where, for any reason, the incumbent is for a prolonged period disabled from performing the duties of his office, a substitute will be appointed under the designation of Minister in Charge. Again, in some parishes, lectureships have been endowed, and are held by a lecturer, who, in respect of his duties as such, is independent of the incumbent.
  • 91. Welcome to our website – the perfect destination for book lovers and knowledge seekers. We believe that every book holds a new world, offering opportunities for learning, discovery, and personal growth. That’s why we are dedicated to bringing you a diverse collection of books, ranging from classic literature and specialized publications to self-development guides and children's books. More than just a book-buying platform, we strive to be a bridge connecting you with timeless cultural and intellectual values. With an elegant, user-friendly interface and a smart search system, you can quickly find the books that best suit your interests. Additionally, our special promotions and home delivery services help you save time and fully enjoy the joy of reading. Join us on a journey of knowledge exploration, passion nurturing, and personal growth every day! ebookbell.com