Professional Software Development
Professional Software Development
I talked about some overlooked (and quite new) features of JUnit at JDays in Gotherburg. My presentation was a tour that started with boring example tests, and then proceeded through parameterized tests, theory tests, and generative testing. At the end of this tour, I spoke about fundamental, yet again overlooked, testing techniques such as finding single mode faults and double mode faults, and how these techniques can be combined with parameterized testing and theories. Here are the slides.
In this series of articles, I’ll be discussing the developer profession from different angles. The common denominator is that all articles will, in one way or another, be about professionalism. This first article is about the different factors and decisions behind every single line of code.
A while ago I spoke to a friend who is pretty much a professional singer. He explained singing to me in a very passionate way, saying that singing is like solving multiple parallel equations in real time. He told me that it’s quite obvious that every singer has to follow notes. What’s less obvious is that the singer also takes a multitude of micro decisions during every second of his/hers singing. He told me about tempo, intensity, interpretation of the composer, matching the expectations of the audience, synchronization with other singers, following the Kapellmeister, and a bunch of other factors. I was quite impressed.
A second later it struck me that this goes for programming as well, and I started to list all the equations a developer must solve while writing a single line of code. Here it is!
Idag fick jag gästa SweNug och prata om testbarhet för utvecklare. Presentationen finns på Slideshare.
Tidigare kollade jag om det fanns intresse att hälsa på hos oss på Crisp och utbyta erfarenheter kring TDD. Efter att ett flertal hade visat intresse har vi nu schemalagt eventet till den 6:e maj.
Anmälan är öppen! Ni som visade intresse genom att kommentera det första blogginlägget ombedes att anmäla er via eventets sida.
Om det känns lockande att fördjupa sig inom olika varianter och vinklingar av TDD, säg till, så ordnar vi ett TDD-kvällsevent här på Crisp.
Igår hade jag äran att få gästa SAST Stockholm Q4, där jag fick hålla en presentation om utvecklartestning. Med handen på hjärtat, så blev det lite mycket information på få tidsenheter ibland. Dock brinner jag verkligen för ämnet och vill säga så mycket jag kan.
Efter att ha checkat runt lite, gläds jag åt att många verkade ha fått med sig följande budskap hem:
Utvecklare och testare tänker och talar annorlunda om test. Det är därför viktigt att utbilda varandra.
Sometimes a continuous integration/delivery scenario is more complex than just building a system in a multi-stage pipeline. The system may consist of several subsystems, or just complex components, each of which requires a build pipeline of their own. Once all systems pass through their respective build pipelines they are integrated together and subjected to a joint deployment and further testing. When facing such a scenario, I decided to build the simplest possible thing that would work and get the job done.
What will software development be like in the future? “Agile” as we know it, will not be around, nor will test-driven development, continuous delivery, or BDD-like methodologies. I’ve been pondering this for a while, and based on some observations and a dose of wishful thinking, I’ve arrived at the conclusion above. Do you agree?
After having worked with various legacy codebases one discovers certain recurring traits and patterns. The topic of today is the Custom Exception Hierarchy encountered in Java legacy code. This phenomenon is rather Java-specific because of that language’s checked exceptions.
So what is a Custom Exception Hierarchy? It’s an exception hierarchy, with some strangely named exception at its root, present throughout the entire codebase and used everywhere. The author(s) of such hierarchy obviously felt that exceptions like
IllegalArgumentException, or the like weren’t sufficient for the sophisticated needs of their application, so they came up with a better suited hierarchy of checked exceptions.
A while ago I was asked to become one of the Swedish country ambassadors for the Agile Testing Days 2012 conference. I said yes, because I think it’s a great conference. As country ambassador, I help in promoting the conference. I chose to do it, because I think it’s a good conference and I already recommend it to my friends.
read more »
Jag har precis lagt upp min första kurs här på Crisp – Testning av webbapplikationer med Selenium WebDriver. I detta blogginlägg tänkte jag förklara lite mer ingående vad kursen är tänkt att lära ut. Mina kolleger har också kommit med värdefull feedback och frågor som säkert kan dyka upp igen.
read more »
I gave a presentation called ”Being good at waiting – Using Selenium to test Ajax-intensive pages” in an unconf session at the Selenium Conference in London.
The audience was great! Thanks everybody! I certainly didn’t know everything there’s to know about the subject, and that resulted in an interactive session where people from the audience would share their experience and answer some questions. That was so cool
read more »
Surprisingly often an organization exposes itself to a multitude of risks by not knowing enough about its systems, infrastructure, and applications. This doesn’t manifest itself as a lack of “enterprise architecture” documents (while some could help). The implications are far more down-to-earth. Does any of this sound familiar?
I had a conversation with some of my colleagues about what makes a good daily stand-up, here are some properties:
* The team has dumbells by the scrum board. The rule is that if you feel the current speaker is monopolizing the meeting, you can hand the speaker a dumbell. Now the speaker can keep talking only as long as they can hold up the dumbbell with an outstretched arm.
As developers feel the daily pressure to deliver, they tend to skip a crucial step in the process: learning and understanding the system. There’s a huge difference between just adding more lines of code to the codebase and making changes that maintain the conceptual integrity of the system.
Horizontal development is the result of not spending enough time learning and understanding the system you’re working on. By starting to churn out code too soon, you’ll inevitably be adding silos of functionality in parallel to existing functionality.
The outcome is legacy code. It doesn’t matter how well factored it is, and what test coverage it has!
If you do TDD or write unit tests you soon start to feel reluctant about parameters and scalar data types. Why?
Consider the function below. Is it easy to test? Would it be created if TDD were used?
bool result = f(int p1, long p2, Object p3);
Pretend that the function above lives in a business layer and determines whether a customer can get a discount a particular month given a set of conditions embodied in the object
otherConditions. Thus the above could be rewritten as:
bool eligibleForDiscount = canCustomerGetDiscount(int month, long customerNumber, Object otherConditions);
Without thinking about it, we would most likely refactor it by introducing types for month and customer number. This would save us from cluttering the first lines of the function with code related to checking the validity of those parameters. Some people would call this object-oriented programming, others would stretch as far as calling it domain-driven design. Irrespectively of the term chosen, the function above would most likely be refactored into something like:
bool eligibleForDiscount = canCustomerGetDiscount(Month month, CustomerNumber customerNumber, Object otherConditions);
While at it, we would probably discover that this code needs to live in a context, and we would place it in a class that handles business rules related to discounts. That class, whatever its name and function, would assume the responsibility of handling discounts, which would make the
otherConditions parameter unnecessary. Of course this parameter was never actually an
Object, rather another class in the business domain. However, I didn’t want to complicate the example.
= discountManager.canCustomerGetDiscount(Month month, CustomerNumber customerNumber);
At this point we could feel quite happy about the function.
DiscountManager’s only responsibility seems to be handling discounts, while validation and domain-compliance are handled in
But what did we actually do to make this happen? Is there a way to formalize these refactorings?
It turns out there is, although we have to borrow a definition from the testing domain.
I came across an article that mentions quite an interesting metric: The Domain-to-Range Ratio. It’s defined as the cardinality of the domain of the specification over the cardinality of the range:
DRR = |D| / |R|
Without being too formal about it, we can say that the lower the DRR, the better. For example:
|D| = cardinality of a 32-bit integer type, |R| cardinality of a 1-bit boolean type, which would produce a function like f(int32) → bool
Is that testable? How many unit tests do you need to make sure that the function behaves correctly? One, ten, or 232?
Returning to the discount function, we see that its DRR would be a scalar product of cardinalities in the magnitude of 232, 264, and the combined DRR of all members of
otherConditions that are queried by the function.
While it’s not apparent how complex the condition object actually is (it could be as simple as a boolean flag), we see that introducing a
Month class reduces the cardinality of the first parameter from 232 to 12, and that introducing a
CustomerNumber class at least halves the cardinality of the second, as customer numbers are most likely not negative.
In this light, we see that refactorings like:
Scalar → enum, Scalar → object, Remove parameter, start making sense in a formal sort of way.
It also happens that such refactorings make the code object-oriented…