1. 71
  1.  

  2. 54

    GoF is not a recipe book for building great software. You can’t use it for designing software that doesn’t exist, or you could, but that would be silly.

    It is a catalogue, a taxonomy like that of von L’innéLinné, it gives names and categories to observations. It’s something you can refer to when you want to identify common abstractions – patterns – when trying to understand software that exists. It’s not a spellbook, it’s a monster manual.

    1. 34

      It’s not a spellbook, it’s a monster manual.

      This is a really nice way to phrase it, thanks.

      1. 5

        As a Swede, I’m obligated to let you know there’s no apostrophe in von Linné’s name…

        I did learn today that his family name was Linnaeus, I thought it was a Latinization after the fact.

        1. 5

          Ha. Uh. That’s curious. I’m from the other side of the Baltic and I knew that as well. Turns out the culprit is my multilingual autocorrect, which has French in it, it corrected Linné into L’inné which means “the innate”.

          Commenting or writing any text on mobile is really painful. Even markdown links are hard!

          1. 5

            I really dislike Markdown links on mobile, mostly because () [] are buried on 2 sub levels of the keyboard l…

      2. 18

        Maybe the word “architecture” means a different thing to me, but when I read the title I thought “But ‘Clear and Simple Design’ is an architecture!” Nonetheless I mostly agree with content of the article.

        My go-to phrasing to junior engineers who seem inclined toward being a Pattern Taxonomist is roughly:

        Patterns do not come from a buffet, having been prepared by someone else.
        Patterns are emergent in the course of solving a problem, and are a communication tool.

        Patterns are jargon, but jargon is itself an emergent property of any community or team over time. It is not a question of whether you will use jargon. Instead, it is a matter of continual practice to ensure that jargon’s use as a communication tool is not eclipsed by other uses. I am not a linguist, but I would not be surprised to find that both the emergence of jargon, and this tendency toward inversion, are well-studied.

        Most commonly, I have seen this inversion of the value of jargon (or a soft-circled collection of jargon) when it begins to be used in a manner that limits discussion, rather than being used for its explanatory power.

        1. 9

          Most commonly, I have seen this inversion of the value of jargon (or a soft-circled collection of jargon) when it begins to be used in a manner that limits discussion, rather than being used for its explanatory power.

          So well phrased. This was actually one of the reasons that triggered writing this article. We had a distributed systems expert join the team, who was also a long-time architect. A junior person invited him to review his design proposal on a small subsystem. This experienced engineer kept correcting the junior engineer on how he’s not naming things correctly and mis-using terms. The design was fine and the tradeoffs were good and there was no discussion about anything needing changes there, but the junior engineer came out devastated. He stopped working on this initiative, privately admitting that he feels he’s not experienced enough to design anything this complex and first needs to read books and learn how it’s done “properly”.

          This person had similar impact on other teams, junior members all becoming dis-engaged from architecture discussions. After we figured out this pattern, we pulled this experienced engineer aside and had a heart to heart on using jargon as a means to prove your smart, opposed to making design accessible to everyone and using it to explain things.

          I see the pattern of engineers with all background commenting and asking questions on design documents that are simple to read. But ones that are limiting due to jargon that’s not explained in the scope of the document get far less input.

          1. 5

            but when I read the title I thought “But ‘Clear and Simple Design’ is an architecture!”

            Same here. But go on any “software design” interview in most tech companies and you’ll be expected to suck ornate flying castles out of your ass. Saying you’re not going to complicate the design until you see actual logs telling where it’s failing will just land you a silent no-pass.

            1. 4

              “But ‘Clear and Simple Design’ is an architecture!”

              It’s the desired goal of software architecture, more like.

              Like how “Be Good” isn’t a philosophy, it’s the desired end goal of moral philosophy, which attempts to define “good” and then tries to figure out how to be good. Just jumping to the desired end goal isn’t very enlightening.

            2. 6

              The solution to all our problems is to build programming languages that model hierarchical state-machines / communicating state-machines.

              Turing completeness is a red herring, it’s all about Petri Nets.

              Please disagree with me :)

              Edit: A lot of his post boils down to good team communication, not getting invested in “your” idea, making sure that everyone has synchronized understanding etc. These are necessary but not sufficient, architecture is still a thing you can do poorly even if you do it together.

              1. 3

                Turing completeness is a red herring, it’s all about Petri Nets.

                Petri nets are pretty limited unless you add inhibitors, though, and that makes them Turing complete.

                1. 1

                  Depends on the mapping you use, the structure captures all relevant process theories.

                  1. 1

                    “Put the widget in bin A unless there are already widgets in bin B, in which case put them in bin B.”

                    I don’t think that’s modelable without inhibitors?

                    1. 1

                      You would have to have proof from context that the program never violates this behavior

                      1. 2

                        I’m sorry, I’m not quite sure I understand what you’re going for. We’re trying to write a specification of the system using Petri nets, right? I’m saying that, without adding inhibitor arcs, specifying a system with the above property is not possible with Petri nets. It doesn’t matter if the program, in practice, is correct or not, because the problem is whether or not we can specify what correct “means”.

                        1. 2

                          You have three places, A, B, C and two transitions T1 and T2. T1 has C and B as inputs (1 each) and outputs 2 to B, T2 has C as input and A as output.

                          In a stochastic Petri net you have no control over whether T1 or T2 fires if both conditions are fulfilled, but in a computational setting you can decide which fires. Then the behavior you asked for is just to prefer T1 over T2.

                          This meta-level conditional logic is what people study with ExPetri and broadcast nets.

                2. 2

                  You’d be amazing how well Sum/Product types model state machines.

                  1. 2

                    No I wouldn’t but yes it’s true :)

                  2. 1

                    But the problem is not the computers. It’s the people writing the code! :)

                    1. 3

                      So give them a better model to think in and watch as we get stuck on much harder problems all of a sudden.

                    2. 0

                      So which languages allow this easily?

                      Erlang is the only one that comes to mind and I’ve never written or seen Erlang code.

                      I think RxJS also allows this type of thinking.

                      1. 2

                        I’ve never written or seen Erlang code

                        That only takes an afternoon to fix, and I’m sure you learn something, one way or another…

                        1. 1

                          Most languages that have pattern matching are really good at it. Any ML derived language, Rust, and a few others come to mind. It’s even better if they also have enumerated types.

                          1. 1

                            And tail recursion!

                      2. 3

                        In software engineering we have this recurring pattern of rejecting “complex” things, and replacing them with “simple” ones, until it turns out the simple approach doesn’t handle edge cases, has flaws, and after all the shortcomings are fixed, we end up with a complex solution again. There’s nothing wrong with doing it this way (Gall’s Law: “A complex system that works is invariably found to have evolved from a simple system that worked”), but you have to realize you’re not getting rid of complexity with a silver bullet, you’re merely starting from scratch.

                        Clear design is software architecture. If your design is uncelar because of “too much architecture” that’s overengineering, YAGNI and just plain old poor design.

                        As your requirements grow, your simple architecture will either become a ball of mud, or you’ll find yourself adding the patterns you dread. You can laugh at an AdapterFactory, but once you get a requirement to support several subsystems swappable at runtime, that’s what you’re going to write.

                        The benefit of having names for these patterns is clarity. Instead of winging it, you can plan it. You can communicate to new members how things are put together using a shared vocabulary.

                        1. 2

                          In software engineering we have this recurring pattern of rejecting “complex” things, and replacing them with “simple” ones, until it turns out the simple approach doesn’t handle edge cases, has flaws, and after all the shortcomings are fixed, we end up with a complex solution again.

                          That’s the good outcome. The bad outcome is replacing a working complex system with a simple one which doesn’t have all the functionality, and then declaring that nobody needs to do anything your system can’t do.

                          As your requirements grow, your simple architecture will either become a ball of mud, or you’ll find yourself adding the patterns you dread.

                          Indeed. The worst designs are from people who think simplicity and extensibility are enemies. A good simple design allows more components to be added easily, and can be turned into a good complex design as the environment dictates; this indicates a clarity of vision beyond just making something simple.

                        2. 3

                          Have you considered using formal methods? It’s fast, it’s like drawing diagrams, except you can test the diagram itself for bugs, too.

                          1. 3

                            I haven’t met a formal method that was less work than writing the software and testing it.

                            1. 4

                              There was a great talk at strangeloop about this! Author found, via a bit of modelling, that a year of development and testing on a nearly complete API had to be thrown out. Another formal methods talk at the same conf was similar, a few days of modelling got her to an architecture that an audience member later told her took them months to iteratively discover.

                              I’ve had similar success, with modelling catching multiple serious, subtle bugs in several different systems. And even on smaller systems, you can catch bugs in half an hour that world-class testers can’t find, even knowing there’s a bug.

                              1. 2

                                My favorite example of how you can sometimes find deep bugs with low effort is Amazon’s paper (pdf). First, they note code for services as complex as theirs has way too much detail to review its inherent design. TLA+ let them specific just what they needed. Second, the model checker started catching bugs their reviews and testing missed. My favorite “contained 35 high-level steps.” I’m very interested in anyone’s testing proposal that will quickly find bugs with 35 steps into one or more programs.

                                Then, there’s all the static analyzers with low false positives. They are using automated application of formal methods. They’re finding piles of bugs out there with some doing it ultra-fast. CompSci groups also typically found bugs in popular F/OSS for each tool they created. The performance-oriented ones like Saturn can run checks over millions of lines of code. A programmer writing tests couldn’t hope to keep up.

                                I still see formal methods and testing as complementary, though. Also, I think we should automate testing much as possible.

                              2. 1

                                It’s fast, it’s like drawing diagrams

                                Except it’s not and I believe the main goal of drawing diagram is not to find bugs (How do you even define a bug in software architecture anyway), but to document a problem, its context and its solution. In my experience, this usually involve many quick iteration and brainstorming. You won’t get any better than a whiteboard and oral discussion to go through simple architecture design.

                                There might be benefits to format methods, but selling it as fast and just like drawing diagrams is dishonest.

                                1. 3
                                  1. It’s not “dishonest” because I genuinely believe it. It’d be “dishonest” if I thought otherwise but was intentionally lying.
                                  2. Formal methods has a lot of variety. I’ve written decision diagrams and state machines on a whiteboard before, which clarified a lot of design decisions.
                                  3. OP is also documenting things and doing a writeup to share around with the company. It’s not just whiteboard and oral discussion. I agree that the FMs I’m most interested in are too heavyweight to replace whiteboarding, but they’re also not too heavyweight to replace informal English documentation.

                                  How do you even define a bug in software architecture anyway

                                  If the proposed solution doesn’t solve the problem or satisfy necessary constraints.

                                  1. 1

                                    How do you even define a bug in software architecture anyway

                                    You define what correctness means, you define the architecture, and you check it against the definition of correctness. Many tools look for logical inconsistencies, too. Some tools look like a programming language with annotations like contracts that feed into checkers of some sort. Some can look like diagrams showing control flow or order of things. There’s formal notations that check for order violations. The information-flow security tools might scan the combo of variables and control flow to look for leaks.

                                    Quite a few things you can do that’s easy to represent on a whiteboard. You could even let people draw with compatible notations on a whiteboard while something kept it in sync with software on a computer. The humans do what they’re good at. The computer does what it’s good at. If the method has code generation, you get an executable prototype to prod at, too.