Posts filed under ‘Software Development’

“Legacy Code: Using Domain-Driven Design to Carve Out Areas of Sanity” Now On InfoQ

See http://www.infoq.com/presentations/Legacy-Code-DDD

(Presentation from http://www.sdec12.com/ )

February 13, 2013 at 9:37 am 2 comments

What is Software Architecture?

It’s about designing systems to support an initial release on the PowerPoint platform, using  patterns,  boxes and arrows.

No – what is software architecture, the essence of it?

It’s an exercise in user experience design.

The history of computing can be seen as a series of attempts to make building software simpler to understand.

This is because the number of factors we can keep in mind at the same time is limited; The level of detail to which we can understand problems and reason about them is constrained by time and capacity.

If we get overwhelmed by complexity we get bugs and it takes longer to deliver the system. We fail to meet the objective: Most of us produce marketable features for sale, directly or indirectly. Simplicity speeds us up. Complexity slows us down. Slow delivery means less to sell and ultimately less money to pay us with.

The user experience of building, deploying and maintaining marketable features must be simple. This is the goal of software architecture.

September 8, 2012 at 7:31 am Leave a comment

Cucumber And SpecFlow Aren’t Test Tools

…. although it’s certainly possible to use them that way. But why would one such a thing, de-tuning what is really a rather nice way of getting product owners and developers to talk to each other?

At least that’s what I think at the current state of my exploration of the world of Given-When-Then.

It comes down to trust and boredom:

Feature: Our new application

Scenario: Users use the system
Given that we want this application to work well
And that there are requirements
When you build it
Then it should meet the requirements
And delight users.

This is the ultimate trust: The spec is short and sweet. It lacks specifics, but there is hope that the CEO will not get bored when reading it: The buck stops with her if requirements are not met and users are not delighted. Technical detail for which she has no time is omitted. Actionable success criteria are at least outlined (“Ask Larry if we’re delighting users yet. Have Malcolm’s folks see if we are meeting requirements.”)

Unfortunately, it’s not very helpful. So let’s look at paranoia instead:

Feature: Create Bus Stop
    We need to be able to enter bus stops into the
    system     so we can have busses arriving at them. 
    There must be no duplicate bus stop numbers and 
    no two stops must be in the same place.

Scenario: Bus stop creation succeeds
    Given there are the following existing bus stops:

        | Bus Stop     | Latitude   | Longitude   |
        | 12111 | 49 20' 0'' | 122 1' 23'' |

    And I enter bus stop no. 44444, lat. 50 1' 12'', long. 122 23' 02'' into the 'Create Stop' form
    When I click 'Create'
    Then the stop with no. 44444, lat. 50 1' 12'', long. 122 23' 02'' is in the list of bus stops. 

Scenario: Cannot create a stop if the stop number already exists
    Given there are the following existing bus stops:

        | Bus Stop     | Latitude   | Longitude   |
        | 12111 | 49 20' 0'' | 122 1' 23'' |

    And I enter bus stop no. 12111, lat. 50 1' 12'', long. 122 23' 02'' into the 'Create Stop' form
    When I click 'Create'
    Then the error message "A stop with this number already exists." appears.
    And the stop with no. 12111, lat. 50 1' 12'', long. 122 23' 02'' is not in the list of bus stops.

Scenario: Cannot create a stop if the stop is in the same location as an existing stop
    Given there are the following existing bus stops:

        | Bus Stop     | Latitude   | Longitude   |
        | 12111 | 49 20' 0'' | 122 1' 23'' |

    And I enter bus stop no. 10000, lat. 49 20' 0'', long. 122 1' 23'' into the 'Create Stop' form
    When I click 'Create'
    Then the error message "A stop already exists in this location." appears.
    And the stop with no. 12111, lat. 50 1' 12'', long. 122 23' 02'' is not in the list of bus stops.

This is great for testers:

  • It’s easy to add new tests which re-use existing step definitions. For example, setting up test data for new scenarios with “Given there are the following bus stops” is straightforward.
  • Lots of parameters are available to write edge test cases. What happens if I enter bus stop no.  –9999999999999999999, lat.  5000 –12’ 0;;, long. 0 0’ 0’’? We can find out – plenty of opportunity to add scenarios without the need for a whole lot of step definition coding.

Unfortunately, it’s boring and obscure:

  • Too much detail. Who has the time? Come to the point.
  • How can I tell how this fits into the big picture? Are we missing something?
  • It’s repetitive and makes your eyes glaze over.
  • Ze Inglisch kann be bat.  “Given there are the following existing bus stops”, followed by a table of only one?

Alternatively, one might tell a story:

Feature: Bus stop creation
    We need to be able to enter bus stops into the
    system so we can have busses arriving at them. 
    There must be no duplicate bus stop numbers and 
    no two stops must be in the same place.

Scenario: Successful bus stop creation
    Given that I enter a bus stop number and location
    And the bus stop number doesn't exist yet
    And there is no other bus stop in the same location
    When I try to create the bus stop
    Then the bus stop should appear in the list of stops.

Scenario: Bus stop number already exists
    Given that I enter a bus stop number and location
    But the bus stop number already exists
    When I try to create the bus stop
    Then an error message appears
    And the bus stop is not created.

Scenario: A Bus stop already exists in this location
    Given that I enter a bus stop number and location
    But there is already a bus stop in this location
    When I try to create the bus stop
    Then an error message appears
    And the bus stop is not created.

Testers won’t be happy:

  • Not possible to write comprehensive tests without new step definition code.
  • Too much ambiguity. What exactly is a “location”?

But it’s less boring:

  • It’s possible to read it like a story about what the system can do and what rules it has, without excessive repetition which obscures the big picture requirements and business value.

So what is the point of the story if it doesn’t give us decent tests? From “The Cucumber Book”:

“Cucumber might just seem like a testing tool, but at its heart it’s really a collaboration tool.”

For example:

“Looks like we’ve got the the requirement of no two bus stops  in the same location covered. I just thought of it – what if somebody enters a stop which is very close to an existing one?”

“Hmm. Let me have a look how we implemented that. Here it is – We check for an exact match in latitude and longitude:”

[Given(@"there is already a bus stop in this location")]
public void GivenThereIsAlreadyABusStopInThisLocation()
{
    CreateBusStopInSameLocationAs(BusStopDataEnteredByUser());            
}

private void CreateBusStopInSameLocationAs(BusStop busStop)
{
    const string stopNumberWhichDoesntExistYet = "99999";
    var existingStop = new BusStop()
        {
            StopNumber = stopNumberWhichDoesntExistYet,
            LatDegrees = busStop.LatDegrees,
            LatMinutes = busStop.LatMinutes,
            LongDegrees = busStop.LongDegrees,
            LongMinutes = busStop.LongMinutes
        };
    _busStopController.Create(existingStop);
}

“Could we change that so that  we can’t have a second bus stop within 30 meters of an existing one?”

“OK…”

Arguably, this conversation might not have happened without the story. We are collaborating more because the story is told in a way that’s accessible to all participants:

The Given-When-Then story is executable documentation, accessible to non-technical stakeholders as a means of seeing what the application can and cannot do.

The tests exercise the code, telling the  “how we do it” part of the story: Click this button, fill in that field, call the method, …

The Step Definitions (… or fixtures, etc.) could be seen as a way of telling how developers interpreted the story. That’s the part I could never figure out before: They aren’t a specification. They aren’t tests. They sort of glue the specification and the tests together, but the usual reason why they need to change seems odd: They need to be modified because either the story or the underlying tests changed. Why did they change? Presumably it was because:

  • Product owners changed the story of what the system can do in the Given-When-Then specification.
  • Developers changed the way they interpreted the specification: They renamed classes/methods/variables, they changed method signatures or behaviours, etc.

In other words, the domain language evolved. New concepts were added to the ubiquitous language, existing ones were better understood or changed.

From a collaboration standpoint, “step definitions” could be seen as an interpretation layer, a  “We Thought You Meant…”

Given readable code, consistent levels of abstraction and good naming developers and product owners might look at this and get a better understanding of  what is being built.

The value compared to having requirement docs in Word and just doing TDD style tests comes from relating requirements to implementation in a way which is accessible to business stakeholders, encourages conversation and is executable at the same time:

  • Given-when-then (What)
  • Step definitions  (“… Thought you meant…”)
  • Tests (How)

Anyway, a story about stories. Given less boredom and more trust when we build the app then we’ll get better software?

April 2, 2012 at 6:31 am 2 comments

If Cars Were Software

Coupling & Cohesion: “We installed your new radio. The tuner is in the trunk, we put the amplifier in the glove compartment and integrated the CD player with the carburetor.”

Single Responsibility: “Yes, that’s by design. The power windows go up and down as you press the accelerator.”

Open-Closed Principle: “To install your ski rack, let us begin by rebuilding the roof.”

Liskov Substitution: “It looks like a timing belt but behaves like a seat belt.”

Interface Segregation: “The lever to the right of the wheel indicates, switches wipers on or off, opens the trunk, controls A/C temperature and now let me show you  how you use it to input destination addresses for the GPS …”

Dependency Inversion: “I’m sorry – we can’t replace the battery. The headlights will only work with this particular brand.”

Consistent levels of abstraction: “By rotating, the pinion engages the teeth on the rack, thus translating rotational motion into linear motion which results in changing the angle of the front wheels relative to the back wheels. This is how you go left or right by turning the steering wheel.”

November 9, 2011 at 7:44 am Leave a comment

The Geek Factor: Why They Aren’t Buying Your Agile And How To Make Them Love It

Gave this presentation at this year’s Agile Vancouver conference.   Thank you everybody who attended – much food for thought and ideas in the discussions afterwards. The slides can be found at http://www.slideshare.net/rreppel/why-theyarentbuyingyouragileandhowtomakethemloveit .

If Agile works, why isn’t everyone doing it? Or, as Agile has become fashionable of late, why all the lip service without the expected amount of real change? This talk makes the argument that it comes down to trust and presents tools and examples for building and keeping trust. The focus is on how to project plan and design applications in a way which, wherever possible, avoids putting stakeholders into situations which require trust in the first place.

In a nutshell:

  • Own your stack. If possible, use one co-located team per bounded context and architect systems in a way which allows developers to easily write end-to-end tests and do releases.
  • Make sure you and your stakeholders have a shared definition of what success looks like. Are you measuring the same things?  For example:  “Diligence in planning” vs. “Adaptability when responding to new knowledge”:  In light of the former, finding something unplanned-for is failure. For the latter, it’s learning and success is measured by how well the new knowledge is assimilated.

November 7, 2011 at 7:24 am Leave a comment

Making commitments: Meeting deadlines vs. maximizing throughput

For those of us who build software, being able to make commitments to business stakeholders is hinging on our ability to deliver features fast enough to enable the business to react quickly to new opportunities and changed market conditions.

And yet – in more than two decades in the industry practically every single project I have ever been involved in was optimizing for adherence to schedule (using waterfall, scrum, “Agile”, whatever, it doesn’t matter) instead of optimizing to maximize throughput.

Where is the disconnect? What am I smoking?

August 21, 2011 at 7:12 am Leave a comment

LiskovCheck: Semi-Automatic Liskov Substitution Principle Adherence Check

LiskovCheck.exe is a command line utility which scans .NET assemblies for inheritance relationships and lists them in English sentences such as (from nunit.framework.dll):

  • “It looks like a LessThanConstraint and behaves like a ComparisonConstraint.”
  • “It looks like an AssertionHelper and behaves like a ConstraintFactory”.

The first sentence sounds about right, but the second one raises eyebrows: One could swap things and say “It looks like a ComparisonConstraint and behaves like a LessThanConstraint.”  However, “It looks like a ConstraintFactory and behaves like an AssertionHelper” makes less sense. (Disclaimer: I haven’t looked at the nunit source – no idea what this is.)

From LiskovCheck’s SpecFlow acceptance tests:

Feature: Semi-automatic check for adherence to the Liskov Substitution Principle.

Definition of the Liskov Substitution Principle:

“Liskov substitution principle (LSP) is a particular definition of a
subtyping relation, called (strong) behavioral subtyping.”
(from http://en.wikipedia.org/wiki/Liskov_substitution_principle)

…also known as:

“If it looks like a duck, quacks like a duck, but needs batteries – you probably have the wrong abstraction.”
(from http://www.lostechies.com/blogs/derickbailey/archive/2009/02/11/solid-development-principles-in-motivational-pictures.aspx )

Scenario: A subtype is more likely to adhere to the Liskov Substitution Principle.

Given a DLL named Zoo.dll with a “Duck” class which inherits from “Animal”
When I run “liskovcheck Zoo.dll”
Then the words “It looks like a Duck and behaves like an Animal” should be on the screen.

Scenario: A subtype is less likely to adhere to the Liskov Substitution Principle

Given a DLL named Zoo.dll with a “MerganserDuck” class which inherits from “TransistorRadio”
When I run liskovcheck.exe with the argument ‘Zoo.dll'”
Then the words “It looks like a MerganserDuck and behaves like a TransistorRadio” should be on the screen.

The project is on GitHub at https://github.com/robertreppel/LiskovCheck.

To try it out:

  • On https://github.com/robertreppel/LiskovCheck click “Downloads” and download LiskovCheck-0.0.1.zip.
  • Unzip the file.
  • Open a command window in the LiskovCheck-0.0.1 folder and run (e.g.) ‘liskovcheck Ninject.dll’.
  • You may need to “Unblock” a downloaded .dll file  first, by right clicking it, going to “Properties” and selecting “Unblock”.

I wrote LiskovCheck as an excuse to play around with Ninject, SpecFlow and OpenWrap.

For more information, see http://birding.about.com/od/birdprofiles/tp/typesofducks.htm.

 

 

February 13, 2011 at 9:50 pm Leave a comment

Older Posts


Twitter

   @robertreppel