Hot answers tagged

69

Last time I tried to start a refactoring with unforeseen consequences, and I could not stabilize the build and / or the tests after one day, I gave up and reverted the codebase to the point before the refactoring. Then, I started to analyze what went wrong and developed a better plan how to do the refactoring in smaller steps. So my advice for avoiding ...


52

Is it just a symptom of my previous classes depending too tightly on each other? Sure. One change causing a myriad of other changes is pretty much the definition of coupling. How do I avoid cascading refactors? In the worst sort of codebases, a single change will continue to cascade, eventually causing you to change (almost) everything. Part of any ...


41

So, what am I missing? Dependency Injection decreases coupling between a class and its dependency. But it increases the coupling between a class and its consumer (since the consumer needs more info to create it) and the dependency and its consumer (since the consumer needs to know the dependency to use). Very often, this is a good trade off. The class ...


33

The approach your professor proposes is best described as stringly typed and is wrong on almost every level. Coupling is best reduced by dependency inversion, which does so by a polymorphic dispatch, rather than hardwiring a number of cases.


31

In theory, loose function-data coupling makes it easier to add more functions to work on the same data. The down side is it makes it more difficult to change the data structure itself, which is why in practice, well-designed functional code and well-designed OOP code have very similar levels of coupling. Take a directed acyclic graph (DAG) as an example ...


28

Follow the KISS principle: Keep It Simple, Stupid, or the YAGNI principle: You Ain't Going to Need It. You can write the code like: void updateSpecialData() { // do the update. backupData(); } Or you can write code like: void updateSpecialData() { // do the update. emit SpecialDataUpdated(); } void SpecialDataUpdatedHandler() { ...


22

In layman's words: Not all users use all of a company's apps Different users have different needs Why force an user to buy a full package when he/she needs only a part ? (Ok, Google apps are free, but other software maker's aren't.) Having those apps separate makes it possible to be updated separately and, most importantly, sold separately. The fact that ...


21

Suppose you have a subsystem S that depends on a database connection D. Without dependency injection, there is a relatively tight coupling between S and D, because S needs to know both how to use D and how to create it. The rest of the system, however, can be blissfully unaware of this dependency between S and D. With dependency injection, the coupling ...


21

I disagree with your assertion that it is a red flag. I also disagree with your representation of the counterpoint, that there is One Right Way of representing a Builder pattern. To me there's one question: Is the Builder a necessary part of the type's API? Here, is the PersonBuilder a necessary part of the Person API? It is entirely reasonable that a ...


18

Your professor is doing it wrong. He's trying to completely decouple the view and model by forcing communication to travel via string in both directions (view doesn't depend on model and model doesn't depend on view), which totally defeats the purpose of object-oriented design and MVC. It sounds like instead of writing classes and designing an OO-based ...


17

It sound like your refactoring was too ambitious. A refactoring should be applied in small steps, each of which can be completed in (say) 30 minutes - or, in a worst-case scenario, at most a day - and leaves the project buildable and all tests still passing. If you keep each individual change minimal, it really shouldn't be possible for a refactoring to ...


15

Well, your first three points are actually about other principles than coupling. You always have to strike a balance between oft-conflicting design principles. Your fourth point is about coupling, and I strongly agree with you. Coupling is about the flow of data between modules. The type of the container that data flows in is largely immaterial. Passing ...


13

There is a balance that needs to be achieved between looseness of coupling and complexity. As the person responsible for the overall architecture, you need to strike that balance. When we call a ToString() method on an object, we can do so safely because we know all of our classes derive from a base class that has a ToString() method, and that method can ...


12

I've been involved in projects like this twice now (both using nuget with .NET), and I would say that on balance it is a good idea. But your mileage may vary. Don't think for a minute that it's a panacea, that it's going to solve all of your problems without causing new ones. Release management will gain a whole new layer of complexity, you'll need to deal ...


12

The example you describe of a simple data, where the modification triggers some effect can perfectly be implemented with the observer design pattern: this is simpler to implement and maintain than full event driven code. the coupling between subject and observer can be abstract, which facilitates separation of concerns. it's ideal for one to many ...


11

