Thursday, November 20, 2014

Some thoughts about BDD

Bob asked me about BDD.
"Behavioral Driven Design?" said I.
"Well... something like that... maybe..." he announced knowingly.
"I met it once" I stuttered.
"Think about it!" said our leader, and vanished in a puff of smoke.

So I thought about it.

The first problem I have with "Behavior Driven Development" is the name itself. Every time someone say it, I get confused. Its' a paradox. Like Military Intelligence.
Behavior is something you observe. A software behavior is driven by the way it was developed. Not the other way around. When I hear "BDD" I think that I need to develop something to behave in some way that will drive me to develop something. Then I must breath into a paper bag.

Of course, what was actually MEANT is that someone will say how he wants the system to behave, and then the developer will do it. Which is actually what software development is all about, and I'm pretty sure it worked that way before 2006.

So what is the difference? The Givenwhenthen.

The Givenwhenthen is a magical creature. It have the head of a business-spec with the body of a unit-test, and the legs of a DSL. When you look at some of the frameworks developed to run it, be it a wiki with a "Test" button, or one of the cucumis sativus family, you get the feeling that what was given when Dan North spoke is much bigger then the product it drives.

Don't get me wrong, I'm all for providing automated tests that describe the business requirements. I'm a big believer in TDD and ATDD. I also really like detailed business requirements. I just think that maintaining a specialized client just to write unit/integration tests is a nuisance more then a benefit.

A business analyst think of requirements in terms of acceptance details. In his mind he sees client application the end-user operates, and devise the best way this app will provide the business needs. He think about reports, and what kind of information should be there. He creates elaborated excel to verify the system actually works. He listen to clients request and decipher what they actually need.

What a BA do not do is write code. And Givenwhenthen is code. Not because it must follow a syntax to fit a parser (which it does), and not because it does not work without writing code that gives it meaning (like most requirements) - it is because only a developer can write, modify and maintain it.

I was there. In the BDD zone. Writing structured semi-formal artifacts to represent behavior, and then writing adapters to pass it a quasi-business-model, that we hooked to the actual system, that was so far from the test at that point that you could never understand why it was red. At some point we just gave up. The effort was so big, we decided to spend it on developing the product itself. And the BA people never even looked at it. So we went back to TDD, and ATDD and integration tests.

So yes. We are doing BDD now. Only it looks just like a unit test, and we call it integration. And when it is done right, it represent the expected behavior, and give a good hint of the requirements... and here is my last reservation.

BDD worries me because it emphasize behavior over requirements. And behavior changes from one client to another, even if it actually uses the same set of services. The FAEMA Enova allow dosed delivery programming, while the ZjNac F305 supply 7 premixed drinks. But both uses the same water measurement service. Because both need to handle the water volume for different behaviors.



If BA will start writing unit-tests, we'll be in a worse place then we where when Dan North presented the TDD challenge. The BA will have to ask themselves all these TDD questions, and might miss out on the Developer to Business-Expert dialog completely.

And then we can kiss DDD goodbye.

Sunday, November 16, 2014

Highly anticipated unexpected announcement

Our development group leader scheduled a meeting on a short notice. The summoned participants included what is considered in our department the "best-of-the-best", strongest, fastest and most-likely-to-suckseed. Oh yes, and me.

I am a code-developer.
At least it is implied from my linked-in profile.
What it actually say is: "Team Leader in Coffeex", which is not true.

For one, I am not a team leader. I am the worst leader I ever met. The last time I lead a team it was made out of 2 other people, that resigned 2 weeks after the team was created. I suspect it was that, or suicide, so at least it means there is an alternative to me.

Second fact is that "Coffeex" do not exist anymore. It was bought in a multimillion transaction about a year ago. How many millions (you may ask)? Lots. More then ten, less then a million. Who bought us (you may ask {you are a bit of a nuisance})? Non other then the well known, mighty, multi-everything cooperative: "NCM United". Who the hell is that (you may ask again - stretching my patience very thin)? Google it!

"NCM United", originally "National Coffee Machines", is an American based coffee-machines, hot-beverages-automation and brewing-software company. Its' main strength is in the hardware area, but it wanted to expend it's software market, especially these days that you can pour fresh cappuccino strait out of your iPhone 8.

Coffeex developed one of the most advanced coffee making software in the world (or at least - the most complicated one). NCM wrote an 8 zeros check, and now it had the most advanced coffee making software etc.
In the 15 month that passed since the deal, NCM did everything it can to kill the software it paid so much to acquire. Moving customers from the Coffeex solution to outdated vending machines, reducing the product range to a minimum, and limiting the new project bids to... well, zero.

And after all this, we arrive to the present day, when we were all sitting around, doing pretty much nothing, waiting for the final closure announcement, that this meeting happened.

Bob (that is our group leader) entered the meeting room, hung a "do not disturb" sign on the door, and locked it. After sweeping for bugs, he made his statement:

"Gentleman.
"I am here to tell you about the most recent decision made by the all mighty NCM management on the other side of the world.
"After this weekend the Coffeex software is no more. You few chosen ones will replace it with a brand new software. A better software. A faster software. A software better suited for today's xanthine alkaloid consumption needs.
"You have 48 hours to decide if you want to be part of this vague and shapeless endeavor, or stay behind working on the crumbling remains of the old, stale and insignificant working product.
"This project, should you decide to accept it, is top secret, and should not be mentioned by any of you for the next 120 minutes.
"This message will self-destruct in five seconds."

