Sunday, July 16, 2017

Outputting the given, when, then, Extending Spock

Spock is a Java testing framework, created in 2008 by Peter Niederwieser a software engineer with GradleWare, which facilitates amongst other things BDD.  Leveraging this example, a story may be defined as:
Story: Returns go to stock

As a store owner
In order to keep track of stock
I want to add items back to stock when they're returned.

Scenario 1: Refunded items should be returned to stock
Given that a customer previously bought a black sweater from me
And I have three black sweaters in stock.
When he returns the black sweater for a refund
Then I should have four black sweaters in stock.

Scenario 2: Replaced items should be returned to stock
Given that a customer previously bought a blue garment from me
And I have two blue garments in stock
And three black garments in stock.
When he returns the blue garment for a replacement in black
Then I should have three blue garments in stock
And three black garments in stock.
Spock makes it possible to map tests very closely to scenario specifications using the same given, when, then format. In Spock we could implement the first scenario as:
class SampleSpec extends Specification{
    def "Scenario 1: Refunded items should be returned to stock"() {
        given: "that a customer previously bought a black sweater from me"
        // ... code 
        and: "I have three black sweaters in stock."
        // ... code
        when: "he returns the black sweater for a refund"
        // ... code
        then: "I should have four black sweaters in stock."
        // ... code
    }
}

What would be nice would be to ensure accurate mapping of test scenario requirements to test scenario implementation. We could get someway down this path if we could output the syntax of the given, when, then from our test.  Spock allows us to add this functionality through its extension framework.

So, let's say our BA is really curious and wants more confidence from the developer that they stuck to the same given, when, then format and their code is in-sync. They want to get this information easily.   Developer could provide this information by first defining this annotation
import java.lang.annotation.*
import org.spockframework.runtime.extension.ExtensionAnnotation

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@ExtensionAnnotation(ReportExtension)
@interface LogScenarioDescription {}
Followed by this implementation:
import org.apache.log4j.Logger
import org.spockframework.runtime.AbstractRunListener
import org.spockframework.runtime.extension.AbstractAnnotationDrivenExtension
import org.spockframework.runtime.model.FeatureInfo
import org.spockframework.runtime.model.SpecInfo


class LogScenarioDescriptionExtension extends AbstractAnnotationDrivenExtension; {
    final static Logger logger = Logger.getLogger("scenarioLog." + ReportExtension.class);

    @Override
    void visitSpecAnnotation(Report annotation, SpecInfo spec) {
        spec.addListener(new AbstractRunListener() {
            @Override
            void afterFeature(FeatureInfo feature) {
                if (System.getEnv("logScenarios")) {
                    logger.info("***SCENARIO TEST:*** " + feature.name)
                    for (block in feature.blocks) {
                        logger.info(block.kind);
                        for (text in block.texts) {
                            logger.info(text)
                        }
                    }
                }
            }
        })
    }
}
This will then be applied to the test
@LogScenarioDescription
class SampleSpec extends Specification{
  //...
When the test is executed it gives the following output:
***SCENARIO TEST:*** Scenario 1: Refunded items should be returned to stock
GIVEN
that a customer previously bought a black sweater from me
AND
I have three black sweaters in stock.
WHEN
he returns the black sweater for a refund
THEN
I should have four black sweaters in stock.
output to a specific logfile for scenario logging by using the following log4j:
log4j.rootLogger=INFO, stdout

log4j.logger.scenarioLog.extension.custom=INFO, scenarioLog

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%m%n

log4j.appender.scenarioLog=org.apache.log4j.FileAppender
log4j.appender.scenarioLog.File=logs/scenario.log
log4j.appender.scenarioLog.layout=org.apache.log4j.PatternLayout
log4j.appender.scenarioLog.layout.ConversionPattern=%m%n
and now you have a logfile that your BA, QA can read! This helps foster an Agile culture of collaboration and ATDD where it possible to check that test scenarios implemented with those that were agreed.

Tuesday, June 13, 2017

CoderDojo, so what's the point?

Initially I was skeptical of CoderDojo. Here's another thing IT professionals are doing for free. Why isn't there Economics Dojo,
Medical Dojo, Legal Dojo?  Why is a profession that at times is
extremely competitive, has long demanding hours, low job security being glamorized beyond a point of credible fiction?  Why are people being told they need to code when there are plenty of careers where you will never need to code and always will be?  And shouldn't our kids be out getting exercise, exploring nature?  At least that's what Steve Jobs thought.

It didn't stop there.  There is this trap that all parents fall for that if they get their kids involved something young they'll be a step ahead and if they don't they'll be a step behind.  CoderDojo is not immune to this quasi chimera.  So, I started thinking over my many glorious years in the IT profession, I have worked with a range of coders from the exceptional to the cryptically insane.  If I was to differentiate between a good coder and a not so good coder the number one differentiator is habits.   Yes habits.  Good coders follow good habits:
  1. They write unit tests first.
  2. They are always seeking feedback on their code.
  3. If something complex is happening, they seek to build consensus.
  4. They follow agreed conventions and industry standards.
These good habits mean you end up with something maintainable.   On the other side, coders with bad habits:
  1. They never write adequate tests.
  2. They don't take feedback well (usually because they are not used to it).
  3. If something complex is happening, they hack something up and you find out about it later than you should.
  4. They don't follow conventions - just stick to they way they do things that only makes sense to them.
So someone with the same aptitude, the same I.Q., the same hairstyle ends up producing something
that is much more difficult to maintain.

Don't get me wrong, there was a time when aptitude was much more important.  Complex C++ memory management, any assembly code required serious aptitude and a base level will always be needed.  There are about 50 important principles from encapsulation to recursion that you need some sort of aptitude to get.  But now with Stackoverflow, Google, lots of great libraries and frameworks mean it is really more about habits.  Pick a technology everyone is using and you get lots of support for free.

So learning to code at age 9, is that going to do anything to help you get good habits? Of course it isn't.  So then what's the point?  The point is for one thing only: fun.

As a friend recently said, it is the new mechano and lego.  Let them code but make sure they still play with lego and mechano.

So in my case, my older son (age 7) recently came home from school crying because he wanted to learn scratch. My wife gave him an old laptop and after reading a few PDFs he was away coding a little game talking about loops, scripts and wanting to change the mp3 files.  I was a bit shocked watching him stare at the screen trying to figure out his own code, coming out with tech babble and being able to get something working all by himself.  Next his friend was over. Is this pair programming for kids?

Anyway, no doubt, this new generation will have more information available to them than any before. This provides all sorts of creative avenues not just in code.  However, I can't agree with articles such as this recent one from RTE, telling us why your kid should code?

Kids should do what is healthy, safe and fun.  If they find Economics, Law or Medicine more stimulating than coding great.  Perhaps, the experts in those professions could also run free classes for all kids.   Alas, I somewhat doubt that will ever happen...