Decoupling my objects/classes?

Decoupling my objects/classes?

Old forum URL: forums.lhotka.net/forums/t/1864.aspx


ianinspain posted on Wednesday, November 29, 2006

Hi there,

after doing some research here, its time to edit my BO and classes to decouple them... but i had some questions that i hope someone can help with..

From what i understand - i should never pass a class from 1 class to another as this can cause many things to break if i change one of the classes...

Does this also go for controls i.e. textboxes, checkboxes etc... should never pass in a control to a class ... otherwise it becomes coupled?

so i presume the only thing that is valid is passing in what?? simple types like string, int, what else??

So if i required to update a grid control, the right way would be to NOT pass in the grid control to a class but to use events and populate the grid via the UI, the UI would obviously get its information from these events from the class/BO??

I also read some where that you can use Interfaces to decouple?? this i  am a little confused with .. because i presumed an interfaces enforces a class to implement a certain number of methods etc

I really tried searching google for some best practices but could find any hints or tips and what to do...

Any help or information really appreciated...



Ian

malloc1024 replied on Wednesday, November 29, 2006

There is nothing wrong with passing an object to a class.  However, you should keep in mind the OOP principle that states you should program to an interface not an implementation.  This basically states that you should program to interfaces or abstract classes rather than concrete classes when it is prudent to do so.  Keep in mind this is a suggestion not a rule.  You can pass control objects to other classes, but you should not pass the control object to a business object.  The business object should know nothing about the presentation layer. 

ianinspain replied on Tuesday, December 05, 2006

Thanks very much for the reply... i am a little confused with this

"However, you should keep in mind the OOP principle that states you should program to an interface not an implementation."

How would i use a interface or abstract class to decouple my class?

Thanks once agian

Ian

ianinspain replied on Tuesday, December 05, 2006

If i require access to a class from another class then should i build my own implementation of this class in the assembly that requires it?

This sounds good, but there is no code re-use so hence each class/assembly that requires access to this special class would need to hold its own copy of class .... hence there is no code-re-use and duplicate code??

Any ideas?


ajj3085 replied on Tuesday, December 05, 2006

Well, remember that the principal is not a hard and fast rule.  If you are trying to decouple some assemblies, probably what you'll have to do is create an interface in a 3rd assembly, which both those assemblies will reference.  Then your BO in the first assembly will implement the interface, and the class in the second assembly that needs the object will accept somethign which implements the interface, not the concreate class.

DansDreams replied on Tuesday, December 05, 2006

I think we need to keep a pragmatic view of this when considering applying this principle as a general rule just because you should.  I'm building a specific UI solely to interact with a specific business layer built on a specific framework.   The reason for decoupling with interfaces would be so you could "swap" out the underlying layer.  There is precisely zero chance of that IMO, so it's just a waste of effort.

I still use several interfaces, mind you, but it's for when I can't know the specifics in a particular area of functionality.

ajj3085 replied on Tuesday, December 05, 2006

DansDreams:
The reason for decoupling with interfaces would be so you could "swap" out the underlying layer.  There is precisely zero chance of that IMO, so it's just a waste of effort.


I wouldn't go that far; perhaps in your circumstances, but not for everyone.  Especially if the OP has chosen to build seperate assemblies which still must work together.  I have this situtation right now, and having interfaces allows me to test each assembly regardless of whether or not the other assembly is working properly or not.

I do have one case where this isn't true in the testing layer; it directly uses another business assembly, and its been causing me nothing but problems.  When I get more time, I do plan on breaking that dependancy.  Changing one assembly shouldn't cause me to change the testing assembly for another different assembly.

Andy

DansDreams replied on Tuesday, December 05, 2006

ajj3085:

I wouldn't go that far; perhaps in your circumstances, but not for everyone.  Especially if the OP has chosen to build seperate assemblies which still must work together.  I have this situtation right now, and having interfaces allows me to test each assembly regardless of whether or not the other assembly is working properly or not.

I do have one case where this isn't true in the testing layer; it directly uses another business assembly, and its been causing me nothing but problems.  When I get more time, I do plan on breaking that dependancy.  Changing one assembly shouldn't cause me to change the testing assembly for another different assembly.

Andy

I was referring to the rather dogmatic adherence to this principle that the OP suggested with words like "always" and "never".  I just think it's silly in a case where a form is built specifically to edit Customer objects which inherit from BusinessBase to add a bunch of interfaces to the mix.  There's zero chance I'll use that form for anything else, so I've gained nothing from the interface.

