The company I work for uses Scrum. They consider the User Stories + the code to be everything you need. I struggle with this, but my manager says they don't want to get tied up doing documentation "because it goes out of date". Beside, they are being Agile which "prefers working code over comprehensive documentation".
I am wondering what other companies do to capture this "distilled knowledge". The backend services I rely on are undocumented beside some paltry swagger that leaves much to be desired. The front end has no product-level "spec", if you want to rebuild the thing from scratch. There isn't even a data dictionary, so everyone calls the same thing by different terms (in code, and conversation).
There are just user stories (thousands) and code.
Does anyone have any suggestions on how to fix this?
Documentation is essential. How things work is an important thing to document. Ideally it should be in version control and be generated from the code, because then it's less likely to go out of date. It still has problems (What do you do when the code and the documentation disagree? Which is correct?), but they're not as severe as the problems that arise when there is no documentation at all.
What is less useful is having comprehensive documentation for those things that are yet to exist. Writing a few hundred pages of specification and handing it over to the dev team is waterfall, and it is _this_ that the Agile manifesto signatories were interested in making clear.
I'd fix it with strategic DDD - I'd develop at least a "ubiquitous language" (or a UL): I'd get others to work with me on having clear terminology and making sure that is used consistently both in user stories and in the code base. That's table stakes.
I'd then event storm the contexts I'm working in and start to develop high level documentation.
Even at this point relationships between systems emerge, and you get to draw circles around things and name them (domains, contexts), and the UL gets a bit better. At this point you can start to think about describing some of your services using the UL and the language of domains and contexts.
By that point, people should start to click that this makes life easier - there is less confusion, and you're now all working together to get a shared understand of the design and the point of DDD is that the design and the code match.
The first part (all 100+ pages of it), of the Millet and Tune book on DDD will pay you dividends here.
If that doesn't work, look around for somewhere else to work that understands that software development is often a team sport and is committed to making that happen.
Documentation is essential. How things work is an important thing to
document. Ideally it should be in version control and be generated
from the code, because then it's less likely to go out of date.
My solution to this is old and fairly unpopular, but I stand by it: anything in the codebase that's not obvious to a new maintainer should have a brief, explanatory code comment.Generally, this falls into two categories.
1. Hacks/kludges to get around bugs in hardware, external services, or included libraries. These manifest in code as incomprehensible, ugly bits of code that are difficult to distinguish from code that is simply "sloppy" or uninformed. More importantly, they represent hard-won knowledge. It often takes many programmer-hours to discover that knowledge, and therefore many dollars. Why throw it away? (Tip: include the version of the dependency in the comment, ie)
# work around bug in libfoo 2.3, see blahblahblah.com/issues/libfoo/48987 for info
# should go away once we can upgrade to libfoo 3..
if error_code == 42 reset_buffer()
...so that future programmers (including you) can more easily judge whether the kludge is still needed in the future.2. Business logic. This too is difficult/impossible to discern from looking at code. Often, one's git commit history is sufficient. But there are any number of scenarios where version control history can become divorced from the code, or require a fair bit of git/hg/svn/whatever spelunking to access. And this of course becomes increasingly onerous as a module grows. If there are 200 lines of code in a given module, it is a significant time investment to go git spelunking for the origins of all 200 lines of code. Some concise internal documentation in the form of code comments can save an order of magnitude or two of effort.
It still has problems (What do you do when the code and the
documentation disagree? Which is correct?), but they're not as
severe as the problems that arise when there is no documentation at all.
This is pretty easy to enforce at code review time, prior to merging.In the first place, only a true maniac would intentionally update
# no sales tax in Kerplakistan on Mondays
return nil if country_code==56 and day_of_week==1
...without updating the associated comment. If they do neglect to update it, that's an easy catch at review time.Leaning towards commenting "why" not "what" is another good general rule. "Self-documenting code" with sensible function and variables names and logical flow already cover the "what" fairly well.
# Some countries have sales tax rules dependent on the day of the week
return nil if country_code==KERPLAKISTAN and day_of_week==MONDAY
The exact comment here could probably be more specific (e.g. where do you find these rules), but it also most likely shouldn't repeat the code (and the code should make clear what it represents).But I agree with your statement that there should be a pointer to the business rules somewhere. Otherwise it's difficult to have a meeting with the business side and ask, "Has anything here changed?" I think that's the biggest thing people miss out -- It's not that hard to find the thing in the code if things change. It's super hard to make sure you are on top of all the business requirement changes.
country_code==FIFTY_FIVE and day_of_week==ONE
string url = HTTP + COLON + SLASH + SLASH + WWW + DOT ...
I swear I'm not making this up....> "There is a famously bad comment style: ...
Don't laugh now, wait until you see it in real life."
But in the trade-off in code readability was probably the cause of many other mistakes, so probably ended up further behind.
[NB 30 isn't an exaggeration - I think the vast team who wrote it were paid by the abstraction or something].
return nil if country_code==KERPLAKISTAN and day_of_week==MONDAY
Hmm.. Well that's strange. I don't have a background in Kerplakistan monetary policy so I don't know why we aren't assessing sales tax on Monday. Perhaps Kerplakistan is a special case. Is that being handled somewhere downstream? Then 1-2 hours later, after shuffling through source and eventually just Googling Kerplakistan sales taxes, you discover what someone found out 2 years ago when they wrote that line. Now you resolve the ticket and move on with your day but you just wasted a couple man-hours on a non-issue that could have been resolved instantly from a code comment.Comments are as much for the next guy as they are for you.
Code smell doesn't mean you should never do it, just that often there's a better way.
I worked on an enterprisey line of business app that assigned sales leads to salespeople.
The algorithm to do this was a multi-step process that was (1) rather complex (2) constantly being tweaked (3) very successful (4) contained a number of weighting factors that were utterly arbitrary even to veterans of this app.
It was full of many `if country_code==KERPLAKISTAN && day_of_week==MONDAY` -style weighting factors. Each represented some hard-won experience And when I say "hard-won" I mean "expensive" -- generating leads is expensive business.
We had a strong culture of informative commit messages, but this file had hundreds if not thousands of commits over the years.
It was the kind of code that resisted serious refactoring or a more streamlined design because it was a recipient of frequent change requests.
A few human-readable comments here and there went a loooong way toward taming the insanity and allowing that module to be worked on by developers besides the original author.
Knowing the why for many of these rules made it much easier to work with, and also allowed developers to be educated about the business itself.
I'm not at all convinced that this is unpopular, but I think it's a whole lot harder than you're letting on. Unless you have a constant stream of new people coming in and you can convince them to give honest feedback, you don't actually know what's not obvious.
return nil if country_code==KERPLAKISTAN and day_of_week==MONDAY
Then you don't need comments and the sync problem goes away?Is this a quick thing somebody hacked in for a special, one-off, tax-free month in Kerplakistan as the country celebrates the birth of a princess?
Is this a permanent thing? Will there eventually be more weirdo tax rules for this country? Will there be others for other countries?
Knowing the "why" would help a developer understand the business, and reason about how best to work with this bit of code... should we just leave this ugly little special case in place? Should we have a more robust, extracted tax code module, etc.?
Commit messages help to accomplish this too, and can offer richer context than inline comments. Each has their place. Sifting through hundreds of commit messages in a frequently-updated module is not a great way to learn about the current state of the module, as the majority of those commit messages may well be utterly stale.
Ultimately the cost of having some concise inline comments is rather low, and the potential payoff is very large.
Remember that the longer term goal (besides the success of the business) of software is to have your developers gain institutional knowledge so that they can make more informed engineering decisions in the future.
I agree with this 100%. However, to be useful it needs to hit the right level of crudity. For most projects, a short (<10 pages) description of goals, design principles, architecture and an overview of interfaces is sufficient.
It is best when this exists as a standalone document which is a required reading for any new developer. After this they can look at module descriptions, function docs, code, etc. and understand how to make sense of it and how to add their code without breaking general principles of the project.
> Ideally it should be in version control and be generated from the code, because then it's less likely to go out of date.
With this, I have some beef. In my experience the best documentation is the one that complements the code. Usually this means a short description by a human that explains what this chunk of code does and assumptions or limitations (e.g., "tested only for points A and B in troposphere") and IME most useful information is not derivable automatically. Auto-generated docs are very useful, but cannot replace clean explanations written by a human. My 2c.
"Documentation" that is nothing more than the interface definitions in HTML for is worse than useless. I can get all of that from just reading the code.
These could be just one document if the project is small enough.
Interestingly, this has been a big point of discussion in the Dota 2 playerbase. Dota 2 is one of the most complex games ever created and it rapidly changes on the order of days or weeks. At one point, the in-game descriptions of spells were months or years out of date because they were being updated manually. After much hue and cry from the community, the developers finally made the tooltips get generated from the same code that determined the spells' effects. Things are a bit better now.
There is still a quite a bit of ways to go though, in terms of generating documentation for all the other mechanics in the game, which are crucial for gaining competency in the game, but which are only available due to third-party community efforts (often via people reading the game's codebase to understand subtleties), instead of being available inside the game.
Not always - when you want to document the requirements (in whatever format), having them be separate from the code is often a plus. The code might implement the requirements incorrectly, so being able to recognise that is important.
I find this very similar to writing tests that are separate from your implementation. In fact, Cucumber/BDD tests try to make product requirements executable to validate the software has been written correctly to meet the requirements.
I never got documentation about the thought processes, the iterations, the design meeting, the considerations, etc. Which is way, way more important to understanding a system in context than knowing "convertLinear" takes 2 unsigned ints.
That doesn't sound too bad from a dev point of view, better than the opposite - half arsed specifications with no thought given to the important details. Though I can imagine a lot depends on what exactly you are trying to build.
> Ideally it should be in version control and be generated from the code ..
May I ask if you have suggestions for tooling to capture the high level documentation. We use javadoc a little, but it seems best for lower level reference. Also for diagrams, like sequence diagram and/or state machines, how do you capture this?
Thanks.
Or better yet: generate your state machines from same format you would use to generate visual representation.
Just build a product specification for how the product works (which is useful documentation), not how the product will work (which is waterfall).
We're experimenting with this a little, and I'm getting into document-driven development a little: if the product spec is in markdown, why not create a pull request on it as part of your story/project planning that shows the changes that would happen as a consequence of your work. Once the story is done, you can merge the pull request, even. We're not quite there with this yet, but I'm optimistic.
Putting design assets into your repo is also acceptable, and also paying time and attention to commit messages can be really, really helpful. I love this talk, for example: https://brightonruby.com/2018/a-branch-in-time-tekin-suleyma...
I've come across the "documentation becomes quickly outdated" argument a lot, but nobody has ever been able to suggest a good alternative. The best I've found is to write design logs for proposed changes (which you then let other team members/stakeholders can review/comment on before it gets implemented) and decision logs for any decisions that are made. This way, them going out of date is expected and ok, as they become a history of ideas and decisions with their context and outcomes laid out. You don't necessarily have a snapshot of "the system right now" but you have a log of all the ideas and decisions that lead up to the current system.
Me too, but I still feel that saying "documentation quickly becomes outdated" and refusing to write any, is not that different from saying "software quickly becomes full of bugs" and refusing to write unit tests. Yes, if you believe that something is doomed, and therefore you refuse to even try, it becomes a self-fulfilling prophecy.
Yes, documentation quickly becomes outdated, if no one updates it. Duh. If a person creates/modifies a part of code, they should also create/modify the corresponding documentation accordingly. (And the person reviewing the code should also review the docs.) If you don't do it, then yes, obviously, the documentation becomes outdated. Did you expect it to update magically by itself?
If you believe that documentation is useless in principle, go ahead and don't write it. Then you won't have to maintain it. Also, make sure to include memory tests to your interview process. If you believe that documentation is useful, write it, and maintain it. But if you have a documentation that you never update, you get the worst of both worlds.
At the very least, the document should capture high-level (again this is relative term) design, possibly an architecture diagram of major interacting functional units. The success measure should be the relative ability to build a mental model of the system by looking at this document for any newbie.
That design document would be a start, and most likely not "quickly outdated".
My personal beef with the agile camp is precisely this: when they let go of documentation, they don't do the design doc as well, and all that remains of the system is thousands of incoherent stories and huge amount of code.
If you diverge too far from the original design, you should probably have a rationale as to why, that gets reviewed by others: another design log and decision log.
These documents don't need to be long either, just a couple of sentences for each of context, what you propose, impact on other teams or systems, decision made may be enough for smaller things (so a paragraph or two) and for larger changes, you probably need the detail for everyone to really understand what, why and its impact. The alternative is to do these things blind.
> when they let go of documentation, they don't do the design doc as well, and all that remains of the system is thousands of incoherent stories and huge amount of code.
Absolutely agreed.
Another thing that helps is to write good commit messages giving the business context for a change. When code is reviewed, the commit messages should be reviewed as well. If they don't agree then that's a problem.
Not to be rude, but yes: switch employers. This is not something you can fix on the employee level, it is a management issue.
It might be a team culture or company culture issue, and even radical changes in the management are not enough to fix it.
Agility requires a stable foundation. And a lot of places forget that.
Then they are Doing It Wrong™. Note that there's nothing in the Agile Manifesto OR the Scrum Guide that says "don't write documentation." The closest you get is in the AM where it says "We have come to value ... Working software over comprehensive documentation". But note that immediately after that it says "That is, while there is value in the items on the right, we value the items on the left more." IOW, the Agile Manifesto explicitly endorses the value of documentation!
Remember this the next time somebody tries to tell you that "we don't do documentation because we're Agile." Anybody running that line is Full Of Shit™.
Have a product wiki (e.g. MediaWiki).
Have documentation in source code that compiles to HTML code, which can be linked to/from the product wiki (e.g. JavaDoc in Java, Natural Docs for languages that do not directly support compilable documentation). Make building and publishing this documentation a part of the continuous integration.
When you have this, make it a part of code reviews to ask "where is this documented?" for those kinds of things that are easy to remember today, but no one will remember it a few months later. In other words, make it a "code+doc review".
(Don't be dogmatic about whether the information should go to code documentation, unit test documentation, or wiki. Use common sense. If it only related to one method, it's probably the code; if it related to a use case, it's probably the unit test that verifies that use case; if it is a general topic that has an impact on many parts of the program, it probably deserves a separate wiki page.)
Are you referring to something like Knuth's Literate Programming (en.m.wikipedia.org/wiki/Literate_programming)? As a non-professional who's learning to develop on the side, something that follows more of a natural language approach appeals to me, as sometimes I have a few months between working on my project, and comments on my source code help me not to forget why I do certain things in the code. However, I'm not doing Literate Programming, just python with comments.
I have never tried the Literal Programming, so perhaps I am out of my depth here, but I strongly suspect it only works after one has already mastered the usual ways of programming. That you do not have to structure the code qua code, because you can already do it in your head. But it's hard to imagine what one has never done before.
For example, if you never tried programming the usual way, how do you know when and why to put "Header files to include" in your Literal code? It's only because you can imagine the constructed code, you know where the header files go in the result, so you know where to place them in the Literal version. Otherwise, it would look quite arbitrarily.
I don't know about documentation in Python, but the JavaDoc (and Natural Docs) work like this: You put comments to classes and methods, or packages (and files), along with the code. So you can read them and write them while you are looking at the code. But then you run a "documentation compiler" that extracts the comments and builds a separate HTML website out of them. Here you can browse and read about what the individual classes and methods do. The idea is to make this a part of the continuous integration, so that whenever you update the source code and the related comment, the HTML website also gets updated.
Java supports this out of the box. When you install the Java compiler, you also install the Java documentation compiler. When you read the official documentation to the standard Java classes, those were made using exactly the same tools you are encouraged to use.
I don't know whether Python has something like this. If yes, go ahead and use it. If not, look at Natural Docs -- it is a system to provide this functionality to languages that do not support it out of the box. Just try it: document a part of your existing project, compile the docs, and see whether you can imagine any value in reading that.
This is funny because “working code” might just mean that it doesn’t crash. But does it actually do what it’s supposed to do or does it reliably deliver the wrong results? How would you know without documentation?
The software in the Therac didn’t crash, it quite reliably killed people with its “working code”.
So I think "working code/application/program" is when it does what it is supposed to do. Including not crashing.
And the point of the comment you're replying to is to ask what is "what it is supposed to do". How do you know what the answer to that question is, without documentation or a specification? And if you try to rely on just verbal communication, in a group of people probably larger than about 1, they're going to have different ideas about what the software is supposed to do.
Some of the most challenging problems I've encountered have been looking at code that does something. What it does is clear enough from the code. But why it does it, or should it do that, that is much harder to answer, particularly if the person who wrote it has left the company or it's been >6 months and they just don't remember.
I might also recommend creating user stories for non-feature development like infrastructure and tech debt paydown (if you don't already). That way, all of the value flow is captured in one place and you're not just leading managers to see new features only.
Second, in addition to the user stories I'd advocate for strong background information about the context of the story as well as detailed acceptance criteria if you don't have that in place already.
2) In my experience, this basically never happens.
Your comment encapsulates a lot of what I have come to call "Scrumbutt." It's Scrum, but. And while I have no idea if it's intended on your part, the sentiment is a fantastic way for a Scrum consultant--only some shade thrown; I've been a "DevOps consultant" before, after all--to come in and pull from deep in their Scrumbutt something to the effect of "you're doing it wrong, Scrum has not failed, you have failed Scrum."
Within epsilon of nobody does Scrum "as prescribed"--because the amount of responsibility that must be undertaken at all levels is virtually impossible to get full buy-in on--and as such the boil on our collective behind that it is persists because criticism is immediately bedeviled by Scotsmen of unknown provenance.
People might be interested in what Scrum is. I know I am. That’s why I pointed out the error. It was a shock to me to learn I wasn’t doing anything close.
Readers can do with the info what they want.
I’m not sure if I can say the same of your comment. You seem to be trying to make me feel bad for commenting? Or accusing me of hawking pointless info for consulting fees? I really can’t tell.
If you have sufficiently detailed user stories, they can be.
Back to the question - what do you do about poor knowledge transfer in a project? I think a moderate de-emphasis on thinking of the user story text and the additional info like acceptance criteria etc. as self-sufficient documentation and adding more emphasis on that close relationship between developer, user, and maybe a tester, can help fill in big knowledge gaps.
I think about that whenever I get frustrated about a vague spec or lack of details. It's the job!
I hope he meant separating out the ambiguity rather than concentrating it. :)
"...the designers job is not to pass along "the design" but to pass along "the theories" driving the design. Knowledge of the theory is tacit in owning..."
Well said. Thank you!
I know as a software developer you don't want to do that. More fun refactoring code than dealing with management. More fun writing that piece of SQL than sitting in a meeting. Easier to whine about missing specifications than to understand the big picture.
Once I stepped back from coding and looked at the software from a birds eye view, I had actually a much easier time programming features than before. More knowledge, less writing code.
Being a part of the early decision making processes has been a challenge for me as a remote employee. In larger companies, there are lots of meetings, discussions, and decisions that happen before anyone talks to the engineering staff is brought in. But, by basically being nice, asking questions, and really getting involved, I've been able to "weasel" my way into some of these discussions.
Once you get involved early on, there's so much more clarity around the one liner "requests" that often get farmed out.
communicationChannels = nrOfTeams(nrOfTeams-1)/2
More people should read The Mythical Man-month
Managers are very unhappy when I tell them of all the knowledge I've developed.
I've experienced more issues caused by management passing around tasks between teams and never paying attention to knowledge and knowledge transfer.
What's amazing, is that in over 18 years as a software engineer, I've seen this so many times. Teams will function well, then the institution tries to change. Often they will try to open up the "innovation" by throwing money at R&D, basically trying to add bodies in order to grow. Then you have tons of teams, and communication becomes very challenging, so then they grow some kind of "task management" layer. Management that never understands who actually _knows_ something, just tracks how much "theoretical bandwidth" they have and a wishlist of features to create. And then the crapware really starts flowing. And then I get bored and move on to the next place.