1. 11

I was just wondering if people write a spec or documentation before starting to write code for a project? I know designing the whole thing upfront is a bad idea, but at least outlining the purpose by writing the equivalent to man pages seems like a good idea to me (and updating it along side the code as it changes). Have we gone too far in terms of unspecified software to be more ‘agile’?

Feel free to share counter points or horror stories :)

  1.  

  2. 12

    I know designing the whole thing upfront is a bad idea

    Not really. I think it’s generally a good idea. Just don’t get too attached to it. There’s nothing wrong with a little requirements gathering, use case analysis, and general component/data flow/API breakdown before you get too far into writing working code. If you start designing classes and whatnot, then you may want to stop yourself.

    Have we gone too far in terms of unspecified software to be more ‘agile’?

    Probably, but that kind of question falls into the “eternal argument” class.

    And to answer the original question, yes, I always write some kind of spec or docs for projects, even if I have no intention of sharing them.

    1. 3

      requirements gathering, use case analysis, and general component/data flow/API breakdown

      I especially like to do a data flow breakdown. A while ago I discovered FMC diagrams http://www.fmc-modeling.org/ which have a nice and simple way of representing components as active or passive items and their communication patterns. Very nice to work with, not so complicated as UML but very powerful. Also I realized that people could read them fairly well when I used them with colleagues. Really sad that UML does not get any competition to balance the baroque toolbox.

      1. 2

        Does ‘don’t get attached to it’ mean don’t update it? or don’t be afraid to update it as things become more clear.

        I’ve never found much value in the documentation of classes or implementation, but I always find system level explanations useful, things explaining the project rationale e.g. why there are 3 services, what the constraints it is trying to satisfy are, or how to configure the thing.

        1. 4

          Definitely “don’t be afraid to update/change”. Incorrect documentation is worse than no documentation, since newcomers will read the documentation and think the project is working a certain way when it’s really not.

          I think class-level docs are helpful for when you want to abstract out functionality, but I suppose this will probably show itself at higher-level documentation too. An example would be defining a common interface to easily add 3rd party services.

          1. 2

            Yeah, it means that you should expect the design to change. “Don’t get attached to it” refers to the fanciful notion of once you have designed it, that’s enough.

        2. 7

          For small changes I don’t spec because it’s more trouble than it’s worth. If I expect something to take more than a day, though, I write documentation. I’m a strong believer in specifications and documentation as a tool for writing code faster and with fewer bugs. I also think that there are different kinds of documentation and that documentation does more than just explain the “why” and “how”. I tend to write the docs in several rounds:

          Proposal

          A quick text doc outlining what changes need to be made, why, and a very rough idea of what I’m thinking. Purpose is twofold: first, it confirms that I understand what the PM needs and that we’re on the same page. Second, it’s a quick check on other developers that I’m approaching this right. It invites people to say “oh, there’s this important bit of context you need” or “check out PR XYZ” or “here’s a library you don’t know about.” Sometimes that missing context is turns a week project into a couple hours.

          Formal Specification

          I discovered formal specification last September and have been an evangelist ever since. The idea is that you can write a specification that you can feed into a model checker to discover if there are system errors. For example, here’s a TLA+ specification of a crappy bank transfer algorithm:

          variable account = [p \in People |-> 10]
          process transfer \in Transfers
            variable amount \in 1..10, sender \in People, receiver \in People;
          begin
            Check: if account[sender] >= amount then
              Add: account[receiver] := account[receiver] + amount;
              Sub: account[sender] := account[sender] - amount;
            end if;
          end process;
          

          If you specify a “No Overdrafts” invariant (\A p \in People: account[p] >= 0) the TLA+ model checker will successfully find a race condition which overdrafts. That helps you find dangerous bugs in your design before you’ve written any code. And it makes pretty good documentation, too!

          I’ll write a TLA+ spec if the project involves concurrency, multiple systems, or convoluted logic. More than once I’ve scrapped ‘obvious’ designs when the spec surfaced an unfixable invariant violation. Once I have a good design, the spec helps me condense my thought process and understand what I want to do.

          Diagram

          I don’t invest too much into diagramming the new system, but it’s nice to throw ten minutes into a quick flowchart or directed graph. More for visual brainstorming than something to actually follow.

          I will, though, spend time diagramming existing code the project will touch. It’s hard to keep more than a couple of classes in my head at once, much less a dozen, much less a dozen classes and the call graph and any weird observers or triggers or inherited methods that aren’t obvious from the code itself. Having a diagram makes it a lot easier to track everything that’s going on, remember what I need to change, and notice any consequences of the changes I want to make.

          I use Graphviz for diagrams, which is really comprehensive but also has a lot of fiddling and bikeshedding. Mermaid looks like a simpler alternative but I haven’t tried it out yet.

          Technical Reference

          Just a quick English explanation of the formal spec and diagram. I also add quick descriptions of what didn’t work, either because it failed in the spec or didn’t mesh with the diagrams. One thing I’ve been playing with is shortening the link and putting it in code comments, so you get something like this:

          # Part of project XYZ see http://is.gd/godiva 
          foo.bar().baz()
          

          The proposal and the reference are both really quick writes so don’t take much time. Diagramming takes longer, but I don’t count it as adding time to the project. I’d have to understanding the existing code anyway, this just makes me do that before I’ve started adding new code. Also, making a visual in advance means that I can refresh my memory much faster than if I had to reparse everything each time. The formal spec is an extra time investment, but the benefits are so big it often reduces the total project time. Plus it means fewer bugs make it to production, which means fewer 3 AM phone calls :D

          For background, I’m a Ruby on Rails webdev, and the culture is a little, uh, skeptical of up front design. As you can probably tell, I disagree :P

          1. 1

            Thanks for writing this up :)

          2. 5

            Small project - maybe never write spec.

            Medium project - while developing.

            Large project - before

            Docs - depends on customer.

            1. 7

              Funnily, one of the things that annoys me the most are the ‘small’ shell scripts you find in projects under some dir like ./scripts/. They tend to almost never have any documentation, or have a purpose that only makes sense for the developers workflow. I feel like just writing down what the script is supposed to do would make them a lot more useful to everyone as they can’t be a total hack job if you can’t explain what it does.

              1. 4

                Your documentation philosophy seems to mirror mine. Here’s a few scripts from my latest project: 1, 2, 3, 4, 5, 6, 7, 8. Tell me what you think.

                Edit 10 minutes later: For another, more complex, example see my tmux_navigate script for switching between Vim windows alongside Tmux panes. I like my docs to emphasize not the precise rules I’ve written but the scenarios I considered in writing them. This is inspired by Christopher Alexander’s approach to design.

                1. 3

                  I always document my shell scripts because they tend to be the glue that holds everything together, where you want to know more about “why” than “how”.

              2. 5

                Writing is formalizing ideas in a different dimension than programming, and if something feels really handwavy in that description, that’s useful information. I’d expect, say, specific command line arguments or the particulars of a schema / config format / whatever to evolve quickly early on, but the overall goals and fundamental design should have a solid foundation. I find writing helpful for quantifying uncertainty – figuring out where the gaps are, and what experiments might help draw things into focus. That can be useful at any stage.

                1. 5

                  I am terrible at writing specs, and find my creative juices flow best when there is no plan. I write things out as I go.

                  That probably makes me a scrub to some people, but meh!

                  1. 2

                    It’s good to see people have a different opinion out there. Its not clear cut.

                  2. 5

                    Yep. I love a spot of README-driven development (short blog post, 2010, Tom Preston-Werner).

                    1. 3

                      I have often said we should let the user documentation writers go first…..

                      If a system is hard to explain, it’s going to be hard for the users to understand, it it is hard to understand, it will be hard to use and unlikely to be used.

                      I have been looking at crypto currencies and the like recently….

                      … but for a lot of it only the nerdiest of geeks might use it.

                      Why? Because the conceptual load to even understand what they are talking about is huge, let alone start using it.

                      1. 1

                        This post sums up lots of what I have been thinking about and what prompted this question, thanks!

                      2. 4

                        For medium sized to large projects the “happy path” to me is to write specs as early as possible and to document as you go. The trick is to keep writing specs and updating docs as the software evolves.

                        1. 4

                          When I write a library I usually start by writing some code that would use it, pretending the API has already been implemented. I guess that’s like a specification. This is followed by a back-and-forth between actually writing the library to make the client code work and updating the client code based on new constraints, challenges, or ideas I encounter during implementation.

                          1. 3

                            When starting a program, I usually scribble a page or two of ideas, focusing on the interface that the program or library provides. If I don’t do that, I find that I end up including extraneous functionality, or missing large simplifications that come from thinking about what the whole project should do. However, if I do more than a page, I find that ideas get bogged down in thoughts about implementation details.

                            As always, there’s a balance.

                            1. 2

                              Unless your program is trivial or throwaway, you should write down its purpose. That will help explain and clarify it for you, and for others. Keep it to 25 words or less.

                              Note that I’m specifically talking about an executable program, rather than a “library” or “framework”. They have different needs.

                              Whether and how you write functional requirements, is flavored by your approach to representing the logic in your program. Some approaches allow you to model a complex problem domain as a sequence of requirements which map from simple words to code that correspond to tests.

                              However, the currently prevalent approach of having use cases describe logic (typically CRUD) in an application/service/controller layer acting on data concepts, where you discover what should be included through trial and error, is by nature problematic in terms of documentation of requirements.

                              Edit: grammar

                              1. 1

                                FYI, one of the projects I’m working on is design as you go, and the spec is basically ‘what the end of life product did but without the bugs’, we want to ship 3 months.