
Redundancy vs. dependencies: which is worse? (2008) - ColinCochrane
http://yosefk.com/blog/redundancy-vs-dependencies-which-is-worse.html
======
mabbo
My personal view is that redundancy on stupid things is okay. That is, things
that are very simple, you should be okay with doing over and over in multiple
modules if you need it.

The experience that lead me to this was a particular team I was on where a
previous developer had said "aha! All of these pieces of code relate to the
same domain model, so we should build a common package of domain model objects
and have all the modules share those objects! That way, we don't have to write
them all over and over again!"

These weren't just model objects for data passing, but actual business logic
inside these models. Usually very simple stuff, but occasionally a particular
module would need some special logic on those objects, so in it went.

The problem was that over time, there modules started drifting. Their domains
became different ever so slightly and the owners of those modules became
different teams. Now if you wanted to modify the domain object, you had to
check it wouldn't break code the other teams were developing.

It became a real mess. And all to avoid writing the same simple pojo classes
more than once.

~~~
HumanDrivenDev
I think I've come to a different conclusion reading your run down of this. The
key paragraph is this:

 _The problem was that over time, there modules started drifting. Their
domains became different ever so slightly and the owners of those modules
became different teams. Now if you wanted to modify the domain object, you had
to check it wouldn 't break code the other teams were developing._

Isn't the real issue here that the architecture didn't keep pace with reality?
It sounds like the dev who made the package had the right ideal. The real
issue was subsequent devs introducing their domain specific stuff into a
common package, instead of extending it or composing it with their own domain
specific code.

~~~
panic
The point of the article is that separating the common code into two different
pieces is often better than "extending or composing" the shared code. Merging
code together is fine if you're willing to separate it again, but lots of devs
aren't.

------
drawkbox
This guy definitely codes, I was nodding nearly every paragraph.

Redundancy vs dependencies is a constant battle, even internally or inside
your own head.

Many times it depends on the project, team size and ability of libraries to be
maintained whether budget, time or goal of the project and its lifeline.

For instance in gaming, you might have common libs for product purchasing,
profile systems, networking, data, serialization, and platform libs to
abstract calls. But systems like game objects, physics, gameplay and ui aren't
as lib-able unless it is a series of the same type of game or system.

It is better sometimes to just get it out, prototype it and iterate to ship,
then harvest and integrate useful/obvious items into dependencies/libraries
for the next one. If you are always organizing to dependencies first, you will
end up doing lots of unnecessary optimization and sometimes impact shipping
speed.

The balance on this is a tough one to learn and changes as you grow more
experienced.

------
segmondy
Neither, they both can be good or bad. Part of being a professional is
learning that there are no hard lines in software development. Being able to
tell when something is good and when something is bad.

When I start developing I encourage redundancy. Premature abstraction is a
very dangerous thing that can pin you into a tight corner.

Dependency is also fine, I keep things coupled together a bit close when they
are still in development and malleable and decouple once they start to
solidify.

It's my personal style of development when working alone. When working in a
team, I follow whatever convention that works best for the team.

------
austincheney
I am often of the impression that it is ok to start with many dependencies to
get an application into an experimental state quickly, but ultimately this is
extremely immature. As the application becomes polished over time and as there
are refinements to increase performance, reduce complexity, and trim some fat
many of the dependencies will go away. The reason why many dependencies peel
off a maturing application is that as the programmers become more involved and
aware of their knowledge domain they have to ask themselves if they can simply
"do it better and faster on their own", which is likely.

Unfortunately many applications, or their programmers, never reach maturity.
Also there is greater security and dependability in managing certain critical
functionality more directly instead of relying upon support from a third party
that may not exist with the same level of compatibility in the future.

~~~
adrianratnapala
_As the application becomes polished over time and as there are refinements to
increase performance, reduce complexity, and trim some fat many of the
dependencies will go away._

Do you find that many teams have the discipline to do this? The cynic in me
says that software far more often gets slower, more complicated, fat and
dependency ridden over time.

More constructively I could ask: what is it that gives a team or project the
discipline to do this work of improvement. How could I encourage such a virtue
in my own environment?

~~~
austincheney
> Do you find that many teams have the discipline to do this?

It depends on the motivation. Ultimately it comes down to discipline.

As applications get popular over time their code base starts to age and get
filled with chaotic cobwebs as new features are added or requirements shift.
If you don't really care you will do the minimum required to complete your
assigned task and await the next assigned task. This is what it is like when
the people who do the actual work have no skin in the game. There is no sense
of failure so long as you ship unbroken code, and so everything is very
mediocre. If you completely suck as a developer then mediocre is your personal
resounded success, and so what is just another layer of abstraction if it
makes your job easier.

