Practices of an Agile Developer
by Venkat Subramaniam and Andy Hunt
I received this book as a gift. The title is pretty self-explanatory of what it's about. All in all, a good book, written in a to-the-point manner. The ideas presented are not path-breaking and will be familiar to anyone who's done a decent amount of reading about Agile topics. However, finding all the practices collected in one place and in a logical flow of thought is always handy. Plus, the "Keeping Your Balance" section at the end of each chapter is a definite value-add as it shows how to not underdo or more importantly overdo a practice in real-world situations.
I'll cover my findings of the book here but please note that this page is simply meant to record my thoughts and footnotes, not to plagiarize!
I strongly recommend that you buy this book and read it in detail. It's not that expensive!
Final thought: As the title mentions, it is mainly for developers. The QA side of things is not covered. The authors will do well to write another book/article about the QA's role in an Agile environment to come full circle.
Chapter 1: Agile Software Development
Overview of Agile, an Agile toolkit
My notes:
- An Agile Toolkit should contain a wiki, a version control system, a unit testing framework, and build automation.
- One can do too much of a good thing or ignore it completely; keep a balance when following Agile practices.
My thoughts:
A nice intro, especially the comparison of Agile with surfing vis-à-vis the proverbial road.
Chapter 2: Beginning Agility
My notes:
- Work for outcome. Don't play the blame game. Focus on finding solutions when things go wrong. Collective responsibility.
- Quick fixes become quicksand. Understand design/code before modifying it. Don't code in isolation - review others' code at a high level. Writing unit tests help keep code layered. Refactor messy code.
- Criticize ideas, not people. Avoid negative comments. Set deadlines for decisions. Discuss pros and cons. Use a mediator. Once a decision is made, cooperate no matter whose idea it was.
- Damn the torpedoes, go ahead! Show courage and honesty. Do what's needed. Do not cover up issues. Find and propose solutions.
My thoughts:
Nice suggestions. I like the focus on the mind-set change rather than step-by-step instructions. This is important at the outset.
Chapter 3: Feeding Agility
My notes:
- Keep up with change. Learn iteratively and incrementally by setting some time aside for it every day. The Web, local user groups, workshops, conferences, and books are good resources.
- Invest in your team. Have regular "brown bag sessions" to discuss new technologies, tools, techniques, etc that may interest the team.
- Know when to unlearn. Many concepts from prior experience may be outdated. Try to adapt them within context if beneficial. Unlearn whatever holds you back.
- Question until you understand. Keep asking why. Don't accept things at face value until you reach the root cause.
- Feel the rhythm. Maintain repeatable intervals for recurring tasks like meetings, code reviews, etc. Keep the iteration length the same. Timebox. But don't burn out.
Chapter 4: Delivering What Users Want
My notes:
- Let customers make decisions. Decide what not to decide. If a choice affects business value, the customer should decide.
- Let design guide, not dictate. Two levels of design: strategic & tactical. Do high-level strategic design at the outset (don't directly jump to coding!). Do low-level tactical design iteratively.
- Justify technology use. No resume-driven design. Find problems first and then technologies to solve them, not vice-versa. Consider factors like getting tied to a technology, maintenance costs, etc. Don't reinvent the wheel. The less code you write, the less you maintain.
- Keep it releasable. Checked-in code is always ready. Workflow: run local tests, check out latest code and test against that, check in your code. If a major upheaval needs lengthy system downtime, consider branching of code.
- Integrate early, integrate often. At least once a day, but should be more often.
- Automate deployment early. Automatic installation helps bring out related issues early on. It also saves time and manual effort.
- Get frequent feedback using demos. Select few features for an iteration and demo them at the end. Make sure the customer knows it is a demo of that feature subset only; the application is a work in progress. Demo stable functionality only.
- Use short iterations, release in increments. Many iterations (1-4 weeks) can go into one increment (1-6 months). Each increment gives a usable product, each iteration may not.
- Fixed prices are broken promises. Possible solutions: good estimates based on experience, or fixed bid per iteration and then a go-no-go decision after every iteration with ongoing SOWs.
Chapter 5: Agile Feedback
Discusses feedback sources beyond those mentioned in Chapter 4
My notes:
- Put angels on your shoulders. These are unit tests. Once an initial effort is made on them, they bring benefits: instant feedback if modified code breaks something, code robustness as you consider different test cases and how your code will behave in those, design aid, confidence boosting, and so on.
- Use it before you build it. Use your APIs yourself before providing them to others. Test Driven Development. Can lead to simple designs that work, instead of unnecessarily complex ones.
- Different makes a difference. Test your code on different machines, setups, etc, which you claim to support. Automatic deployment and continuous integration help in this. If problems exist, they'll be uncovered early.
- Automate acceptance testing. Users should be involved in this.
- Measure real progress. Timesheets are normally for payroll accounting, not for measuring work progress in projects. Keep track of how long your tasks really take and estimate better. Use backlogs to help measure progress.
- Listen to users. Don't laugh off their concerns. There is no stupid user. But there are stupid, arrogant developers.
Chapter 6: Agile Coding
My notes:
- Program intently and expressively. Code will be read many, many more times than it is written. Use language features to be expressive. Use enums, avoid bit operators where not needed, method & parameter names should convey intent, exceptions should convey what can go wrong, etc. Write code to be clear, not clever.
- Communicate in code. Keeping documentation separate from code violates DRY (Don't Repeat Yourself). Two ways to document code: the code itself and comments in code. Comment only where necessary, such as to give class or method overview (purpose, pre-conditions, post-conditions, exceptions). Use utilities like javadoc and ndoc. Comment why, not what.
- Actively evaluate trade-offs. Consider performance, convenience, elegance, productivity, cost, and time to market. If performance is adequate, focus on another factor, and so on. Let the customer decide the trade offs.
- Code in increments. Don't code for hours at a stretch until you're completely done. Write code in short edit-build-test cycles. Pausing and zooming out from time to time keeps you on track. You end up with smaller methods, cohesive classes, and better structured code. Refactor continuously.
- Keep it simple. Simple is not simplistic. Don't overdesign or overcomplicate your code but keep it adequate. Elegance is easy to understand but harder to create.
- Write cohesive code. Keep classes focused and components small. Bugs are easy to track down, and code is easy to modify.
- Tell, don't ask. The caller should tell the called object what to do and then stick to its own job. The caller should not ask for information from the called object and then take decisions to change the state of the called object.
- Substitute by contract. Liskov's Substitution Principle (LSP): Any derived class object must be substitutable wherever a base class object is used, without the need for the user to know the difference. Choose wisely between inheritance and delegation.
My thoughts:
Mostly common sense (wrt good programming/design practices). But alas, common sense remains only common knowledge, and not followed -- laziness or carelessness take priority. The above suggestions should be practised.
Chapter 7: Agile Debugging
My notes:
- Keep a solutions log. Helps when you encounter similar problems later. You should include: problem date, short description of problem, detailed description of solution, references to URLs that helped, any related code segments, settings, snapshots, etc. Keep it light; you don't need publication quality.
- Warnings are really errors. Treat them so, else they'll come back to bite you! Eg: "Are you using = instead of == in a conditional expression?" Use IDE or compiler settings to treat warnings as errors right from outset of the project.
- Attack problems in isolation. Separate a problem area from its surroundings when working on it.
- Report all exceptions. Handle or propagate all exceptions, don't suppress them with empty exception handlers. Who is responsible for handling an exception is part of design.
- Provide useful error messages. Give as much supporting detail as possible to make life of support staff easy but don't bury the user with it. Give a high-level meaningful message with a provision, such as a link, to get further details of the error (such as line number) when desired. Error types: program defects, environmental problems, user error.
Chapter 8: Agile Collaboration
My notes:
- Schedule regular face time. Have short regular Stand-up meetings (at least twice a week of max half hour) where the team members one by one answer within 2 mins: "What did I achieve yesterday?", "What am I planning to do today?", "What's in my way?" If something needs in-depth discussion, request a follow-up meeting among those directly involved. Stand-ups are for concrete progress reports but not low-level details. Hold it early morn but after coffee & email checking. Start promptly. Non-team members like business owners can attend but not participate. Advantages: day starts with focus, developers can actively seek help, leads/managers see which areas face problems & need additional hands, everyone's aware of what's happening in the project overall, people get motivated looking at others' progress.
- Architects must write code. Design is specific to the problem and understanding of problem evolves over time during implementation. An architect directly helps with strategic design but must remain involved after that. He should mentor the leads/developers to themselves come up with tactical design as the project progresses. Don't design in isolation.
- Practise collective ownership. Code should not exclusively belong to any one developer. Any team member should be able to fix any code. Rotate developers across different modules/tasks of the system. Advantages: overall knowledge and experience of entire team increases; attrition doesn't result in knowledge loss; knowing others will work on your code, you'll be more disciplined; code quality improves. Caution: someone may be skilled in a particular area, so retain him as the "expert" while exposing him to the rest of the system; collective ownership doesn't mean hack away wherever you want; be wary of those modules where inexperience or less exposure to the domain may be dangerous.
- Be a mentor. Share knowledge; you'll learn in the process. It'll motivate others and enrich the team. Pair programming is an effective mentoring platform.
- Allow people to figure it out. Mentoring doesn't mean spoon-feeding. Give helpful directions and let people come up with solutions/ideas themselves. They'll learn more in the process and may come up with something you might learn from too.
- Share code only when ready. Check in frequently but never check in half-done work.
- Review code. Best way to locate and solve 80% of problems. Recommended ways: the pick-up game (when code is completed, compiled and tested, before checking in, get it reviewed by another developer, but not the same one who'd reviewed your work the last time); pair programming (work in pairs where one developer codes while other continuously reviews from behind, but roles are interchanged from time to time... like long-distance driving). Things to look for: readability, obvious errors, possible ripple effects, code duplication, possible refactorings. Review all code. Different coding style than yours doesn't mean bad code. Have a follow-up meeting to see what was done about the code-review suggestions.
- Keep others informed. Don't wait for managers/customers to ask for status report every now and then. Maintain an "information radiator" such as a wall poster, a wiki, or a blog where you can actively publish status, designs, new ideas, etc. Advantages: you eliminate nasty surprises; the manager/customer knows about the progress/blockages; if something is holding you back, help can be offered, task may be pushed to another iteration, customer may decide to replace this task with another critical one for current iteration, etc. Caution: don't spend more time maintaining the information radiator and less time on actual work!
My thoughts:
The best chapter in the entire book!! Very important points and well-written too.
Chapter 9: Epilogue: Moving to Agility
The book concludes with two brief case studies that show how Agile practices can save projects in trouble. Also mentioned is how a manager can gradually move a project and the team into an Agile mode of working, by introducing subsets of practices at a time. A programmer on the other hand has to lead by example, demonstrating the advantages of Agile by following them himself at first.