Thursday, December 22, 2022

DDD - My Understanding

 (Start any project with event storming. If you don’t know what is event storming, look at the later part of the blog, or there are tons of material out there in internet)

Talk to domain expert and understand the domain well. Translate that into the code. The domain code should reflect the real world domain. Functions, classes, objects, properties should have same names that are used in the real world, by the domain experts.

In business, when a same name is used in different places to denote different things, (ex: accounts in banking, policy in insurance, warrant/case in criminal justice) please follow the below points
The different places in which the same name are used might be a different context. Which had to separated as separate module/package/namespace/service.
Make it a point to discuss this with the domain expert and only after agreement, introduce specific names (which had to be adopted in the real world too)
Don’t shy away from picking up those discussions. (Else you are not doing DDD)

An aggregate (loosely treat this as module/package/namespace/service) is a one or more entities, (entities are things/people/actions uniquely identified by id), along with value objects. Entities belongs to this aggregate while value objects  belong to different aggregate or context. We cannot/should not modify Value Objects. An aggregate should contain entities that are to be in sync for them to be valid business wise. Ex: in a tablet strip while last tablet is taken out, the tablet strip should be treated as an empty strip. While that said, try keeping an aggregate small. Before moving an entity into a different aggregate validate with business, if it is okey to daly (and also the duration of the delay) before the system becomes valid business wise. Ex: is it okay to place an order for a new strip of tablet with in another hour when a tablet strip gets empty.

Use domain events as message to be broadcasted to the other aggregates for them to act upon. Ex: “Tablet strip is emptied”, “Tablet had expired”.

Event Storming is a beautiful way to get started with this. Bring the whole team both dev and domain experts to gather into a room. Give the domain experts orange stickies and ask them to write down the events that happen in their business. One event per sticky. Events to be ordered in in time series in which they happen. The dev team should ask question on things that they don’t understand.

If you are lazy to pick a book and ready, I would highly recommend, workshops, enjoyable way to understand DDD.

Sandeep Jagtap's

https://learning.oreilly.com/live-events/domain-driven-design-boot-camp/0636920072004

Andrew Harmel-Law's

https://learning.oreilly.com/live-events/domain-driven-design-first-steps/0636920436867

This one will also highly recommended, for you understand the tech terms of DDD, though he may sound dry, he had covered breadth and some depth well.

Vaughn Vernon's

https://learning.oreilly.com/videos/domain-driven-design-distilled/9780134593449/

 

The last one, this to sounded simple.

Amichai Mantinband's

https://www.youtube.com/playlist?list=PLzYkqgWkHPKDpXETRRsFv2F9ht6XdAF3v

Thursday, September 12, 2013

say no to "common'ers"

let's take a bet. I say your test suite have any of the following as name of the class, file or folder
  • Common*
  • Helper*
  • Generic*
  • Utils
Gotcha! And if I were true, then you are heading your suite to a death march.

I would relate any such "file or folder"  to a lazy bachelor's apartment table or shelf. That is where we can though whatever we want to through, it will happily hold it. If you want to find something you would spend lot time in searching for it, and you may or may not find it. And that would make the place look messy.

Let's take an example. Assume we have file read and file write operation in multiple places in our project. We would extract these operations into methods. Rather than placing these methods in class/file with generic name (called, "HelperMethods" or "CommonOperations") put them into a class or file with more specific name (called "TextFile").
In the place where you use it, it would look elegant.In our case the choice is obvious.
  • HelperMethods.CreateFile() 
  • TextFile.Create()
If someone new in the team wants to use a text file related operation, the chances are more that he/she would use this method. Also if they introduce a related methods, say 'delete' in our case, they will be in ease in choosing where to put the method.

Let's go back to our test suites and clean them if they have any "common'ers". Read through the methods, group the related methods and move then into a new file/class with name more specific, unique and meaningful for the group of methods.
Even if it means having a single method in a class, lets go ahead and do it. Rather than having unrelated methods in a single class/file, making the whole the place messy let's have classes with single methods which will be more meaningful.

Tuesday, August 20, 2013

confused on choosing test suite's language?

confused on choosing test suite's language? the K.I.S.S. answer is, let your test suite be in same language/environment as of the application. If there are multiple language used if the application, then choose a language that is used to define your application's models and their builders.

And the long answer...
Recently I came across a project where application was written in Java and the test suite was in Ruby. The reason for the choice of test suite’s language was that the tester in the team was conformable with Ruby, and the 'team felt that' it would be quicker to develop tests in Ruby.

Given the same scenario, if I were the tester I would have chose otherwise. Yes I would have faced difficulty in setting the initial framework in Java, since I would be less familiar with the language, and my churn of initial set of stories would be less.

Let me explain why I would have chosen the difficult path (though at the face it looks so, let me argue it is the other way). Below I would compare the various aspects and their effort with the test suite is in Ruby and the application is Java against both test suite and application in same language.