enums (or public static final Strings) should be used instead of magic Strings. Your professor doesn't understand OO. For example having a concrete Vehicle class? And to have this class understand the make of a bicycle? Vehicle should be abstract and there should be an concrete subclass called Bike. I would play by his rules to get a good grade and then ...


11

Constants that are specific to a class should go in that class's interface. Constants that are really configuration options should be part of a configuration class. If you provide accessors for the configuration options in that class (and use them in place of the constants elsewhere), you won't have to recompile the whole world when you change a few options....


11

I think the confusion is that high cohesion does not necessarily mean you want to put all of the "closely related responsibilities" in one class, but rather that all of the items in a class should correspond to closely related responsibilities. For example, if you have a Kitchen class, you wouldn't want bathroom logic in it; however, you don't HAVE to also ...


11

In case you didn't know it already take this insight: The concepts of object-oriented and closures are two sides of the same coin. That said, what is a closure? It takes variable(s) or data from surrounding scope and binds to it inside the function, or from an OO-perspective you effectively do the same thing when you, for example, pass something into a ...


11

How can I avoid this kind of cascading refactor in the future? Wishful Thinking Design The goal is excellent OO design and implementation for the new feature. Avoiding refactoring is also a goal. Start from scratch and make a design for the new feature that is what you wish you had. Take the time to do it well. Note however that the key here is "add a ...


10

TO make your code loosely coupled here are a few simple things to remember: Part 1: Technically known as "Separation of Concern". Each class has a specific role, it should be handling business logic or application logic. Try and steer clear of class that combine both responsibilities. i.e. A class that manages (broad term) data is application logic while a ...


10

My recommendation is: Use addTrack( ITrack t ) but be sure that ITrack is an interface and not a concrete class. Album doesn't know the internals of ITrack implementors. It's only coupled to the contract defined by the ITrack. I think this is the solution that generates the least amount of coupling.


9

If you really need coordination between those two classes, write a CsvCoordinator class that encapsulates your two classes, and test that. However, I dispute the notion that CsvRecord is not independently testable. CsvRecord is basically a DTO class, is it not? It's just a collection of fields, with maybe a couple of helper methods. And CsvRecord can be ...


9

Good question, simply put, decouple. That's the way to go here, you do not want to be tied to the version of java. There's one scenario you don't decouple: if your technology will allow for non-type-specific objects to be sent over the wire, that is, if you can use the current java objects now as a YAGNI, and the replacement with a different type that you ...


8

From (the wonderful) book Working Effectively with Legacy Code by Michael Feathers: When you break dependencies in legacy code, you often have to suspend your sense of aesthetics a bit. Some dependencies break cleanly; others end up looking less than ideal from a design point of view. They are like the incision points in surgery: there might be a scar ...


7

From the comments I see you're using Java. Have a look at various Queue implementations. Particularly, BlockingQueue is useful for producer-consumer scenarios. You could have two queues: one between Source (producer of data) and Process (consumer of data), and another between Process (producer of results) and Persist (consumer of results). With limited-...


7

I would say it's definitely not as bad as a God Object or Super Object. Those are a whole different animal that is hard to write, maintain, debug, and test and they should be avoided at all costs. As far as the namespace goes, that's definitely a legitimate concern, and if you are finally getting to the point where your namespace is becoming overcrowded I ...


7

Afferent coupling can most easily be assessed in terms of how much pain it causes/saves because of change necessity or likelihood. For instance, take your wheel class and let's say that a lot of other modules use it to build various kinds of vehicles. If the wheel class is extremely stable, then this afferent coupling is beneficial since vehicles need ...


7

I strongly disagree that it increases coupling. Without dependency injection you have tight coupling between a sub system and the concrete implementation of the dependency. With dependency injection you have decoupled the sub system from the implementation of the dependency. Making the argument that it increases coupling between the consumer and this sub ...


7

I understand how annoying it can be when 'appeal to authority' is used in a debate. Arguments should stand on their own IMO and while it's not wrong to point to the advice of such a well-respected person, it really can't be considered a full argument in itself ala we know the Sun travels around the earth because Aristotle said so. Having said that, I think ...



Only top voted, non community-wiki answers of a minimum length are eligible