I'm interested in a little further explanation of your scenario though.  We are all using "separate assemblies which still must work together" by definition because we're building n-tiered applications.  I'm presuming you're meaning multiple assemblies at the same tier, as in two assemblies of business objects.  But what is the test scenario where an interface helps you?  Are you saying you put "dummy" classes in one assembly to represent the classes that would really be found in the other in production so you can stay "local" for testing?

DansDreams replied on Tuesday, December 05, 2006

DansDreams:

I was referring to the rather dogmatic adherence to this principle that the OP suggested with words like "always" and "never".  I just think it's silly in a case where a form is built specifically to edit Customer objects which inherit from BusinessBase to add a bunch of interfaces to the mix.  There's zero chance I'll use that form for anything else, so I've gained nothing from the interface.

I want to clarify that in actual practice I often build forms or controls that have common functionality for dealing with an unknown implementing type.  But I didn't feel that was specifically what the OP was addressing.

ajj3085 replied on Tuesday, December 05, 2006

DansDreams:
I was referring to the rather dogmatic adherence to this principle that the OP suggested with words like "always" and "never".  I just think it's silly in a case where a form is built specifically to edit Customer objects which inherit from BusinessBase to add a bunch of interfaces to the mix.  There's zero chance I'll use that form for anything else, so I've gained nothing from the interface.


Right, which is why I said that OO principal wasn't a hard and fast rule. 

DansDreams:
I'm interested in a little further explanation of your scenario though.  We are all using "separate assemblies which still must work together" by definition because we're building n-tiered applications.  I'm presuming you're meaning multiple assemblies at the same tier, as in two assemblies of business objects.  But what is the test scenario where an interface helps you?  Are you saying you put "dummy" classes in one assembly to represent the classes that would really be found in the other in production so you can stay "local" for testing?

Yes, I have multiple business assemblies.  There are some cases where I need to know the properties of say a Contact, but managing contacts is handled by an external assembly.  Rather than recode the object, I put an interface in a lower level assembly, so my Contact manager assembly has some objects which implement that interface, and my quoting assembly needs to consume that data.

The application works nicely because it can use both assemblies and existing screens to select a contact, and then use that to work with the quoting assembly's objects.  The problem was that in my test assembly for the quoting module, I directly referenced the contact management assembly (much like the application would).  This causes problems in the build, because if a "lower" dependancy and the quoting module builds first, the quoting module will use the old version of the contact module, which is still using the old version of the "lower" assembly. 

In my third (softwaer) assembly, instead of referencing the contacts assembly in the testing assembly I created mock objects which implement the interfaces in the lower assembly.  This doesn't cause any problems if the contacts or lower assembly is changed.

Now, it could be argued that these assemblies should be merged into one and that is something I'm certainly considering.. except that I'll be creating a new totally seperate UI which will need to use the contacts and software assemblies, but shouldn't include the quoting assembly (it will never be used in the UI).

I also suppose it could be argued that I should have one assembly for each application, but then we are talking about major code duplication, and I'm not sure that cost would be worth it because both applications still use the same database..

So, to sum it up, maybe having seperate assemblies may or may not be the right thing to do, but if you DO have seperate assemblies which have some common ground, the interfaces are very very helpful.

Clear as mud?

Andy

PS - Are there any resources out there to help figure out how to physically seperate classes into assemblies, when there are two or more applications share a common database?

ianinspain replied on Thursday, December 07, 2006

Wow ... this thread as turned out to be really good!, I have learned a lot here... I am very interested in the process of using an interface to decouple... see if i get this right.. I am sure i won't and have missed something :-)

create an interface and have some specific classes inherit from this interface so they have a contract and have to act a certain way..

have another class i.e. a BO or whatever.. doesn't really matter that accepts a parameter on a method not of type class, arraylist, MyOwnClass but of an interface meaning that you can pass ANYTHING into this method that implements this interface...

Would you not have to cast it once it arrives?

And where would be the best place to store the interface as many many different assemblys would possible use it ... so what is the best thing to do.... to create a seperate assembly and put all common interfaces into it..... and then add a reference to this assembly from my other assemblys?  but this is coupling each assembly with this common Interface assembly isn't it... I presume it would  matter because if you update the common assembly then all assemblies would get the changes ....

I hope i am not babbling :-)

Thanks

Ian

ajj3085 replied on Thursday, December 07, 2006

No, you wouldn't have to cast it.  An interface is a type as well, and you'd interact with it just as you if the method accepted a concrete type.

Now, suppose you have the following:

public interface MyInterface {
     string MyString{ get; }
     void DoSomething( int count );
}

public class MyClass : MyInterface {
     public string MyString{
        get { return myString; }
        set { myString = value; }
    }
    public void DoSomething( int count ) {
           // Do something here
    }
    public void DoSomethingElse() {
        // Do something here
    }
}