When application is in Java and if tests are in Ruby and if tests are in Java
To set up a development environment, We have to spend effort in setting Java environment (JDK, class path, java_home, maven), and the Ruby environment (RVM, bundle, gem, rake ...). And the pain would be two fold considering the ground difficulties  (it work in that machine, and not in this machine) All the effort spent/confusion in setting a new environment is saved
Setting test execution Configure and set up test execution form scratch, I my experience though are familiar with a language every time new set of issues will be waiting for us to solve Happily reuse the configuration and execution scripts developed for unit/integration tests done by developers
Setting CI pipe line Every time you set a new box for your regression suite, same story as development environment will repeat here Sit back and relax, if your app work test would work
IDE Multiple ones, and do consider the cost associated with them :)
Maintenance Once you happily handover the project to the client, the poor guy have to find a person who is good with both the languages to maintain the code base Skills is narrowed to a single language
If you choose to ignore all the above argument, here is a lethal one.
Test Data Set up Whatever the approach you choose to use,
  • be it writing your own model to match the application and builders (like factory girl) with that
  • be reverse engineering the DB
  • parsing the migration scripts
  • using bridge (like jruby or ironruby) to use developer builders
It would involve a heavy effort. Most likely it would turn dirty as we run behind to chase and match all the changes happening in your application model and their relations
go ahead and use builders developed for unit/integration tests

Irrespective of the languages (Java and Ruby) used in above argument, the issues remains same for any combination of languages.

Tuesday, August 13, 2013

layering your tests

When ever my wife leaves our house alone to me for a week or so, things start piling around. Cloths will be lying on the floor left exactly where I took then off, sink will be full, layer of dust in the floor, mobile/laptop/tablets/purse/keys hidden under pillow/bed sheets/pillow/shoes!!....

So when I look around for a nail cutter, obviously I'll not be able to locate it. After enough googling around my house, I'll go buy a new a nail cutter, which would eventually get lost into those black holes in my house.

My wife comes back, scolds me for the mess I created, make me slog with her in cleaning it. Oops she finds the extra nail cutter, give an other round of bash. I end up buying some gifts in consoling her.

Moral of the story: Keep thing organised, though it takes an extra effort at first place, so you can avoid
  • living along with the mess
  • search for thing you want
  • investing (cost/time) on getting some thing that you have already
  • cost/time spent on cleaning
  • penalty we pay for creating the mess
  • and mostly importantly, those bitter moments in life.

Enough of my story, coming to work, in an automation code base, if we put things where ever we want, we will end up repeating my story at house.
 
For example, if you are writing a function to delete a file if it exist and create a new one. And it part of some test and it is not abstracted into proper class and method. When your team mate wants same function, he/she would google to find how to implement the functionality, and may do in a different way than yours, since they will not be able to see that this already exist.
 
There are multiple reasons why this mess gets created
  • Test suite is not organised enough
  • Though with a good framework in place, lake of discipline, awareness or skill level.
The ways in which we can avoid such mess are
  • Create modules/projects/namespace that does a specific work. Like tests(will hold your tests), application (operation in a application like login, create user), file operations, test tool(implements button click, type text, select option, drag drop). "Page Object Model" is a good starting point
  • Define contracts between the modules. Ex. test tool module should only be used in application module and not in tests. In other words button click in your test class is wrong, they should be in your application module.
  • Educate you team about the structures. Pair with them in writing few test, so they would learn.
  • Use custom checks as part of your build to find module leakages and if found fail the build. Ex, use a parser to find if there are any button click in you test class, and if found fail the build

more to come...


Monday, August 12, 2013

hate random test failures

Here was the scenario that I was facing, and I hope most of you would be facing this. Your regression build will always fail due some random test failure. When you try to rerun the test locally (or in the build machine itself) it would pass. Every time you would have spent an hour or two in setting up things and rerunning the failed test, finding no real defect.

Over a period of time, a dirty fact that "Failing build is due to random test failure, (and not because of application issue)" will get registered in your mind and in your team's mind.
When a real application defects comes in, the tests would fail, alas we would mistake it for random failure.

I would give you a rough numbers form one of my projects that suffered with this issue. On a high level there were 400 tests. out of which only 150 were passing. On a deeper analysis we found
  • 60 failing tests were tests for out dated application features
  • 84 tests failing due to application defects. (totally 14 defects)
  • Others were real test issue.
The test suite failed to capture the application defect, which was it's only responsibility. It needs hell a lot of maintenance in removing tests for outdated features and find which tests are failing for genuine reason and which are not. Hence that would make sense if I would say, value of failing test suite is zero.Hence effort spent in adding new test on it will as well be waste, with out fixing the current failing tests.

The following would be quick (and some what dirty) fix for the above issue.Create a downstream project, that would pick the failed test run them alone, once the your regression tests run gets completed. Chances are more that a random test will pass in a another run, ( In fact, in one of my project all the random test pass here ). So the downstream project will be your indicator on your test suite sanity.
This gives you some breathing time find the real issue behind the random failing tests and fixing it.

The following might be the reason behind the randomness,
  • The timing issue, like waiting for a page/control to load/disappear. Please don't add blind sleep. Make a feature in your framework to wait for a condition, and mention what exact condition to wait for.
  • Application behaviour. There are time when your application itself behave randomly. Having screen shots for failing tests would help you pin such issues.
  • Random generators used for the test data. There is a practice of creating test data randomly. Avoid this. If you rely on random data to find a defect, chances are that it may not occur at all.