3

Suppose I have a function to log error messages printError(). Suppose I have another function which might throw an error, doSomething(). Should doSomething() implement its own error logging or depend on the existing printError()?

Generalizing the question, should new code depend on existing code? In the given example, both printError() and doSomething() are functions that are meant to be exported.

In case it matters, suppose I'm building a library in C, but generic language agnostic answers are welcome.

Hopefully I've made myself clear.

Thank you for your time.

3
  • 4
    "should new code depend on existing code" - if the answer to that was no, how would you build any large, non-trivial program that does useful things? Feb 5, 2021 at 16:03
  • Suppose I have the main function, and some other doSomething function. Now I want main to do the same something that doSomething does. Should main call doSomething or should implement the same functionality again? If the answer always was to implement the same functionality again, we would never make functions. And thus functions have not stuck as a language feature. Since functions are an acceptable language feature, it is acceptable for a function to depend on another. QED. Addendum: the question should be when is it ok.
    – Theraot
    Feb 5, 2021 at 16:08
  • Thank you for the comments, I guess I've been overthinking and overlooked this simple argument. Feb 5, 2021 at 16:49

4 Answers 4

3

Generalizing the question, should new code depend on existing code?

All new code depends on existing code. If your new code adds 1 and 2 together it depends on existing add code. Even if it’s assembly you end up depending on micro code.

The big difference is when you depend on unstable code. Your code is only as stable as the code it depends on.

If printError() is unstable it may be worth reimplementing it just for that reason. That may avoid breaking changes or legal entanglements.

However, following the impulse to do it all yourself is a poor justification. You should have a clear reason, not wild speculation. Otherwise you end up building the whole computer from artisanal hand dug ores.

1

According to Uncle Bob and others:

A function should do one thing only and do it well

Accordingly, if printError() only prints error and prints errors well, there is no benefit in reinventing the wheel and reimplement the same again in another context.

Moreover, if doSomething() would by itself do something and print errors, it would no longer do one thing.

Lastly, if you printError() prints error well, but you would find a way to print them even better, then improving printError() would immedialtely benefit all those other functions that depend on it.

Now, when designing an API, you have to carefully make the difference between improving a function and extending it. For instance you may find it interesting to explain the root cause of an error and provide advice to avoid it. This is no longer doing one thing but doing something more. The question is then if explainError() should start with calling printError() or if printError() and explainError() should be completely independent letting the choice of combining them to the using context.

So to summarize: yes, functions should depend on other functions as much as possible but certainly not more.

1
  • Thank you for the answer, I guess I've been overthinking and overlooked this simple argument. I'll wait a bit before accepting this as an answer in case someone else wishes to add something. Feb 5, 2021 at 16:51
0

Your question/situation is a good example of using the DRY - Don't Repeat Yourself principle.

DRY - Don't repeat yourself: The name pretty much says it all. Don't repeat yourself (just did it again! :) The main idea behind this principle is to ensure that changes are confined to one location/scope and there is no duplicate code lying around. The motivation for this should be easy to see - duplicate code can increase maintenance costs of an application/system (bugs in one place can become bugs in N locations).

// say this is in file 1. 

public static void warn(String message) { 
  printMessage(message, Level.WARNING);
}

// say this is in file 2.

public static void info(String message) { 
  printMessage(message, Level.WARNING);
}

// say this is in file 3.

public static void printMessage(String message, String level) {
...
// If you find a bug here, you can deal with the issue just here in file3.
// If not, you'd have to fix it in two different files. <scream_emoji>
}

This principle is just that. It's a principle. You don't have to follow it. But it can make your life easier as you develop and maintain the software you work on.

So it's not only a good idea to depend on other functions, but also recommended. And at the cost of repeating myself, don't repeat yourself! ;)

0

As with most things in programming, the answer is "it depends".

At one level, your C code absolutely depends on code in the standard library - you aren't going to re-implement printf, for example.

But on a higher level, things get murkier. Using third-party solutions can make life a lot easier for some tasks, but adding a third-party dependency can cause problems as well.

For example, hand-hacking your own XML and JSON parsers is a pain in the ass1, and there are existing third-party tools that do that for you. Using those tools saves you time in development and testing and allows you to focus on the actual problem at hand.

At the same time, reliance on those third-party tools introduces some problems of its own. You may run into licensing issues, there may be security issues (such as the Heartbleed bug that was in OpenSSL), there may be versioning issues, incompatibilities with other tools, etc. You have to be careful how you design the code that uses the third party tool - it's often a good idea to create your own abstraction layer such that if you decide to use a different tool in the future, those changes are isolated from your application code.

Sometimes third-party tools are simply too "heavyweight" (use too many resources) and you only need a small slice of the functionality they offer - in that case, rolling your own solution may indeed be the better decision.

Summing up, leverage existing code where it makes sense to do so - re-implementing the same code over and over again is generally a waste of resources. Just be aware that there are times when you will want to roll your own solutions2.


  1. I speak from experience.
  2. Make absolutely sure that's the right answer, though - it's easy to fool yourself into believing something's easy (like a fully-featured XML/JSON parser) when it's really a lot of work. Crypto is one area where correctly implementing your own solution is hard and almost never a good idea.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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