138 lines
5.6 KiB
Org Mode
138 lines
5.6 KiB
Org Mode
:PROPERTIES:
|
||
:ID: f4975aa1-bd2e-46f5-9b9b-851677b39918
|
||
:ROAM_REFS: https://www.haskellforall.com/2020/07/the-golden-rule-of-software-quality.html
|
||
:END:
|
||
#+title: Haskell for all: The golden rule of software quality
|
||
|
||
Haskell for all
|
||
Monday, July 27, 2020
|
||
|
||
** The golden rule of software quality
|
||
|
||
This post summarizes a rule of thumb that I commonly cite in software
|
||
quality discussions, so that I can link to my own post to save time.
|
||
I have taken to calling this the “golden rule of software quality” because
|
||
the rule is succinct and generalizable.
|
||
|
||
The golden rule is:
|
||
|
||
#+begin_quote
|
||
Prefer to push fixes upstream instead of working around problems downstream
|
||
#+end_quote
|
||
|
||
…
|
||
and I’ll explain implications of this rule for a few software engineering
|
||
tradeoffs (using examples from the Haskell community and ecosystem).
|
||
|
||
Disclaimer: The golden rule of software quality bears no relationship to
|
||
the golden rule of treating others as you want to be treated.
|
||
|
||
** Third-party dependencies
|
||
Most developers rely on third-party dependencies or tools for their
|
||
projects, but the same developers rarely give thought to fixing or
|
||
improving that same third-party code.
|
||
Instead, they tend to succumb to the bystander effect, meaning that the
|
||
more widely used a project, the more a person assumes that some other
|
||
developer will take care of any problems for them.
|
||
Consequently, these same developers tend to work around problems in widely
|
||
used tools.
|
||
|
||
For example, for the longest time Haskell did not support a “dot” syntax
|
||
for accessing record fields, something that the community worked around
|
||
downstream through a variety of packages (including lens) to simulate an
|
||
approximation of dot syntax within the language.
|
||
This approach had some upsides (accessors were first class), but several
|
||
downsides such as poor type inference, poor error messages, and lack of
|
||
editor support for field completions.
|
||
Only recently did Neil Mitchell and Shayne Fletcher upstream this feature
|
||
directly into the language via the RecordDotSyntax proposal, solving the
|
||
root of the problem.
|
||
|
||
The golden rule of software quality implies that you should prefer to
|
||
directly improve the tools and packages that you depend on (“push fixes
|
||
upstream”) instead of hacking around the problem locally (“working around
|
||
problems downstream”).
|
||
These sorts of upstream improvements can be made directly to:
|
||
|
||
- Your editor / IDE
|
||
- Your command-line shell
|
||
- Programming languages you use
|
||
- Packages that you depend on
|
||
|
||
Note that this is not always possible (especially if upstream is hostile to outside contributions), but don’t give up before at least trying to do so.
|
||
|
||
** Typed APIs
|
||
|
||
Function types can also follow this same precept.
|
||
For example, there are two ways that one can assign a “safe” (total) type
|
||
to the head function for obtaining the first value in a list.
|
||
|
||
The first approach pushes error handling downstream:
|
||
|
||
#+begin_src haskell
|
||
-- Return the first value wrapped in a `Just` if present, `Nothing` otherwise
|
||
head :: [a] -> Maybe a
|
||
#+end_src
|
||
|
||
|
||
… and the second approach pushes the requirements upstream:
|
||
|
||
#+begin_src haskell
|
||
-- Return the first value of a list, which never fails if the list is `NonEmpty`
|
||
head :: NonEmpty a -> a
|
||
#+end_src
|
||
|
||
The golden rule states that you should prefer the latter type signature for
|
||
head (that requires a NonEmpty input) since this type pushes the fix
|
||
upstream by not allowing the user to supply an empty list in the first
|
||
place.
|
||
More generally, if you take this rule to its logical conclusion you end up
|
||
making illegal states unrepresentable.
|
||
|
||
Contrast this with the former type signature for head that works around a
|
||
potentially empty list by returning a Maybe.
|
||
This type promotes catching errors later in the process, which reduces
|
||
quality since we don’t fail as quickly as we should.
|
||
You can improve quality by failing fast at the true upstream root of the
|
||
problem instead of debugging indirect downstream symptoms of the problem.
|
||
|
||
** Social divisions
|
||
|
||
I’m a firm believer in Conway’s Law, which says:
|
||
|
||
Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization’s communication structure.
|
||
|
||
— Melvin E. Conway
|
||
|
||
… which I sometimes paraphrase as “social divisions lead to technical
|
||
divisions”.
|
||
|
||
If social issues are upstream of technical issues, the golden rule implies
|
||
that we should prefer fixing root causes (social friction) instead of
|
||
attempting to mask social disagreements with technical solutions.
|
||
|
||
The classic example of this within the Haskell community is the cabal vs.
|
||
stack divide, which originated out of divisions between FPComplete and
|
||
Cabal contributors (Corrected based on feedback from the Haskell
|
||
subreddit).
|
||
The failure to resolve the upstream friction between the paid and open
|
||
source contributors led to an attempt to work around the problem downstream
|
||
with a technical solution by creating a parallel install tool.
|
||
This in turn fragmented the Haskell community, leading to a poor and
|
||
confusing experience for first-time users.
|
||
|
||
That’s not to imply that the divide in the community could have been
|
||
resolved (maybe the differences between paid contributors and open source
|
||
volunteers were irreconcilable), but the example still illustrates the
|
||
marked impact on quality of failing to fix issues at the source.
|
||
|
||
** Conclusion
|
||
|
||
Carefully note that the golden rule of software quality does not mandate
|
||
that you have to fix problems upstream.
|
||
The rule advises that you should prefer to upstream fixes, all other things
|
||
equal.
|
||
Sometimes other considerations can prevent one from doing so (such as
|
||
limitations on time or money).
|
||
However, when quality is paramount then you should strive to observe the
|
||
rule!
|