Wednesday, December 29, 2010
TDD – But What do I Test?
FAST FAST is not actually an answer to the question, but a setup. FAST describes what makes a good test or suite of tests.
Fast – yes, the word associated with the first letter is the same and the acronym itself. Even a unit test project with thousands of tests should take no longer than a few seconds to run.
Atomic – unit tests should test one and only one piece of functionality or behavior. Atomic also means the test is not dependent on outside systems such as a web server or service, the file system, or a database. Those should all be represented by abstractions to support the F in FAST. We should be able to write and test our domain without a UI or data store.
Static – once a test is written, it should not change. This does not mean tests can never be refactored, but if you are practicing TDD, then you are setting up expectations of how the system should behave before writing any code. The implementation of that expectation may and probably will change, but the underlying test for the behavior should remain unchanged.
Thorough – unit tests should test as many conditions as the system under test will face during its lifetime. Testing just a single passing case does not really exercise the code fully or completely. It may not be possible for us to test every edge case, but we can put the code through its paces and ensure its behavior, stability, effectiveness, and graceful failing.
BEER Now on to what needs to be tested. BEER describes a set of cases or circumstances that require reflection and attention when writing tests and designing our APIs. The B in BEER does not stands for behavior - that is just a little too vague to be instructive.
Boundary Conditions – a value that exceeds the maximum or minimum allowed value. If we are testing a validation rule for a string that is required and cannot be more than fifty characters, we need to write a series of tests that address each a series of conditions - a null string, a zero-length string, a string with one character, a string with a length greater than one and less than fifty, a string with fifty characters, and a string with more than fifty characters. The same would apply to numbers or dates. This follows the T in FAST.
Existence – Not Cartesian existence, but nulls and state. We often see this when testing repositories and services. Unit testing persistence requires inserting an object into the data store (represented by an abstractions such as a repository - remember the A in FAST) and retrieving it to make sure it was correctly saved. The opposite, removing an object from the data store, requires a test to assert that it was correctly deleted. This also applies to an object’s state. We want to write tests for state transitions and verify that our objects behave appropriately in each case.
Exceptions – although we may not be able to foresee all possible conditions, we can test for certain exception conditions and ensure they are handled gracefully. Does an object in an invalid state throw an exception? Does the exception give the user an out? Does the exception provide useful information to either the user or other developer for resolving the issue?
Range Conditions – This would include things like a start date occurring before an end date or an invalid enumerator or case in a switch statement. Testing a sorting algorithm where the first element is less than the proceeding one would fall under range conditions.
Conclusion Unit testing is not just about one case or single event. It is about proving our code works in different environments and conditions. Is is also about falsifiability. When we are writing tests, focus on the negative cases and taking a defensive coding posture. What can go wrong and how will my code react? When outside forces assert pressure on the system how will it handle them?
Following these guidelines will help you achieve not just higher test coverage, but higher quality test coverage.
Wednesday, December 15, 2010
What is a Professional Redux?
One definition might be getting paid to do something. Another might be a commitment to performing at the highest level, to give your best at all times. Yet another may be exhibiting a courteous, conscientious, and generally businesslike manner in the workplace. While all of these are partially correct, there are many facets to being a true professional.
There are two parts to learning craftsmanship: knowledge and work. You must gain the knowledge of principles, patterns, practices, and heuristics that a craftsman knows, and you must also grind that knowledge into your fingers, eyes, and gut by working hard and practicing.
It requires more than just the knowledge of principles and patterns. You must sweat over it. You must practice it yourself, and watch yourself fail. You must watch others practice it and fail. You must see them stumble and retrace their steps. You must see them agonize over decisions and see the price they pay for making those decisions the wrong way.
- Robert Martin, Clean Code
A professional has specialized skills and knowledge that required independent erudition and effort on their part to attain. They engage in a process of constant evaluation and improvement. A professional makes decisions based on their dedication to the craft and not the current circumstance. The characteristic that separates the professional from the dilettante is an uncompromising commitment to excellence – doing what is required to get the job done at its highest level, even when it is inconvenient. An amateur is capable of doing some things well under the right conditions, but a professional, as a matter of course, does it well regardless of the situation.
A professional is passionate, motivated, and punctual. A professional respects the respectable, but admires the inspirational. A professional is a seeker of knowledge but also a teacher. A professional is disciplined, has the highest standards, and is engaged in the constant pursuit of un-attainable perfection. A professional is restless and never satisfied, always evaluating and re-evaluating where they’ve come and finding ways to do what they are doing better now, today, moment to moment.
I have offended God and mankind because my work did not reach the quality it should have.
- Leonardo da Vinci, artist, d. 1519, last words
Wednesday, December 8, 2010
Project Estimates, the Silent Killer
I have written about estimating in the past. That article discussed some of the inherent challenges of software project estimating. This time I want to focus on deliverables that are NOT code.
When creating a project estimate, we tend to concentrate on development time while neglecting common and important tasks that require hours and should be considered when defining an estimate. These are the areas where overages tend to occur precisely because they were overlooked.
These are just guidelines and should be modified for your specific situation.
Project setup
This includes setting up the development, QA, staging, and production environments, installing 3rd party software, getting access to client servers, VPN, remote desktop, web services etc. – minimum 8 hours.
QA time
This number should be provided after the project scope and business requirements have been establish and estimated. Ideally, this number would be provided by a qualified QA specialist.
Code Reviews
This is an invaluable step in maintaining code throughout the project - one hour per week of the project.
Meetings
This includes design meetings, internal and external, client meetings, phone calls, email conversations, etc. - minimum one hour per week of the project per team member working on the project.
Demos
You are planning on showing something to the client right? One hour per iteration.
UAT
Let’s not forget that we must have user acceptance testing. One hour per iteration.
Post Implementation Meeting
This is another invaluable tool in fine-tuning the process of constant improvement over the lifetime of the project and the developer. Half hour per iteration per team member working on the project.
Deployment
This includes creating a deployment and rollback plans, database update scripts, deployment to QA and staging environments during development, etc. - minimum 8 hours.
Post Implementation Client Support
This is support supplied to the client after a production release - minimum 2 hours.
UI/UX Design
If a project requires graphic design, then it requires a graphic designer – minimum 24 hours for design, CSS, html, images, etc.
And those are just the minimum requirements. Check out this more comprehensive list from Steve McConnell’s Software Estimation. Demystifying the Black Art
Wednesday, December 1, 2010
Visual Layout Design Help
As software developers, most of us are expected to be many things to our customers and employers: an architect, estimator, tester, technical writer, project manager, diplomat, usability expert, visual/UI designer, etc.
In an effort to pass along knowledge that may be helpful to support education in the realm of visual layout, I wanted to share this. It is a CSS layout based on the “optimal” on-screen layout of 960 pixels. It has an HTML, CSS generator and you can download templates for more than a dozen platforms (Fireworks, Photoshop, Visio, etc.)
You can check out more of the background details here.