public class Consumer {
      public void Consume( MyInterface myIFace ) {
           myIFace.MyString = "x"; // Will bomb, because the interface only specifies that get is required
           Console.WriteLine( myIFace.MyString );
            myIFace.DoSomething( 3 );
            myIFace.DoSomethingElse(); // Will bomb, because not in the interface definition.
}


That's an example (in C#) of implicit interface implementation.  That means that the interface is concidered implemented because it has matched all the signatures in the interface.  If you explicitly implement (as here);

public class MyClass : MyInterface {
     string MyInterface.MyString{
        get { return myString; }
    }
    void MyInterface.DoSomething( int count ) {
           // Do something here
    }
    public void DoSomethingElse() {
        // Do something here
    }
}


You can ONLY call DoSomething if you first cast the instance of MyClass to MyInterface.  So explicitly implementing can be used to 'hide' methods.  This can be very useful ifyou just want an interface for internal use within the assembly; declare the interface as internal instead of public, and explicity implement it where you need it. 

Finally, remember that you can implement an interface both implicity AND explictly in the same class. 

HTH
Andy

SonOfPirate replied on Thursday, December 07, 2006

I understand the argument that there are many times and applications where adhering to the OOP principals, such as coding to an interface not an implementation, is "overkill" and may seem excessive.  However, it is my seasoned opinion that you are either disciplined to program following solid OOP practices or you are not.  I don't care if you are programming a simple calculator to do only addition, there is no justifiable reason why you should ever do LESS than a standard job developing an app.

Among the many reasons for this opinion is the fact that everythign changes and while you all can say today that your apps are not going to need code reuse or being extended or grow, s*** happens.  Everything changes.  In addition, if you don't develop a standard set of practices for yourself, how can you ever expect to have a framework that supports you?  Furthermore, going back and looking at an app that you completed 6 months ago using one approach after spending the gap working on a new app with a completely different tact will only lead to increased time reassessing what you did and why.  Add in the case where many of us are battling with contractors (both on-shore and off-shore) and these kinds of variations and deviations are killers.

Fact is, the best way to make yourself a good OOP programmer is to simply make it a habit to do things the OOP way.  Now, I am not saying that OOP is the be-all-end-all.  Just saying that picking and chosing when to follow good, solid, standard practices because "it is easier" is just lazy - IMO.

The original post indicates a real confusion over how this principal is implemented and that still seems to be a concern.  By telling the author that he can follow the rule sometimes will certainly not help matters as now you've introduced another variable into the decision making process.  These rules, like the decisions made by Rocky with CSLA, are there for a reason - to share with the developer community the lessons learned by more experienced programmers.  Fact is, this would not be a rule if those that have walked this path before didn't feel it was important and significant.  And rather than add the additional variable, just make it a habit of thinking this way and developing this way and, voila! Before you know it you will be doing it without consciously thinking about it.

The result will be better code.  And whether you are making a database app of your CD collection or an e-commerce solution for a Fortune 500 company, IMO it doesn't matter and there is never an excuse for less than your best.  But, I have taught myself to be a highly disciplined programmer over my 25 years in the trenches.  I understand where these rules, principals and guidelines comes from because I've been bittin the same way those that came up with the tenets have.  I'm the guy that comments everything (!) because I've been the guy brought in one an app that was under development for a year when the guy up and died!  Try picking up the pieces when that happens!

Again, IMO, there is never an excuse to pick and choose when to apply good standard and practices.  Anyone working in manufacturing or quality-controlled industries know that is just not allowed.  This "rule" should be applied to programming as well.  If you are going to claim to be an OOP programmer, than be one all the time.  Not just when you have the time.

As for the original post, the rule is intended to facilitate change, modularization and extensibility and even if you don't think these things are necessary for your application, it is simply good practice to follow them anyway.  The key to understanding this one is understanding what an interface is.  The fact that an actual Interface and an Abstract Class can be thought of the same way makes it a bit more confusing, but remember, you can't instantiate either directly - that is the key.  In both case, some other class has to exist that either inherits from the base class or implements the interface.  In either case, your goal is to make your dependant class use the interface rather than the derived class.

Perhaps the most prevalent example of this rule is the IEnumerable interface.  This interface indicates that the concrete class that has implemented it allows enumeration via the GetEnumerator() method.  Coupled with the IEnumerator interface that is returned from GetEnumerator, this provides for a very meaty and flexible way to interact with an incredibly wide-spectrum of objects.

Let's say you want to create a method to generate a simple listing of objects.  Your method would accept an IEnumerable as an argument as simply iterate of the elements, calling ToString() to dump the text for each item.  You don't care if this is a List, Array, ControlCollection or some custom collection because it doesn't matter to your functionality what the actual object is.  All that matters to you is that the object has the properties and methods that you need to complete the task.  That is what an interface does for you.

Yes, it may seem like redundancy because you've defined the properties and methods in your actual class, but the interface allows you to "decouple" - as they say - that concrete class.  And even in a simple case, this can be valuable if for no other reason than to simply make it a habit of programming this way.  Why?  Because is it good practice to do so.

One finaly note.  Generics have introduced a new complexity that can only be solved by interfaces.  Try determining the type of a generic object in code (for comparitive purposes) and you'll quickly find out how valuable it is that there are interfaces to check for.  This is because each type that the generic class handles actually becomes its own type at run-time.  So, there is no checking for: type == typeof(List<>), for instance.  You either know the specific type that you want, like List<int>, or you need to be able to check against an interface (IList).

Make it a habit to follow good practices and it will simply become a matter of fact rather than another variable you must decide when developing your apps.

Of course, that's just my opinion.

 

 

malloc1024 replied on Thursday, December 07, 2006

The OOP principles are guidelines not rules.  In many cases it is not possible or practical to follow every principle for every situation.  There are some principles that you should follow every time but the "program to an interface not an implementation" principle is not one of them. This does not mean you are doing less than your best if you don’t follow an OOP principle.  It does not mean your application is any less OOP.  It takes experience to know when to follow the principles.  The only advice I can really give to the OP is to know all of the principles and use them.  Using them will help you understand when to use them.

ajj3085 replied on Thursday, December 07, 2006

I'm going to have to agree with malloc here.  If the 'program to interface' rule was always applied, that would mean for every object in your system you'd have a corresponding interface.   Not only does that waste a lot of time just generating interfaces, you may never actually have any other classes implement the interface.

Your Enumerator and List examples don't really apply here either I think.  There is a difference between building a framework class, that will be used by millions, and building business objects, where the number of applications using them is quite small.

I think in programming everything is a tradeoff, and you have the find the one that works best for your situation.  If at some point in the future and interface is needed, it can easily be added at that time.

Just my opinion, of course.

Andy

ianinspain replied on Thursday, December 21, 2006

Thanks for everyones comments on this... It has been real helpful.....

I am certainly going to try and following the rules if i can... i know sometimes its not practical.... but i am going to try and stick to them as much as possible... as to get an habit of doing things right

thanks again

ian

DansDreams replied on Thursday, December 07, 2006

SonOfPirate, thank you for that lengthy thoughtful response.

However, and this is certainly my OPINION, I have to say what you've described is exactly the level of dogmatic adherence I think is ridiculous.

Having an interface for every single business object results in "better code"?  I should say not! 

I'd like to humbly suggest you do a little googling on agile development principles and then spend some time pondering them.  While I don't consider myself a full-blown agile or test-driven development, I have found keeping them in mind has made me a more disciplined developer.

And the interesting point about that is that one of the core principles is exactly 180 degrees the opposite of what you describe - namely that you never do something "just because", but rather only when there's a specific need to.  I stop myself several times a week from going down the path of some complex solution when a simple one will work just fine.  Yes, sometimes I have to refactor or redesign things, but the time saved still far outweighs what's spent doing that.

And that's the bottom line, not what some alleged OO guru says in a popular book.  At the end of the day it's all about having the most functional and maintainable code. 

So, I guess I'll consider myself "lazy", as I have to pass on your advice.

malloc1024 replied on Thursday, December 07, 2006

The following links contain the OOP design principles that you should by heart.  If you need more information, you can google it.

 

http://sis36.berkeley.edu/projects/streek/agile/oo-design-principles.html

http://architechie.blogspot.com/2005/10/oo-design-principles-quick-rundown.html

http://www.codeproject.com/gen/design/nfOORules.asp

 

The following link contains a very detailed explanation of the program to an interface, not an implementation principle.  This is a very good article and I recommend reading it.

 

http://www.artima.com/lejava/articles/designprinciples.html

malloc1024 replied on Tuesday, December 05, 2006

If one class is only going to implement the interface or abstract class and no future classes will, then it is not necessary to create that interface or abstract class in most cases.  However, if many classes are going to implement the interface or abstract class, you might want to consider creating the interface or abstract class.  Keep in mind this is an oversimplification of the issue and it does not work for every scenario.  For example, the separated interface pattern uses interfaces to separate a package from its implementation.  Many of these interfaces will only be implemented by one class, depending on the usage.  Despite this, it can be a very useful pattern to decouple assemblies.

Copyright (c) Marimer LLC