Mockist VS "Let architectural layers emerge, don't anticipate them before starting TDD process"

380 views
Skip to first unread message

Michael Azerhad

unread,
Jun 23, 2013, 8:43:50 PM6/23/13
to growing-object-o...@googlegroups.com
Hello,

TDD promotes design emergence.
Thus, it is not advised to anticipate layers in advance (service layers, business layer, dao layer etc...).

At a given time during a TDD refactoring step, design may reveal the need of splitting our code in some main layers (in refactoring part of TDD).
Assuming, we talk about Mockists guys, which enjoy isolating each components by placing needed mocks and verify behaviours thanks to them.
What would the design of layers lead to?  => to rewrite a huge part of unit tests, in order to place appropriate mocks and their expectations (messy no?). Indeed, the whole algorithms would now be splitted into several parts, most of them representing one distinct layer. 
Classist TDD would not really be impacted by this huge refactoring, since their writing style is by far most flexible (like mini-integration test) that a mocking style.

Question is: If I'm about to start a huge project, knowing at 99% that I will need some basic layers (service layer, business layer etc...), shouldn't I write them before starting TDD steps? 
                      Indeed, advantage would be that my first tests would already place necessary mocks about main layers. 

Thanks a lot,

Michael


George Dinwiddie

unread,
Jun 23, 2013, 9:56:18 PM6/23/13
to growing-object-o...@googlegroups.com
Michael,

On 6/23/13 8:43 PM, Michael Azerhad wrote:
> Hello,
>
> TDD promotes design emergence.
> Thus, it is not advised to anticipate layers in advance (service layers,
> business layer, dao layer etc...).

I don't know that you can resist anticipating, but you can resist coding.

>
> At a given time during a TDD refactoring step, design may reveal the
> need of splitting our code in some main layers (in refactoring part of TDD).
> Assuming, we talk about Mockists guys, which enjoy isolating each
> components by placing needed mocks and verify behaviours thanks to them.
> What would the design of layers lead to? => to rewrite a huge part of
> unit tests, in order to place appropriate mocks and their expectations
> (messy no?).

Is this something you're worried about? Or something you've experienced?

In my own experience, the need to rewrite a number of unit tests tells
me I've not been listening to what they've been telling me.

> Indeed, the whole algorithms would now be splitted into
> several parts, most of them representing one distinct layer.
> Classist TDD would not really be impacted by this huge refactoring,
> since their writing style is by far most flexible (like mini-integration
> test) that a mocking style.

Why would a mocking style be different? What would invalidate your
previous tests?

>
> Question is: If I'm about to start a huge project, knowing at 99% that I
> will need some basic layers (service layer, business layer etc...),
> shouldn't I write them before starting TDD steps?
> Indeed, advantage would be that my first tests
> would already place necessary mocks about main layers.

You can do that. I wouldn't call it TDD, though.

- George

--
----------------------------------------------------------------------
* George Dinwiddie * http://blog.gdinwiddie.com
Software Development http://www.idiacomputing.com
Consultant and Coach http://www.agilemaryland.org
----------------------------------------------------------------------

Nat Pryce

unread,
Jun 24, 2013, 1:51:38 AM6/24/13
to growing-object-o...@googlegroups.com
My experience is that mocks do not affect the overhead of splitting a system into modules as it grows, *if I'm doing TDD* and *if I'm doing OO design*. Mocks help me make explicit the protocols between objects. Those protocols are my domain model. If not doing OO (eg when writing procedural or functional code), I don't find mocks useful, because the domain is not modelled as message protocols.

When doing OO I don't think in terms of layers. The fundamental organising principle in OO design is "inside" vs "outside", not "above" vs "below". That is, decide what behaviour belongs inside an object, and what should be performed by a peer of an object. The implementation of an object's behaviour is hidden / encapsulated. Inside an object, it's behaviour will be implemented by objects working together, and those objects themselves have hidden internals. The entire program is an object. So no layers, more like rings within rings within rings.

My experience is that TDD - and in particular refactoring when tests are hard to write - guides the separation of OO code into insides and outsides, simple protocols between injects, and at a larger scale, different domains. I don't end up with things like "DAO" and "service" layers. I do end up with application domain abstractions implemented in terms of underlying technologies, such as a database, HTTP or messaging.

