Coupling Is Your Friend
My SOLID article in Code Magazine talks about the concept of coupling as one of the object oriented principles that we are striving to get right.
“Coupling is not inherently evil. If you don’t have some amount of coupling, your software will not do anything for you. You need well-known points of interaction between the pieces of your system. Without them, you cannot create a system of parts that can work together, so you should not strive to eliminate coupling entirely. Rather, your goal in software development should be to attain the correct level of coupling while creating a system that is functional, understandable (readable by humans), and maintainable.” (originally published in the Jan/Feb 2010 issue of CODE Magazine)
I was reminded of this today, during a conversation with some coworkers when we realized that our efforts to decouple several screens from each other had led us to very tightly couple the workflow of the process we were implementing with the screen in that process. Be careful not to miss out on some important modeling opportunities in your efforts to decouple your system. You may end up decoupling the original pieces that you were concerned with only to end up coupling those same pieces to something that should have been made explicit.
In our specific instance we were having problems getting data from one screen to another. Each of our screens was decoupled from the next via calls out to the application controller. For example:
1: public void Login()
2: {
3: ApplicationController.Execute<Login>();
4: }
</div> </div>
This would open the Login screen from a button click on another screen.
We were having problems figuring out how to get the login information back to the calling screen because the Execute method has no return value. We could have used the event aggregator with the .Raise method on the app controller, but this seems a little hackish. Why should we have to call out to a third party object just to get a return value from should rightfully be a simple method call? In the end we realized that we were so concerned with decoupling the screens from each other that we missed the opportunity to correctly model the processes that we were dealing with. By introducing an object that property encapsulated the process of calling out to the login screen and handling the results of the login effort we were able to resolve the issues, maintain the decoupling between the forms and create a more explicit model and body of knowledge within our code.
1: public class StartupController()
2: {
3: //pass dependencies in through the constructor, here
4:
5: public void Run()
6: {
7: RunLaunch();
8: }
9:
10: public void RunLaunch()
11: {
12: var launchResult = _launch.Run();
13: switch (launchResult.Data)
14: {
15: case LaunchActions.Login:
16: {
17: RunLogin();
18: }
19: //other actions here
20: }
21: }
22:
23: public void RunLogin()
24: {
25: var loginResult = _login.Run();
26: switch (loginResult.Data)
27: {
28: case LoginActions.Cancel:
29: {
30: RunLaunch();
31: }
32: //other actions here
33: }
34: }
35: }
</div> </div>
Our efforts to decouple the screens were misguided because we were stuck with the mentality of “decouple this code” when we should have had the mentality of “couple this code correctly”. Once we got past this mental block, though, our problems were easy to solve.