. . .

This was the introduction to what is going to be (probably) the most mundane and expected NCM project, known now only by its' code name: NEMO.
My next post will give the details of this initial meeting, that I cannot disclose at the moment, for it is only an hour and a half since it began.



Monday, May 26, 2008

Why not use doFactory

I was looking at the doFactory, that is a framework built to implement design-patterns defined by "Gang-of-Four" in 1995. Other people also looked at it, and suggested to use it. So I'm posting here my thoughts about it:

  • I did not like the GoF implementation to start with. It is old-fashion, very ".NET 1.0" in code design, and super-complicated in some cases.
  • In more then one case the code do not give the actual essence of the relevant pattern (see Command pattern), what can lead to misunderstandings. Just to give you a general idea, look at http://sourcemaking.com/design-patterns-and-tips and see how deferent approach to design pattern introduction make them clearer to understand.
  • The 23 patterns that GoF introduce might still be valid today, but are a bit academic as far as implementing them. A lot of them are part of the programming language, like: iterator (foreach), visitor (extension methods), observer (delegate), strategy (well… delegate) and template-method (simply abstract-class). Others are implemented in few lines of code (singleton), or available for usage in some domains (i.e. StreamReader implements decorator for Stream, and interop is an adaptor for COM objects). See this article for more details. There are also some patterns that are better implemented by means other then POCO, like decorator and proxy that are better implemented using AOP.
  • The GoF patterns are just the basic object-oriented patterns. A lot of application-architecture patterns are not covered by GoF. Some of them are at the enterprise level (like MVC), but some are just modern OO approach (like IoC and ORM). Frameworks other then the doFactory answer these patterns better.


In any case, I did not see how exactly the doFactory looks like, but as far as I understand it is not very promising. If any of you have a copy of the doFactory for me to look at, I would not refuse.

Monday, March 3, 2008

The Curious Incident of the Disappearing-Item in Production-time

This is a blog from 2008 that I wanted to preserve, so I copied it here. It refers a retail solution, and I only changed it a bit to remove specific customer or company names. (It is actually published in this blog on February 2016).

Background:


When our customer was moving to version 4.7.7, and installing it widely, a new and weird bug appeared.
Every now and again, all the POSs in one of the store servers, gave "Item Not Found" for each scan, save the first one.
There was no specific Server or Store or Time that could be blamed for this behavior. It happened in most stores, although it did not happen again in the same store.
To resolve it, you could use IIS-Reset, or Clear-Persistence, or client-restart or all of the above, or none. No apparent pattern could be found in the reason for the bug or the method to resolve it. Actually it looked like it resolved itself after some time...

Working the Bug:

 
The information we did have, was system logs that included a "ItemDataCartridge is NULL" log line for every incident, but nothing else.

To solve the problem, I worked my way very carefully through the code, noting every situation that might cause this specific behavior, Namely: Producing ONLY the mentioned log, and return "ItemNotOnFile" ResultCode.
 
After a while, I found an "IsValid" property in the PID (PosItemData) that was called each time this object was retrieved from the items cache list. Because it was called even when it should not have, it was evident that if it returned false each time, the result behavior will be the same as the bug.

I looked into this "IsValid" implementation, and this is (more or less) what I saw:
 
 
  get{ ... return expired > System.Environment.TickCount; }  
 
 
So I looked into the place "expired" is set, and saw:
 
 
  expired = System.Environment.TickCount + ActiveTimeout; 
 
 
Looks suspicious?  I thought so.

"TickCount", as far as I remembered, is an Int32. Int32 have a max value, that when you add positive int to it, becomes negative. When that happens, the "IsValid" will always return false, and Bob's Your Uncle!

So what I did now, and pay close attention because this is the whole trick, is placed the cursor (a.k.a. bin) between the "System.Environment.Tic" and the "kCount", and pressed "F1". And for those of you that do not have a working help file, here is the relevant quotes:

"A 32-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started. ...TickCount will increment from zero to Int32.MaxValue for approximately 24.9 days, then jump to Int32.MinValue, which is a negative number..."
 

The Conclusion:

 
The bug was this:

1) ActiveTimeout is an Int32 that equals 24 minutes in milliseconds (1440000).

2) The "expiration" field is calculated for every lookup in the transaction after the first one (for reasons I won't get into right now) as the current TickCount + ActiveTimeout.

3) For this reason, when a POS-Server runs for 24 days and 21 hours and 30 minutes (approximately), adding these 24 minutes to the TickCount value (that is now very close to the "Int32.MaxValue") will ALWAYS result in a negative value.

4) And because, as mentioned before, this calculation is always evaluated (even when the lookup is done through the Database), it will always return false, and the lookup will always fail.
 
The Grand-Total Effect is:
In each store one of the pos servers stop selling after 24.9 days for 24 minutes.
_____________________________________________________________________
 
And one final thing I'd like to point out:

The programmer that wrote this feature originally, declared the "expired" variable as long. This is interesting, because if the calculation was done in a scope of int64, this problem would have never occur. Unfortunately, the actual participants in the calculation where all int32 typed, what means that no meter what type of variant is used to hold the result, the Math is done in an Int32 scope.
 
 
p.s.

This was fixed, basically, by replacing the "TickCount" with "DateTime". This type also have a "MaxValue", but Microsoft operating-systems do not support it.
We might have a problem moving to Linux, though...