So, my spider sense is tingling when you talk about using mocks *and* organising into layers in the same question. I worry that you're trying to use mocks with an essentially procedural design, for which they are not a good fit.

--Nat
--
 
---
You received this message because you are subscribed to the Google Groups "Growing Object-Oriented Software" group.
To unsubscribe from this group and stop receiving emails from it, send an email to growing-object-oriente...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Michael Azerhad

unread,
Jun 24, 2013, 6:31:43 AM6/24/13
to growing-object-o...@googlegroups.com
Hello George and Nat,

Actually, by reading your answers, I've just realized that the issue I explained, was not relevant with a nice TDD approach :)

I would rephrase my whole observation : Being a mockist brings some test reworks when a mockist realizes that a tested class does not fully follow SRP, and has to proceed to some "extract class" action. In this case, he would have to isolate the initial component from this new extracted class with some mocks (of course, if it makes sense). 
No need, with a classicist TDD approach

Thus, nothing linked with the notion of layers.

Nat, I really adhere to your way of tackling enterprise applications similar to the way of tackling some "tools", like calculator etc... I mean that you treat every object at the same level, communicating by some messages at 99%. (with Tell don't ask philosophy). I even found that by far more closed to the real world.
Therefore, if you have to deal with a DDD-focused application, what would be your TDD procedure? Since you would probably have to deal with some already established layer by others (services, repositories etc...) . Would you start with an outside-in approach, focused on one layer at a time ? (I ask for that since it's my case... ;))

Thanks a lot , anyway :) I really appreciate !

Michael





 
To unsubscribe from this group and stop receiving emails from it, send an email to growing-object-oriented-software+unsubscribe@googlegroups.com.

Nat Pryce

unread,
Jun 24, 2013, 8:13:05 AM6/24/13
to growing-object-o...@googlegroups.com
On 24 June 2013 11:31, Michael Azerhad <michael...@gmail.com> wrote:
I would rephrase my whole observation : Being a mockist brings some test reworks when a mockist realizes that a tested class does not fully follow SRP, and has to proceed to some "extract class" action. In this case, he would have to isolate the initial component from this new extracted class with some mocks (of course, if it makes sense). 
No need, with a classicist TDD approach

I don't find this to be the case with mocks.

Maybe it's because I model the domain in terms of messaging protocols, not classes, and define roles that objects play from the needs of the client.  When I find that a client needs services from another object, I'll introduce a new role or use an existing role.  As it needs new services, I'll either add those to existing roles (if it makes sense) or define new roles, to be played by new objects.  So if I find an SRP violation it's not when a *class* gets too big, but when a new message doesn't match an existing role.

If an object gets too big, I split up its implementation.  Some of the behaviour moves to new objects that I can easily unit test.  The object uses those objects internally.  Outside, it's behaviour appears to be the same.  Internally, there are more objects but the interactions between them are hidden to the rest of the system.  I try to follow a rule of thumb I call "Composite Simpler than the Sum of Its Parts".  That is, wherever you are in the system, objects should have interfaces (encapsulation boundaries) of roughly the the same complexity.

--Nat

--
http://www.natpryce.com

Michael Azerhad

unread,
Jun 24, 2013, 9:05:25 AM6/24/13
to growing-object-o...@googlegroups.com
I think I've figured it out :)

I think my case explained just above leads to broken tests only if I didn't initially discover all the roles that my involved objects would induct before starting writing a test. => Meaning if I have the bad habit to blend non-related roles inside one object as soon as TDD steps start THEN rely on TDD procedure to discover roles further. (bad so)
Of course, in that case, discover one new role later would compel my test to be adapted in order take in account the mocking of my new collaborator. (if I'm still a mockist :))

If I already established the different roles that my SUT would need, mocks would be set up as soon as the first TDD step.

I hope to not misinterpreted your answer ... :)

Thanks,

Michael

Steve Freeman

unread,
Jun 24, 2013, 9:12:03 AM6/24/13
to growing-object-o...@googlegroups.com
On 24 Jun 2013, at 14:05, Michael Azerhad wrote:
> I think my case explained just above leads to broken tests only if I didn't
> initially discover all the roles that my involved objects would induct
> before starting writing a test. => Meaning if I have the bad habit to blend
> non-related roles inside one object as soon as TDD steps start THEN rely on
> TDD procedure to discover roles further. (bad so)
> Of course, in that case, discover one new role later would compel my test
> to be adapted in order take in account the mocking of my new collaborator.
> (if I'm still a mockist :))
>
> If I already established the different roles that my SUT would need, mocks
> would be set up as soon as the first TDD step.

You might be taking too large a step. For me the design question is, "if this succeeded, who would know". That might be an existing collaborator or might require a new one (which might not exist yet). I don't regard changing existing tests as a bad thing, that's part of the thinking process. If I get to a point where a change triggers lots of test changes, that's a clue that my design might be broken.

S

Michael Azerhad

unread,
Jun 24, 2013, 9:24:08 AM6/24/13
to growing-object-o...@googlegroups.com
Hello Steve,

I think we say the same thing.

as soon as the first TDD step.

Maybe I didn't well express my idea. I didn't want to mean:  "find all collaborators for the feature to achieve, BEFORE writing the first test".  
Of course, discovery of collaborators/roles concerns only the current test, and they may be several unit tests to achieving a feature => thus as many discoveries as number of unit tests related to the same feature. 
So I think it is conformed to your sentence: 
 "if this succeeded, who would know"

Michael 

Nat Pryce

unread,
Jun 24, 2013, 9:59:09 AM6/24/13
to growing-object-o...@googlegroups.com
On 24 June 2013 11:31, Michael Azerhad <michael...@gmail.com> wrote:
Nat, I really adhere to your way of tackling enterprise applications similar to the way of tackling some "tools", like calculator etc... I mean that you treat every object at the same level, communicating by some messages at 99%. (with Tell don't ask philosophy). I even found that by far more closed to the real world.
Therefore, if you have to deal with a DDD-focused application, what would be your TDD procedure? Since you would probably have to deal with some already established layer by others (services, repositories etc...) . Would you start with an outside-in approach, focused on one layer at a time ? (I ask for that since it's my case... ;))

 
I think that if the development team is divided by module, and the modules have been "finished" before end-to-end features, then it's going to be hard to apply an iterative/incremental process like TDD.  How can you redesign module interfaces when tests are hard to write?  Or have the simplest design for the current functionality?

But, DDD doesn't imply working module by module.  TDD and DDD are perfectly compatible.  Focus on features, work from edge-to-edge, ensure the system is always running, and refactor to remove duplication and express intent. If DDD-isms remove duplication and express intent they will emerge.  If your team values DDD-isms over other design choices, then they can refactor to create them, supported by the test coverage created by the TDD process.
 
--Nat

--
http://www.natpryce.com

Michael Azerhad

unread,
Jun 24, 2013, 10:39:44 AM6/24/13
to growing-object-o...@googlegroups.com
I will try to really practice TDD without anticipating anything in term of code design, until one is demanded as development progresses.
No more traditional layers, only objects "in the air", well named and with explicit roles (of course, with some packages if necessary for isolation or grouping some related objects) communicating each other by messages. 

I think that would be cool :)

Thanks a lot Nat :)

Michael Azerhad

unread,
Jun 24, 2013, 12:08:58 PM6/24/13
to growing-object-o...@googlegroups.com
On the page 63 of GOOS, you describe the fact that a class name ending with "Impl" is a sign of poor design.
Let's suppose the feature:  a User should be able to be created, updated, deleted, and suspended.

Traditional approach, typically presents in SOA world would be:   "Let's make a UserServices interface with create, update, delete and suspend method, and let's implement it with UserServicesImpl".
I agree, that the term "Impl" doesn't BRING some new information to the code reader. Indeed, it is redundant with the interface name.

If we stop following "SOA-like" habits, what could be an appropriate design? : 
The first solution would be to consider these four actions as 4 roles => 4 interfaces : Creatable, Deletable etc... but it's make no sense...since they would never be referenced distinctly by any client. It's not like the case with the CD player, that can be referenced as a simple Schedulable by client (explained in GOOS). 

Should I rather model these 4 actions, as 4 distinct classes ? :
UserCreator, UserUpdater etc...


Michael

Colin Vipurs

unread,
Jun 24, 2013, 12:20:20 PM6/24/13
to growing-object-o...@googlegroups.com
"The first solution would be to consider these four actions as 4 roles => 4 interfaces : Creatable, Deletable etc... but it's make no sense...since they would never be referenced distinctly by any client"

Why do you say that? I find it more likely that no other piece of code ever needs all 4 pieces of functionality.


--
 
---
You received this message because you are subscribed to the Google Groups "Growing Object-Oriented Software" group.
To unsubscribe from this group and stop receiving emails from it, send an email to growing-object-oriente...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Maybe she awoke to see the roommate's boyfriend swinging from the chandelier wearing a boar's head.

Something which you, I, and everyone else would call "Tuesday", of course.

Michael Azerhad

unread,
Jun 24, 2013, 12:34:03 PM6/24/13
to growing-object-o...@googlegroups.com
Hello Colin,   

I find it more likely that no other piece of code ever needs all 4 pieces of functionality.

Indeed..that's right, I agree. I wanted to outline the fact that those CRUD actions are often considered and grouped as one role.

But, while re-thinking about it, I admit that applying interface segregation here would be good.

Michael :)

To unsubscribe from this group and stop receiving emails from it, send an email to growing-object-oriented-software+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.
 
 

Steve Freeman

unread,
Jun 25, 2013, 6:32:17 AM6/25/13
to growing-object-o...@googlegroups.com
4 roles as interfaces is probably overkill (although not always). The points we were trying to make were

1) can we find a domain term that describes the service? I'm regularly amazed at the power of not calling things XService which highlights features that don't fit. For example, would your example be better called a Registrar (e.g. admin at a university)?