In startups, personal projects, or ambitious open source initiatives failure
and pressure are constant reminders of reality. Everything is highly visible
and it is always your fault until you ship something amazingly awesome. You
need to ship quality code and make changes in the shortest time possible
without dicking up the application. You don't want to get caught with your
pants down updating a very simple bug only to discover a larger series of bugs
in code you don't own that prevents you from shipping your little tiny code
fix.

Also keep in mind that nobody (well... very rarely) is going to look into your
code to see if you have a million dependencies, but they know when
applications are slow heavy pieces of crap. If an application constantly
breaks because the dependencies don't play well together and your developers
lack the confidence to solve elementary problems your brittle house of cards
pisses people off. I am a web guy and many major companies ignore these
problems by doubling down on their branding, instead of training their people
to write better code, which really pisses me off.

> what is it that gives a team or project the discipline to do this work of
> improvement.

Ownership of success/failure. When your job or equity are directly impacted
(the more directly the better) the emotional connection to quality drastically
changes. I apply this level of thinking to my big open source project even
though I lose money on it, because I know people depend upon me and I own it.
I can be more successful than I am now if I continue to improve what I own or
I can be a disappointing failure.

This is harder than it sounds because metrics of product quality the
confidence to attain such a level of quality differ by experience. Not
everybody has years and years of experience. In that case you need somebody
who can supply some technical leadership and not be afraid to hurt people's
feelings when things get tough.

------
marcosdumay
You depend on code that is more abstract than yours. You replicate code that
is at the same abstraction level of yours. You shouldn't even be touching any
code that is less abstract than yours.

There is something to be said about libraries quality and trivial pieces of
code. But I feel that this is just a rant about some environment that lacks a
good command line parsing library.

------
rdiddly
On my last project since I was a one-man team, I erred way over on the side of
dependencies. Thought I was being clever and organized for the first time, by
encapsulating related things in related places and being a stickler about it.
But in the quest to do that, I ended up with a large group of tightly-coupled
trash cans!

------
everdev
In Go, "a little copying is better than a little dependency"

[https://www.youtube.com/watch?v=PAAkCSZUG1c&t=9m28s](https://www.youtube.com/watch?v=PAAkCSZUG1c&t=9m28s)

~~~
lloeki
A lovely story about dependencies:
[https://www.dotconferences.com/2014/10/blake-mizerany-
three-...](https://www.dotconferences.com/2014/10/blake-mizerany-three-
fallacies-of-dependencies)

------
dozzie
In the long run, dependencies are more expensive to work with, though
programmers usually don't see it nor admit it, as language package managers
hide the initial portion of the cost (the smaller one, but much better
visible).

------
ivanhoe
The main problem with redundancy is that every time you refactor you need to
look for all the occurrences, and sooner or later you'll forget to update the
change in one of the places. So in my book redundancy is bad almost always. On
the other hand if it's only a few lines without extra dependences, it's often
more readable to just repeat them, especially (and it's quite common) when you
would need to add extra logic and conditions just to make that little
abstraction work.

~~~
ozim
Let's talk about risk of regression.

Ok I forgot to update some code in one place because I was doing duplicated
code. If it is often used place it will be found out quick by QA or users. I
kind of have more control over what can break.

On the other hand I made something that is abstract and used in many places in
code. I might not be able to tell what will break maybe it will be 5 places
maybe none.

In the end you should be able to find similar code in all project files with
the tooling. The same with references to abstract code, but abstractions are
behind interfaces or are subtypes and it is harder to find in my opinion than
doing CTRL-F on all files. Specially with OOP code until you run the program
you might not know which method is going to be called.

~~~
ivanhoe
For me it's a lot about the stress of refactoring: if I know the code is all
in one place, I can make sure that I don't break the contract and be fairly
relaxed about making my changes. Searching through files, making sure that
you've found all the occurrences, reading each of those blocks of code and
trying to understand them enough to be sure you're not breaking something is a
lot more work, but more importantly it makes me feel very uneasy about
refactoring. It's much more stressful because there's more moving parts, you
need to be concentrated about a lot more things at once.

------
rwmj
The command line example is a bit odd since any POSIX environment has getopt
(GNU has getopt_long too) and most languages out there have well-developed
command line parsing in their standard libraries (eg. Python's excellent
argparse).

