Many people are familiar with Bill Wake's INVEST acronym when it comes to user stories. Even though I've heard a number of criticisms launched at conferences, from my experience it is still very popular in current teaching material.
Althought INVEST can be used to review user stories, when I look at the quality aspects of a process overall I would like to have a different approach. With user stories in each various incantations being very popular in the Agile world, I would therefore want to be able to review from an outsider's point of view, possibly that of a coach or consultant.
My friends Ashish Misra and Aditya Garg have come up with what I consider to be an excellent list [1]. I have deemed to name it the User Story Quality Factors:
Completeness: Any team or organisation will develop a way of capturing user stories. This might be internalised or published in a similar fashion to a Definition of Done. Therefore does te story have all the information it is supposed to have? Does it have traceability from previous documentation or discussions?
Consistency: The way the specification is formatted, the language used and the way the requirements are presented should be consistent throughout.
Ambiguity: Is it free of any ambiguous statements?
Specific: Is it free of generalised statements?
Realisable: Does the requirement make sense and is it possible? Has all of
the information been included in order to deliver the product?
Testable: If the user acceptance criteria is not testable it cannot be built with confidence.
Traceable: Who wants this requirement and why is it needed, what business strategy does it support?
Measurable: How are you going to measure if the requirements have actually been delivered and are operational to specification? Quantification applies to both user acceptance criteria (that which tell you that you can release) and success criteria (that which tells you that your release is a success in the market). If I don't see this I usually teach people the basic of Planguage - Name, Scale, Meter & Goal.
Acceptable: Is the use of calculations, language, logic and formulas correct?
Achievable: Is the user story achievable within an sprint (iteration-based) or a acceptable number of cadences (iteration-less)? If not, then consideration must be given to splitting the user story in to smaller units that still deliver value.
Independent: It is best if stories are independent. Sometimes this is not completly possible, thus one-way directional dependencies are acceptable. Circular and two-way dependencies are not allowed, otherwise prioritisation and planning problems will occur. The latter will also indicate that there are other issues within the context of a project or business value increment.
[1] By their own admission, Ashish & Adi would not declare full originality to the
idea, but rather that it has been a fusion of ideas, influenced by the
streams of time. Maybe a similar list already exists in another
publication. If anyone reads this and can point me to that, then please
do so - appropriate credit needs to be given.
Thursday, 6 March 2014
Thursday, 27 June 2013
More Advanced Build Flows with Jenkins
A while ago I needed to orchestrate a much more complex build flow in Jenkins. Besides the normal build, which includes unit testing, there was a need to test performance, performance static analysis on the code and well as execute a full functional test run. The problem was that most of these things took hours to complete. As the start of this, a full functional test run, if done sequentially, took 60 hours. Luckily it was possible to partition the testing so that it could be run in parallel.
What was required is to create a flow that looked similar to below.
This is achieved via the Cloudbees Build Flow Plugin, which is free and open-source. The source code is on Github. I am not going to explain more about the basics of the plugin, that can be read for itself on the plugin wiki page. There is enough there to get someone started. However, when you want to achieve the above kind of flow you'll need to know a bit more.
The DSL is Groovy-based, so knowing the basics of the languages and especially Closure syntax is required. The flow itself is controlled via the FlowDSL class. Furthermore calling
Once you have the
For me one of the drawbacks of the current implementation is the lack of Grape support. Sometimes one needs just a bit more decision-making capability than what stock Groovy will offer you. It would be helpful to be able to use @Grab to pull in some extra libraries.
It is also not possible to version the build flow script. It could definitely be useful to store it in source control and then update it before each run. The best workaround for now is to either
Even given the above mentioned limitations, the Build Flow Plugin is a powerful item in the quiver of any Jenkins crew. I hope that this article will help other towards some more complex real world orchestrations.
What was required is to create a flow that looked similar to below.
This is achieved via the Cloudbees Build Flow Plugin, which is free and open-source. The source code is on Github. I am not going to explain more about the basics of the plugin, that can be read for itself on the plugin wiki page. There is enough there to get someone started. However, when you want to achieve the above kind of flow you'll need to know a bit more.
The DSL is Groovy-based, so knowing the basics of the languages and especially Closure syntax is required. The flow itself is controlled via the FlowDSL class. Furthermore calling
build returns a JobInvocation instance and dependant on how parallel is called, it will either return a list or a map containing FlowState instances. The build results are actually stored in a Run instance which, after obtaining a JobInvocation instance is available via .build property-syntax. Knowing this difference is important as it will help you to extract build information later on.Once you have the
JobInvocation object you can obtain a number of useful bits of informationCreating Build Flow
The following code snippet illustrates how to create a build flow similar to the graphic depiction.Define as much as possible as closures
This will delay execution until such time that is required. This is whatparallel relies on too. buildFlow, staticAnalysisFlow and performanceFLow are examples.
Capturing build results within the closure
Notice howbuildFlow will store results in buildResult. (The latter will become a JobInvocation instance after execution)Executing multiple instances of the same job
It is relatively easy to execute multiple instances in parallel, each running with different parameters. This can be done with a simple Groovy Range and using thecollect operation. parallel requires a list of closures to be passed to it, collect does that for you
See how testFlow is defined above. We have even wrapped each build inside and ignore closure, so that unstable builds don't break the build pipeline.Break down complex flows into smaller flows
Stringing lots of flow sections together, can be tricky to follow. In such cases break down the flows into smaller manageable sections. AsstaticAnalysisFlow took a very long time to complete, I wanted it to run parallel to everything else. I have therefore created a mainFlow to run alongside. In order to deal with the complexity of running performanceFlow in parallel with another flow which already has more parallel flows in it, I have broken it down into smaller flows, which are then strung back together. Strictly speaking the use of arrays and each are not necessarily, but when you have even for jobs involved, this style can sometimes be easier to read.Collecting results from multiple parallel builds
For all of the aprtitioned test runs, I wanted to collect the build numbers so that it could be passed downstream. As mentioned earlierparallel returns a FlowState instance. It is a simple case of iterating through all of the builds and finding the lastBuild property which will give you a JobInvocation to work with.Collecting everything
Once all of the builds have completed, the necessary information can be passed do a final downstream job, which in turn can aggragate information form all of the other jobs.Build-flow Limitations
For me one of the drawbacks of the current implementation is the lack of Grape support. Sometimes one needs just a bit more decision-making capability than what stock Groovy will offer you. It would be helpful to be able to use @Grab to pull in some extra libraries.
It is also not possible to version the build flow script. It could definitely be useful to store it in source control and then update it before each run. The best workaround for now is to either
- Create the build flow job via Jenkins CLI and version control the config.xml file
- Create the build via Gary Hale's gradle-jenkins-plugin and version control the build.gradle and template.xml files.
- There is no real way of testing the flow outside of Jenkins at present. This makes it hard to syntax check before hand. The best you can do is create a series of fast-completing mock jobs, to experiment with and once you are happy convert the flow to attach the real jobs that you need to link.
In conclusion
Even given the above mentioned limitations, the Build Flow Plugin is a powerful item in the quiver of any Jenkins crew. I hope that this article will help other towards some more complex real world orchestrations.
Monday, 24 June 2013
Automated Tests and Deployment are Real Code
Dale Emery has posted a great set of slides. I would recommend this to all software developers, testers, business analysts and everyone in the software management food chain to read.
Slide #9 from Dale's deck
This has reminded ne of a conversation with a tester not too long ago. I was doing some work with him on their test system. We pair-programmed the change - it was his first experience in pairing. It was the also only way we could achieve this tricky modification. The system has grown into a big code base. It was not well documented, apart from some Word documents that were not up to date. There was also a number of methods that mostly did the same thing.
I explained to him that the test system itself should be modular and unit-tested. His jaw dropped: "We should have tests for our tests?". "Indeed", I replied, "you are using this to functionally test the product as if it is installed in a live environment. You need to have the confidence that changes you make will not adversely affect the results."
This was an eye-opener for him. He has never considered test code to be real code. Surely we sometimes do things in test code that we won't do in production code, but that is intentional as the code is fit for purpose. It still needs to be maintained and structured properly for it will probably live as long as the product itself would. Just as there is a cost to not doing TDD on any sizeable production of code, there is a cost to not doing it for any sizeable test code base. This test code will probably live as long as the product itself, therefore it needs to be maintained with the same fervour as the production code. Good developers understand this about unit tests, but I am seeing that the biggest breakdown still occurs where people need to build test systems to perform functional or integration testing.
The same applies for your deployment code. The DevOps movement tells us that infrastructure is code. Not only do you need to look after your production code and test code, you also need to look after your deployment code with the same zeal. It is hard to do, it requires discipline, but that discipline is what is going to allow you to relax on the weekend, instead of fighting fires in the office. I would call that prosperity:
I have recently heard of a team that used to work to the mantra of building walking skeletons first, including building the skeleton deployment code first. Of late, they have been told to manually deploy because THERE_IS_NO_TIME_FOR_WRITING_AUTO_DEPLOYMENT code. Now that is just wrong. It is a mutation of Dale's Automation Last Zombie (see slide #12 of Dale's deck). We can even call it the Deployment Last Zombie. I am sure that team will pay for this short-term thinking pressed upon them.
Just as test-driven development has done a lot for design and testability we really need Deployment-driven development. Dare I call it DDD? Preferably not, there are too many buzz acronyms around already. Regardless of what we call it, this is what DevOps and the next level of effective software development brings to the table.
Just remember, treat your test automation code and your deployment code with the same respect that you treat your production code with.
Labels:
agile,
automation,
devops,
kanban,
lean,
lean software,
prosperity,
TDD,
testing
Monday, 26 December 2011
Upgrading to Mandriva Powerpack 2011 - Resolving the Pain Points
I recently had to upgrade three Lenovo G550 laptops to Mandriva Powerpack 2011. I have been a Mandriva user since the 90s, but I cannot say that this has been an easy upgrade - so much so that I have considered switching to Ubuntu instead. Anways I hope that these notes might help others solving some issues on the 2011 release.
Fails to start on first boot after installation:
Boot with failsafe the first time, the 2nd time normal boot will work. I don't know why it works, it is a stupid workaround.
Fixing segmentation faults in Mozilla Thunderbird:
This issue only occurs when using LDAP for login authentication. Starting nscd works around the problem, but for some reason nscd does not want to start at boot time. I have never been a fan of nscd anyway, I after having hours trying to get debug why nscd does not start I gave up and found a workaround in a BUG 291127.
This is not really a satisfactory solution, as everytime I upgrade Thunderbird, I might need to fix the symlink again, but it got it going.
Autofs cannot mount NFS locations:
This appears to be name resolving bug in autofs 5.0.6. Solved it by doing
CD-ROM only works during installation:
Delete /dev/cdrom line from /etc/fstab as per Mandriva Errata.
Network errors on eth0:
If the ethernet adaptor according to lspci is "Ethernet controller: Broadcom Corporation NetLink BCM5906M Fast Ethernet PCI Express (rev 02)" then set the MTU=1000 (in contrast to default of 1500) as per a previous posting.
BCM4312 wifi driver:
If you are unlucky still to have Broadcom wireless hardware in your G550, then some work lies ahead. This specific hardware identifies itself to lspci as
Mandriva gives you the option to use the new dkms-broadcom-wl package, but it simply did not want to install on the default 2.6.39 kernel due to DKMS build failures. I decided to settle for using the firmware-dependent b43 driver instead. For this the b43-fwcutter package had to be installed and the firmware downloaded from openwrt and unpacked - just follow the Mandriva instructions. It was also necessary to edit /etc/modprobe.conf and add the line
(Src: OpenSuse Forums)
Finally setting MTU=1000 as was the case for the ethernet hardware, solved the dropping of packets.
Fails to start on first boot after installation:
Boot with failsafe the first time, the 2nd time normal boot will work. I don't know why it works, it is a stupid workaround.
Fixing segmentation faults in Mozilla Thunderbird:
This issue only occurs when using LDAP for login authentication. Starting nscd works around the problem, but for some reason nscd does not want to start at boot time. I have never been a fan of nscd anyway, I after having hours trying to get debug why nscd does not start I gave up and found a workaround in a BUG 291127.
cd /usr/lib64/mozilla-thunderbird-8.0
mv libldap60.so libldap60.so.REAL
ln -s /usr/lib64/libldap-2.4.so.2 libldap60.so
This is not really a satisfactory solution, as everytime I upgrade Thunderbird, I might need to fix the symlink again, but it got it going.
Autofs cannot mount NFS locations:
This appears to be name resolving bug in autofs 5.0.6. Solved it by doing
rpm -Uvh --oldpackage autofs-5.0.5-2mdv2010.1.x86_64.rpm
CD-ROM only works during installation:
Delete /dev/cdrom line from /etc/fstab as per Mandriva Errata.
Network errors on eth0:
If the ethernet adaptor according to lspci is "Ethernet controller: Broadcom Corporation NetLink BCM5906M Fast Ethernet PCI Express (rev 02)" then set the MTU=1000 (in contrast to default of 1500) as per a previous posting.
BCM4312 wifi driver:
If you are unlucky still to have Broadcom wireless hardware in your G550, then some work lies ahead. This specific hardware identifies itself to lspci as
Network controller: Broadcom Corporation BCM4312 802.11b/g LP-PHY (rev 01)
Mandriva gives you the option to use the new dkms-broadcom-wl package, but it simply did not want to install on the default 2.6.39 kernel due to DKMS build failures. I decided to settle for using the firmware-dependent b43 driver instead. For this the b43-fwcutter package had to be installed and the firmware downloaded from openwrt and unpacked - just follow the Mandriva instructions. It was also necessary to edit /etc/modprobe.conf and add the line
options b43 pio=1 qos=0
(Src: OpenSuse Forums)
Finally setting MTU=1000 as was the case for the ethernet hardware, solved the dropping of packets.
Thursday, 1 December 2011
WS-Security Username Tokens in Groovy
The simplest of WS-Security tokens: just send a username and password in the SOAP header. Ignoring the usual arguments about how insecure this might be, there are a number of systems that actually utitlise this and if you are using groovy-wslite, you might need to add it. The following code snippet generates the appropriate XML fix can be placed in the header.
If you place this in a seperate closure, the just call it from your message closure as using mkp.yieldUnescaped.
If you place this in a seperate closure, the just call it from your message closure as using mkp.yieldUnescaped.
Tuesday, 22 November 2011
Kicking off Multiple Processes from Groovy
The following is a code snippet for kicking of a number of similar processes from a Groovy script and waiting for them to finish. The stdout & stderr streams are discarded.
Normally creating interfaces with maps in Groovy when there are overloaded methods present, are non-trivial, but in this case we throw away all content. This leads to a simple nullAppender.
I just used touch as a simple illustration, replace it with whatever you need. If you want to execute your process in anotehr directory than the current worknig directory or want to customise the environment, remember that execute can take two parameters to do exactly that.
Normally creating interfaces with maps in Groovy when there are overloaded methods present, are non-trivial, but in this case we throw away all content. This leads to a simple nullAppender.
I just used touch as a simple illustration, replace it with whatever you need. If you want to execute your process in anotehr directory than the current worknig directory or want to customise the environment, remember that execute can take two parameters to do exactly that.
Wednesday, 31 August 2011
How Management Can Help Continuous Improvement
When doing some house clearing, I can across and old note book from 2003/2004. Some notes I made about Continuous Improvement (CI) really struck me as they are as relevant today as they were when I wrote them. IN this blog, you will not any earth-shattering new information, just five simple principles that managers or thought leaders within an organisation should keep in mind.
Support the process through allocation of time, money, space + other resources
Support experimentation. Do not punish mistakes, but encourage learning from mistakes. Making a mistake is not failure,
When major organisational changes are planned or coming your way, assess the impact on the existing CI system.
Incorporate it in your planning. It is therefore important to align your CI system with your strategy.
Facilitate CI co-operation across functional boundaries.
Apply shared-problem solving. If only one group improves, it is just local optimisation. But co-operating across teams and functional boundaries, optimisation can go company global. This is also an underlying principle of rightshifting.
Become a learning organisation.
As a manager you must accept that learning will take place and, where applicable, act on all the learning that have taken place. The organisation itself, needs articulate and consolidate the learning of individual and groups. It is not of much help if only individuals learn, but that learning must be shared in some form or another.
The CI system itself must also be continuously improved.
It is important that sufficient resources are made available. If necessary, lobby higher levels of management to understand this. Try to use Reinertsen's Economic model to quantify what value your CI is process providing.
Note: Unfortunately I cannot remember some of the references I was reading at the time, when I made the notes. If anyone recognises something, please let me know.
Support the process through allocation of time, money, space + other resources
Support experimentation. Do not punish mistakes, but encourage learning from mistakes. Making a mistake is not failure,
When major organisational changes are planned or coming your way, assess the impact on the existing CI system.
Incorporate it in your planning. It is therefore important to align your CI system with your strategy.
Facilitate CI co-operation across functional boundaries.
Apply shared-problem solving. If only one group improves, it is just local optimisation. But co-operating across teams and functional boundaries, optimisation can go company global. This is also an underlying principle of rightshifting.
Become a learning organisation.
As a manager you must accept that learning will take place and, where applicable, act on all the learning that have taken place. The organisation itself, needs articulate and consolidate the learning of individual and groups. It is not of much help if only individuals learn, but that learning must be shared in some form or another.
The CI system itself must also be continuously improved.
It is important that sufficient resources are made available. If necessary, lobby higher levels of management to understand this. Try to use Reinertsen's Economic model to quantify what value your CI is process providing.
Note: Unfortunately I cannot remember some of the references I was reading at the time, when I made the notes. If anyone recognises something, please let me know.
Subscribe to:
Posts (Atom)