2) The class name should describe the implementation, for example MongoRegistrar

S.

Michael Azerhad

unread,
Jun 25, 2013, 6:49:26 AM6/25/13
to growing-object-o...@googlegroups.com
Hi Steve,

The class name should describe the implementation, for example MongoRegistrar 

Since I'm using a DDD approach, components like services should not be aware of the infrastructure, so ignoring of Mongo usage.
UserService (still misnamed) should not be aware of the implementation of the repositories it uses.
Therefore, I would be Ok with a name like: "UserRegistrar", indeed, why not :)

Using a DDD architecture, let's assume that my service is called "UserRegistrar". 
What about my related domain service?
Indeed, my application service layer (or similar thing if we apply a pure TDD ignoring well-established layered) should not implement business logic (it's just a facade), but has to delegate to another collaborator. (in my case, a domain service).
What about its name?   It would be redundant, and confusing to call it "UserRegistrar" too.
I would think about UserRegistrar as my application service, and distinct roles implemented inside distinct classes like:  UserCreator, UserUpdater etc...
Each method of UserRegistrar would delegate to the relevant role.

Would it be a good choice?

Thanks a lot,     

Michael
Message has been deleted

James Richardson

unread,
Jun 25, 2013, 9:00:04 AM6/25/13
to growing-object-o...@googlegroups.com
Since I'm using a DDD approach, components like services should not be aware of the infrastructure, so ignoring of Mongo usage.
UserService (still misnamed) should not be aware of the implementation of the repositories it uses.
Therefore, I would be Ok with a name like: "UserRegistrar", indeed, why not :)

Well - ok, your "UserService" might use an interface called "UserRegistrar", but the specific implementation it was given at runtime might be "MongoUserRegistrar", or "CsvUserRegistrar", or whatever. _Somebody_ somewhere knows about the implementations...

I wouldn't choose "UserUpdater" etc, because its unlikely that you could mix and match different implementations. A UserCreator that wrote to a flat file wouldn't be able to interoperate with a "UserUpdater" that uses JDBC.

In any case this is where sometimes you might choose to let your implementation choices bleed through. Using something like JPA, the user never needs to be given to a service to be explicity written back to the persistence layer, as the transaction manager will automatically persist the changes to the user back to the database, or forget them, if the tx was rolled back. If you have a naive implementation of something, you might need to call usermanager.save(user) afterwards.....

James








--
 
---
You received this message because you are subscribed to the Google Groups "Growing Object-Oriented Software" group.
To unsubscribe from this group and stop receiving emails from it, send an email to growing-object-oriente...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages