If you cannot measure it, you cannot improve it. Lord Kelvin
When I became a full-time developer I determined to learn what constitutes best-practice in my profession and to learn to apply it to my practice. Thus far, it has been an interesting and largely enjoyable journey.
Of course, I’ve made some fundamental mistakes on the way. One source of error has been difficulty in determining what constitutes best practice in the context of the projects I’m working on. Clearly, best practice in any endevour must be determined by your overall purpose. Today, I came across an article by Eric Lippert that sums up our purpose as well as anything I’ve come across up to this point:
The purpose of code is to create value by solving a business problem.
Best practice, then, is that which most effectively enables us to add business value. Not all code adds value in the same way, so best practice will vary between projects.
In the same article, Lippert identifies 3 areas in which code displays fitness for purpose:
- Good code is code which “works correctly according to its specification to actually solve the stated problem”
- Good code “communicates its meaning to the reader who needs to understand its operation”
- Good code “allows for relatively low-cost modification to solve new problems as the business environment changes”
The relative importance of these 3 areas can vary between projects. A quick throw-away script that is used by a single develpoper needs to be functional but less emphasis can be placed on modification and readability. On the other hand, an application like Microsoft Word will be worked on by many developers and maintained through numerous development cycles. As such, readability and maintainability need to be emphasised as much as correct fuctionality.
Note: This page is an ongoing project…
Below is my summary of “Practices of an Agile Developer: Working in the Real World” by Venkat Subramaniam and Andy Hunt. In my view this is a 4-star book, well worth reading in its entirety.
Aside from introductory and closing chapters, each chapter of the book describes one of 45 practices that are important in achieving an Agile development environment (one reviewer suggested it be renamed, “45 Habits of Highly Effective Developers”)
The thing I like most about the book is the emotional awareness of the authors. They recognise that development is as much an emotional experience as it is a technical one, and that communicating good practice needs to address the readers’ emotional needs as well as their practical ones. This applies to both the presentation and content of each chapter. As a result, I felt good about reading this book, and I feel good about trying out the espoused practices.
The language, typography and layout make it an easy read.
The subdivision of the book into 45 practices means that:
- It can be read in digestible chunks
- It is possible to dip-in
- It makes a good reference book
The chapters on each of the practices includes:
- A practice number and title, for easy reference.
- An explicit statement of the reasons why we might resist the practice described (the Devil’s temptation)
- A discussion that explains the rational behind the practice and how to apply it practically, typically backed up by real-world examples
- A summary of the key message of the chapter (the Angel’s advice)
- The emotional outcome of following the practices described (What it Feels Like). This encourages emotional buy-in.
- Notes on how not maintain perspective (“Keeping Your Balance”)
Work for Outcome (Page 12) – PoAD#P1
Prioritise finding the culprit over resolving the problem
- Reactive and defensive people are unproductive
- Assigning blame can make the situation worse
- It is rare that one person is entirely to blame
- Everyone makes mistakes (unless they take no risks)
- A person’s misunderstanding / ignorance/mistake often reveals an area for team development
Outcome is more important than taking credit / apportioning blame
Blame doesn’t fix bugs
Offer to help.
Be part of the solution, not part of the problem
Don’t argue about it, fix it.
- Safe to admit ignorance
- Mistakes are learning opportunities
- Remove bad apples from the bunch
- Remove yourself from a bad team
- Credit-whoring can be just as bad as apportioning blame
- Both the fear of and actuality of blame / credit whoring is damaging productivity
Quick Fixes Become Quicksand (Page 15) – PoAD#P2
Make a quick fix to code you don’t really understand
Clarity of code goes down
Accumulation of quick fixes become “quicksand”
You can’t possibly be agile with that kind of baggage
Long term code clarity is more important than short-term fixes.
- Get a good understanding of the overall architecture and design
- Understand the code you modify
- Avoid quick hacks
- Invest in code clarity
Fix the problem, not the symptom
- Don’t code in isolation (e.g. use code reviews)
- Unit testing
- Clean code
- No areas of untouchable code
- Developers have a general working knowledge of the code base
There are no dark corners in the project
- You don’t need to become an expert at everything
- Larger systems are rarely understood by one individual
- If the code can’t be understood by the team, it is too hard to maintain – even for the original author
Quick fixes can be bad news in the short term, too. The project was a static data loader that threw an exception. I made a small change to a piece of code I didn’t fully understand. The consequence was the the data in the wrong version of the database was overwritten.
Criticize Ideas, Not People (Page 18) – PoAD#P3
Making it about who is right rather than what is right.
- Does nothing to enhance understanding
- Suppresses innovation
- Makes people unhappy
- Everyone has bad ideas
- Nothing is perfect – there is only “better”
- Bad ideas can stimulate good ones
- Everyone starts somewhere
- Compromises are inevitable
Focus on the best solution, not the best person.
Criticize ideas, not people
- Ask open questions to reveal flaws and solutions
- Don’t be afraid of criticism
- When you see a potential problem, realistically ask how often a problem actually occurs
- Support the decision
Tools for Overcoming Indecision
- Set a deadline
- Argue for the opposite
- Freedom to explore ideas
- Ideas can be rejected without hurt feelings
- Imperfect ideas can be adopted without guilt
- Make sure everyone agrees on what “best” means. Users and developers often disagree
- Sometimes you have to accept the least worst solution
Damn the Torpedoes, Go Ahead (Page 23) – PoAD#P4
Ignore important issues to avoid uncomfortable situations
Courage to do what is right
- Be courageous
- Communicate truth
- Do the right thing
Admiral David Farragut:
Damn the torpedoes, full speed ahead!
- Short-term discomfort
- Relief, not dread
- Festering problems addressed
- If everyone else disagrees, you may be explaining it wrong – or just wrong
- Impatience is not courage – take time to understand why things are the way they are
Keep Up with Change (Page 28) – PoAD#P5
Keep up with changing technology. You don’t have to become an expert at everything, but stay aware of where
the industry is headed, and plan your career and projects accordingly.
Invest in Your Team (Page 31) – PoAD#P6
Raise the bar for you and your team. Use brown-bag sessions to increase everyone’s knowledge and skills and help bring people together. Get the team excited about technologies or techniques that will benefit your project.
Know When to Unlearn (Page 34) – PoAD#P7
Learn the new; unlearn the old. When learning a new technology, unlearn any old habits that might hold you back.
Question Until You Understand (Page 37) – PoAD#P8
Keep asking Why. Don’t just accept what you’re told at face value. Keep questioning until you understand the root of
Feel the Rhythm (Page 40) – PoAD#P9
Tackle tasks before they bunch up. It’s easier to tackle common recurring tasks when you maintain steady, repeatable intervals between events.
Delivering What Users Want
Let Customers Make Decisions (Page 45) – PoAD#P10
Let your customers decide. Developers, managers, or business analysts shouldn’t make business-critical decisions. Present details to business owners in a language they can understand, and let them make the decision.
Let Design Guide, Not Dictate (Page 48) – PoAD#P11
A good design is a map; let it evolve. Design points you in the right direction. It’s not the territory itself; it shouldn’t dictate the specific route. Don’t let the design (or the designer) hold you hostage.
Justify Technology Use (Page 52) – PoAD#P12
Choose technology based on need. Determine your needs first, and then evaluate the use of technologies for those specific problems. Ask critical questions about the use of any technology, and answer them genuinely.
Keep It Releasable (Page 55) – PoAD#P13
Keep your project releasable at all times. Ensure that the project is always compilable, runnable, tested, and ready to deploy at a moment’s notice.
Integrate Early, Integrate Often (Page 58) – PoAD#P14
Integrate early, integrate often. Code integration is a major source of risk. To mitigate that risk, start integration early and continue to do it regularly.
Automate Deployment Early (Page 61) – PoAD#P15
Deploy your application automatically from the start. Use that deployment to install the application on arbitrary machines with different configurations to test dependencies. QA should test the deployment as well as your application.
Get Frequent Feedback Using Demos (Page 64) – PoAD#P16
Develop in plain sight. Keep your application in sight (and in the customers’ mind) during development. Bring customers together and proactively seek their feedback using demos every week or two.
Use Short Iterations, Release in Increments (Page 69) – PoAD#P17
Develop in increments. Release your product with minimal, yet usable, chunks of functionality. Within the development of each increment, use an iterative cycle of one to four weeks or so.
Fixed Prices Are Broken Promises (Page 73) – PoAD#P18
Estimate based on real work. Let the team actually work on the current project, with the current client, to get realistic estimates. Give the client control over their features and budget.
Put Angels on Your Shoulders (Page 78) – PoAD#P19
Use automated unit tests. Good unit tests warn you about problems immediately. Don’t make any design or code changes without solid unit tests in place.
Use It Before You Build It (Page 82) – PoAD#P20
Use it before you build it. Use Test Driven Development as a design tool. It will lead you to a more pragmatic and simpler design.
Different Makes a Difference (Page 87) – PoAD#P21
Different makes a difference. Run unit tests on each supported platform and environment combination, using continuous integration tools. Actively find problems before they find you.
Automate Acceptance Testing (Page 90) – PoAD#P22
Create tests for core business logic. Have your customers verify these tests in isolation, and exercise them automatically as part of your general test runs.
Measure Real Progress (Page 93) – PoAD#P23
Measure how much work is left. Don’t kid yourself — or your team — with irrelevant metrics. Measure the backlog of work to do.
Listen to Users (Page 96) – PoAD#P24
Every complaint holds a truth. Find the truth, and fix the real problem.
Program Intently and Expressively (Page 100) – PoAD#P25
Write code to be clear, not clever. Express your intentions clearly to the reader of the code. Unreadable code isn’t clever.
Communicate in Code (Page 105) – PoAD#P26
Comment to communicate. Document code using wellchosen, meaningful names. Use comments to describe its purpose and constraints. Don’t use commenting as a substitute for good code.
Actively Evaluate Trade-Offs (Page 110) – PoAD#P27
Actively evaluate trade-offs. Consider performance, convenience, productivity, cost, and time to market. If performance is adequate, then focus on improving the other factors. Don’t complicate the design for the sake of perceived performance or elegance.
Code in Increments (Page 113) – PoAD#P28
Write code in short edit/build/test cycles. It’s better than coding for an extended period of time. You’ll create code that’s clearer, simpler, and easier to maintain.
Keep It Simple (Page 115) – PoAD#P29
Develop the simplest solution that works. Incorporate patterns, principles, and technology only if you have a compelling reason to use them.
Write Cohesive Code (Page 117) – PoAD#P30
Keep classes focused and components small. Avoid the temptation to build large classes or components or miscellaneous catchall classes.
Tell, Don’t Ask (Page 121) – PoAD#P31
Tell, don’t ask. Don’t take on another object’s or component’s job. Tell it what to do, and stick to your own job.
Substitute by Contract (Page 124) – PoAD#P32
Extend systems by substituting code. Add and enhance features by substituting classes that honor the interface contract. Delegation is almost always preferable to inheritance.
Keep a Solutions Log (Page 129) – PoAD#P33
Maintain a log of problems and their solutions. Part of fixing a problem is retaining details of the solution so you can find and apply it later.
Warnings Are Really Errors (Page 132) – PoAD#P34
Treat warnings as errors. Checking in code with warnings is just as bad as checking in code with errors or code that fails its tests. No checked-in code should produce any warnings from the build tools.
Attack Problems in Isolation (Page 136) – PoAD#P35
Attack problems in isolation. Separate a problem area from its surroundings when working on it, especially in a large application.
Report All Exceptions (Page 139) – PoAD#P36
Handle or propagate all exceptions. Don’t suppress them, even temporarily. Write your code with the expectation that things will fail.
Provide Useful Error Messages (Page 141) – PoAD#P37
Present useful error messages. Provide an easy way to find the details of errors. Present as much supporting detail as you can about a problem when it occurs, but don’t bury the user with it.
Schedule Regular Face Time (Page 148) – PoAD#P38
Use stand-up meetings. Stand-up meetings keep the team on the same page. Keep the meeting short, focused, and intense.
Architects Must Write Code (Page 152) – PoAD#P39
Good design evolves from active programmers. Real insight comes from active coding. Don’t use architects who don’t code—they can’t design without knowing the realities of your system.
Practice Collective Ownership (Page 155) – PoAD#P40
Emphasize collective ownership of code. Rotate developers across different modules and tasks in different areas of the system.
Be a Mentor (Page 157) – PoAD#P41
Be a mentor. There’s fun in sharing what you know—you gain as you give. You motivate others to achieve better results. You improve the overall competence of your team.
Allow People to Figure It Out (Page 160) – PoAD#P42
Give others a chance to solve problems. Point them in the right direction instead of handing them solutions. Everyone can learn something in the process.
Share Code Only When Ready (Page 162) – PoAD#P43
Share code only when ready. Never check in code that’s not ready for others. Deliberately checking in code that doesn’t compile or pass its unit tests should be considered
an act of criminal project negligence.
Review Code (Page 165) – PoAD#P44
Review all code. Code reviews are invaluable in improving the quality of the code and keeping the error rate low. If done correctly, reviews can be practical and effective. Review code after each task, using different developers.
Keep Others Informed (Page 168) – PoAD#P45
Focus on getting the job done. If people want a status update, they’ll ask.
- Trust diminishes
- You won’t get help
- Customers can’t re-prioritize
- Interruptions for status updates
Keep others informed
- Tell people, don’t wait for them to ask
- Deliver bad news early: don’t give people unpleasant surprises
- Publish designs, cool ideas, research, status etc.
Stay head’s up, not head down
- Sticky notes
- Phone calls
- Status charts
- Daily stand-up
- People don’t pester you for status updates
- Know your audience, level appropriately
- Don’t let communication efforts get in the way of work progress
Other Summaries and Reviews
Issues and Changes
- Change is inevitable
Projects need a systematic method for managing change
Change management is a continual activity
An issue is an event that was
- not planned
- requires management action
Issues can be raised by anyone
Types of Issues
- Off Specification (Off Spec): any product that is missing / not meeting agreed specification
- Request for Change (RfC): proposed change from baseline
- Problem / Concern (P/C): any other problem / concern / query / suggestion
Systematic change control keeps project:
- Responsive to change
- Under control
Ensures change is
- Authorised by appropriate authority
- Considered in relation to baseline
Procedures ensure that issues and changes are:
- Approved / rejected
Products are versioned (i.e. kept in configuration management)
Mechanism to track configuration:
Something subject to configuration management, such as:
- A product
- A component of a product
- A set of products that form a release
A set of products that are managed, tested and deployed as a unit
Management Products (Documents)
- Configuration Management Strategy
- Configuration Item Records
- Product Status Accounts
- Daily Log
- Issue Register
- Issue Reports
Configuration Management Strategy
Facilitates impact assessments (relationships between products)
Maintains product baselines
Based on corporate or programme strategy where these exist
- Management procedure
- Issue / Change control procedure
- What: Tools and techniques
- Why: Records and Reporting
- When: Timing
- Who: Roles and responsibilities
Who has responsibility at each severity level.eg. Project Board, PM, etc.
Funding for the costs of change
Managed by Change Authority
Limits can be specified for:
- Costs of single change
- Total spend on change in stage
Configuration Item Records
Include information on:
- Relationships between items
Product Status Account
State of products
Records problems and concerns that can be handled by PM informally
Can be transferred to Issue Register if required
Contains information on issues managed formally
Monitored by PM regularly
Only required for formal issues, these include:
- Impact assessment
Configuration Management Procedure
- Decide level of configuration management required
- And how that level will be achieved
All components of products at level of control
- Approve products
- Baseline products (old baselines are archived, not deleted)
- Ensure changes are authorised by appropriate authorities
- Management products (inc documentation)
- Specialist products
Reporting on current and historical data re: product
Verification and Audit
- Comparing actual and authorised status of products.
- Check procedures in Configuration Management Strategy are followed
Occur at end of stage and end of project
Issue and Change Control Procedure
Defined by IP process
Reviewed and updated during MSB process
- Type of Issue – formal / informal
- Determine severity / priority
- Level of authority
- Formal issues -> Issue Register
- Issue Report created
- Impact of analysis cost
- Impact analysis on project objectives / business case / project risk profile
- Impact on supplier / user / business
- Update Issue Register / Issue Report
- Identify options
- Evaluate options
- Recommend options
- Exception Report?
- Request info
- Grant Concession
- Request info
Problem / concern
- Provide guidance
- Take corrective action
- Create an exception plan
Update issue register
Some changes impact budget
Using Tolerance to fund Changes
Using Change Budget
Increase project cost
Reducing project scope
I’ve just published my first Visual Studio Extension. It is a very simple one-command extension that allows you to view the contents of the folder that contains the current project in the Visual Studio Browser. At the moment, only Visual Studio 2010 is supported.
Instructions for Use
To view open the browser on the project’s folder, just click on the button in the Solution Explorer’s toolbar. The button is only visible when you have a solution loaded in Visual Studio.
The contents of the folder that contains the current project will be displayed in Visual Studio. That’s it!
Unfortunately, StudioStyles doesn’t support all the styles for VB.Net, so you’ll have to tweak it a bit if you want VB.Net goodness.
This post has moved to Yagni.net.
Performance can be an important consideration for applications. In some scenarios, object creation is a costly step.
Avoids cost of initializing objects by maintaining a pool of pre-initialized objects that can be re-used.
Description of Benefits
Can offer a performance boost where:
- object instantiation is expensive
- instances of the class are frequently created
- number of instances at any one time is small
Can make initialization time predictable where it would otherwise be unpredictable (e.g. when squiring resources over a network)
Instantiation of objects that represent:
- database connections
- socket connections
- large graphic objects
- Shoe shelf at a bowling club
- Car pooling
Reusable: An object used by Client until they it is no longer required.
Client: Uses an instance of Reusable for a limited amount of time
ReusablePool: Manages the collection of Reusable objects by:
- creating new instances of Reusable
- supplying instances of Reusable to Clients
Typical methods induce:
- getInstance: A static method that returns an instance of ReusablePool
- aquireReusable:A method that returns an instance of Reusable
- releaseReusable(Reusable):A method that returns a Reusable to the pool
Basic Implementation (Collaboration)
The Client is responsible for requesting the Reusable from the ReusablePool.
On receiving a request for an object, the ReusablePool will attempt to supply an suitable Reusable.
The Client should be unaware that the Reusable can be shared with other Clients: from the Client‘s point of view, the Reusable can be treated in exactly the same way as an object that has been created in any other way,the only difference being that it must return it to the ReusablePool once it has finished using it.
The Client is responsible for returning Reusables to the ReusablePool once it is finished with.
Resource Loading Strategy
Several strategies are available, for example:
- Eager: A specified number of Reusables are created by the ReusablePool when the ReusablePool is instantiated.
- Lazy: Reusables are not created by the ReusablePool until they are requested by the a Client. Once Reusables are released, they are immediately available for other Clients.
- Hybrid: A specified number of Reusables are created eagerly, but additional Reusables are created lazily.
- Lazy-Expanding: Creates resources lazily, but doesn’t re-use them until the ReusablePool reaches a certain size.
- Eager-Expanding: Creates resources eagerly. Creates additional resources when available objects in the ReusablePool drops below a certain threshold.
Maximum Pool Size
Some implementations may set a maximum number of Reusables in the ReusablePool
Various strategies can be adopted to handle the situation where a Client requests an instance from the pool, but none is currently available:
Prevent the situation by ensuring that the ReusablePool will always contain enough Reusables.
- Fail to provide Reusable, and inform the Client that none is available
- Create a new Reusable, thus increasing the size of the pool
- Block until another thread to releases an object back into the pool
- Forcible reclaim a Reusable from a low-priority Client
In a multi-threaded environment, careful consideration must be given to synchronisation of methods on the ResourcePool object.
If the Client fails to return a Reusable to the pool, then it will be unavailable to other Clients. To avoid this, the ResourcePool could implement an expiry time for Reusable:
if the Reusable has not actually been used for a certain length of time, it can be made available to other Clients.
In some situations, it may be undesirable to hold unused Reusables in the ReusablePool for long periods of time. In this case, it may be desirable to evict Reusables from the ReusablePool if they have not been requested by a Client for a specified length of time.
Some types of Reusables may need to be reset to a know state before they can be allocated to another Client. This is the responsibility of the ReusablePool.
- Mixed Pools
Relationship with Other Patterns
ReusablePool is often implemented as a Singleton.