11

I am currently working on a small game I did in about ten days. Since I am programming for myself, I am being lazy and going to the easiest solution with (too) little concern about bad code quality.

However I am reaching a point where it begins to matter. I am starting to move booleans that references states into classes etc. and now I wanted to know experienced programmers opinion about mutual referencing objects.

What I mean by mutual referencing objects is this: we have a server which can create multiple games, such as chess games when two clients connect to play. Everytime a player makes a move, his connection handler must update a specific board on the server. After the update, once the board is updated, a broadcast of the new state needs to be done to each client.

I found convenient to have two Client objects in the Board (so Board can Client.send() to both) and a Board in each Client (so Client can call Board.update (move)). For some reason, I'm inclined to think this is generally bad and could be avoided, but what is your opinion ?

Is this fine as it is, or am I missing something here ?

5
  • 3
    Have you considered posting your code on Code Review?
    – RubberDuck
    Commented Sep 27, 2015 at 21:30
  • 1
    In and of itself it sounds fine.
    – NPSF3000
    Commented Sep 27, 2015 at 22:17
  • This can turn into a problem when everything depends on everything else. There are some patterns, such as model-view-controller, that try to impose some order on the relationships between objects.
    – Davislor
    Commented Sep 28, 2015 at 0:59
  • Read about the Observer Pattern. en.m.wikipedia.org/wiki/Observer_pattern Commented Sep 28, 2015 at 16:17
  • In my experience, and I think in harmony with Mason's answer, is that this is a symptom of the sort of tight coupling that is appropriate in the business/domain layer. UI components and mechanical/utility classes can often benefit from the flexibility and interchangeability of loose coupling. But, when the business says an Order needs a collection of LineItem's and that each LineItem must live under an order, you ought to tightly couple those classes. (Not to imply that you don't also find plenty of opportunity for loose coupling in your "philosophy" layer.)
    – svidgen
    Commented Sep 28, 2015 at 21:41

3 Answers 3

11

Having classes directly depend on each other is known as coupling. It's generally taken as an article of faith, with no explanation provided because apparently none should even be needed, that coupling is a Bad Thing because it makes your system "inflexible."

The problem is, the only thing worse than too little flexibility is too much flexibility. When you make everything as flexible as possible, you end up with horrible messes like Soft Coding. And that inflexibility can actually be a huge benefit by turning the perceived disadvantage on its head. The disadvantage frequently cited is that if you change one thing, it will break everything it's coupled to and you'll have to change that too. But consider this: changes to one subsystem frequently (not always, but more often than you'd like!) do end up affecting related subsystems anyway. If they're strongly coupled, and your language has a strong, static type system, then when you make a breaking change, the compiler will do all the hard work for you and show you exactly what has to be fixed and where. The more you decouple things, the harder it is to track down problems like this.

Which is not to say that everything should be strongly coupled, of course, especially if you want your code to be able to work with different types of related systems. People call too much coupling a maintenance nightmare for a good reason. But be careful of just decoupling everything for the sake of decoupling everything, because that can be even worse.

In this particular case, it looks like you're not trying to make your code work with multiple different types of systems. Your Client isn't trying to be able to run "a chess Board, a checkers Board, a backgammon Board or a Scrabble Board"; it's simply playing chess. So having it know about the Board class isn't a problem. Likewise, the Board isn't trying to communicate with multiple different clients, so it doesn't need to be flexible in the type of client it tries to communicate with, and therefore, you don't need the added complexity that comes with making it flexible. This is a very important pragmatic programming principle known as YAGNI (You ain't gonna need it!) Keep that in mind, and you should do fine.

1
  • 1
    Wish I could give this two +1's: One for recognizing tight coupling as the underlying "condition." And another for good-measured pragmatism: Loose coupling should only be a means to an end, not an end in itself!
    – svidgen
    Commented Sep 28, 2015 at 21:25
6

Yes, this can be a problem.

When A depends on B, that means changes in B often require changes in A as well. When A and B both depend on each other, that means changes in either one often require changes in the other. For maintenance purposes, once two classes mutually reference each other, they might as well be a single big class.

Like many software architecture issues, just one mutual reference like the example you describe is unlikely to be a major problem by itself, but if you never remove this mutual reference when it does become a nuisance, it will make many future changes needlessly fiddly. And if you let yourself add more mutual references, you risk turning all of your nice small classes into a de facto god class you can no longer detangle.

As a very, very simplistic example of what I'm talking about, imagine you want to add a spectator mode or an online leaderboard or some other feature that requires sending the board state to "clients" that aren't the other player. Client has to change no matter what since it needs to know how to call SpectatorBoard.update() and Leaderboard.addScore() as well as Board.update(), but because of the mutual reference, Board also has to change so that it can call Spectator.send() and Leaderboard.sendScore(). Now your complex networking logic is scattered across two classes, one of which clearly has no business knowing about it in this much detail.

Without knowing more about your requirements, current code and programming language it's impossible to say what the correct alternative is, but I'm going to guess that the need to send updates "originated" in the Board somehow (perhaps it's the one handling user input), in which case one obvious alternative is to teach the Board to fire an event (assuming your language supports events, a.k.a. the Observer pattern), and then simply have the Client subscribe to that event. Then the Client can remain the only class that needs to know your networking logic.

1

The poor mans approach here is to create a Mediator design pattern, where the two classes mentioned only communicate to the mediator and the mediator knows about the two classes. You can take that as far as little as you desire with interfaces instead of concrete classes, factories to build the components, so on, but a mediator will definitely make any possible refactor simpler down the road!

Not the answer you're looking for? Browse other questions tagged or ask your own question.