24

Dave Thomas, the author of the Don't Repeat Yourself principle said:

DRY says that every piece of system knowledge should have one authoritative, unambiguous representation. Every piece of knowledge in the development of something should have a single representation. A system's knowledge is far broader than just its code. It refers to database schemas, test plans, the build system, even documentation.

I have difficulty to understand how it applies to programming code documentation.

Java API has the java.util.Arrays class with the copyOf method that is overloaded 7 times. The 8 methods can be documented in two ways containing the same information. The first way describes all overloaded methods using a single description, highlighting the differences between overloads. The second way describes each overloaded method using a separate description. Below are both ways - I bolded the differences in the content. The second way was literally copied from the API documentation of the java.util.Arrays class.

Is the second way compliant with the DRY principle? In my opinion it isn't, because it contains text which was copied multiple times, then, additionally, minor modifications were made to each copy. The same information can be provided in one text, which is almost eight times shorter. But I am not sure if I understand correctly the definition of the DRY principle. What are the "pieces of system knowledge" in this case? Do they have single, unambiguous, authoritative representation in the quoted documentation?

Documentation of the overloaded copyOf() methods - 1st way

public static byte[]    copyOf​(byte[]    original, int newLength)
public static short[]   copyOf​(short[]   original, int newLength)
public static int[]     copyOf​(int[]     original, int newLength)
public static long[]    copyOf​(long[]    original, int newLength)
public static float[]   copyOf​(float[]   original, int newLength)
public static double[]  copyOf​(double[]  original, int newLength)
public static char[]    copyOf​(char[]    original, int newLength)
public static boolean[] copyOf​(boolean[] original, int newLength)

Copies the specified array, truncating or padding with the default values (if necessary) so the copy has the specified length. For all indices that are valid in both the original array and the copy, the two arrays will contain identical values. For any indices that are valid in the copy but not the original, the copy will contain the default value. Such indices will exist if and only if the specified length is greater than that of the original array.

The following table lists default values for given type of array elements:

type the default value of type
byte, short, int, long 0
float, double 0.0
char null character ('\u0000')
boolean false

Parameters:

  • original - the array to be copied
  • newLength - the length of the copy to be returned

Returns: a copy of the original array, truncated or padded with the default values to obtain the specified length

Throws:

  • NegativeArraySizeException - if newLength is negative
  • NullPointerException - if original is null

Since: 1.6

Documentation of the overloaded copyOf() methods - 2nd way

public static byte[] copyOf​(byte[] original, int newLength)

Copies the specified array, truncating or padding with zeros (if necessary) so the copy has the specified length. For all indices that are valid in both the original array and the copy, the two arrays will contain identical values. For any indices that are valid in the copy but not the original, the copy will contain (byte)0. Such indices will exist if and only if the specified length is greater than that of the original array.

Parameters:

  • original - the array to be copied
  • newLength - the length of the copy to be returned

Returns: a copy of the original array, truncated or padded with zeros to obtain the specified length

Throws:

  • NegativeArraySizeException - if newLength is negative
  • NullPointerException - if original is null

Since: 1.6

public static short[] copyOf​(short[] original, int newLength)

Copies the specified array, truncating or padding with zeros (if necessary) so the copy has the specified length. For all indices that are valid in both the original array and the copy, the two arrays will contain identical values. For any indices that are valid in the copy but not the original, the copy will contain (short)0. Such indices will exist if and only if the specified length is greater than that of the original array.

Parameters:

  • original - the array to be copied
  • newLength - the length of the copy to be returned

Returns: a copy of the original array, truncated or padded with zeros to obtain the specified length

Throws:

  • NegativeArraySizeException - if newLength is negative
  • NullPointerException - if original is null

Since: 1.6

and so on for: int, long, float, double, char, boolean. It is exactly the same text, eight times, where only the bold parts are different.

12
  • 16
    Are you sure the documentation was copy&pasted? I am not very familiar with the J2SE API, but I know the Scala API documentation quite well, and there, they use macros to generate documentation for similar methods. So, the content is only written once, and parameterized with the different types. Commented Jun 24, 2021 at 7:57
  • 2
    @JörgWMittag, it is in the same form in the API documentation on docs.oracle.com/en/java/javase/16/docs/api/java.base/java/util/…, and in the source code in Arrays.java file. But I don't know if Oracle generates Arrays.java file or not.
    – iwis
    Commented Jun 24, 2021 at 8:45
  • 1
    If you can get access to the 2019 edition of The Pragmatic Programmer, read the chapter on DRY, it's explained pretty well there. The main objection is that people tend to repeat implementation details in the documentation (e.g. the comment says "if the account is in overdraft for more than 3 days, charge $10 for each day", which is an internal detail, and already can be seen from the code (example from the book). This is often a result of silly company policies mandating that all functions must have doc comments. Another common thing is something like amount += 10; // increment by 10 Commented Jun 24, 2021 at 20:40
  • 1
    @DocBrown: I shortened the citation to two examples
    – iwis
    Commented Jun 25, 2021 at 11:27
  • 1
    @FilipMilovanović I don't think your two documentation examples are equivalent. The first (overdraft) explains the intention of the code. They code may or may not implement that intention. The second (increment) is a description of of the mechanics of the code. I happily accept the former, but in general the latter should die (with exceptions for unusual code/methodologies). I'll also plug an answer of mine on SO about coments: stackoverflow.com/a/308930/31326
    – Peter M
    Commented Jun 25, 2021 at 12:07

11 Answers 11

30

About this specific problem:
From a technical perspective for me, the documentation of Array.copyOf is DRY, from my Developer perspective it is not.

The relevant information of each method are the input parameters, the output, the special behavior for different lengths, the possible errors.
Those are nearly identical over all overloaded implementations. From a technical perspective, each overloaded method could in theory behave differently. That means even if that is not the case now, it could in the future. Therefore those information are the same, but not identical. Therefor "repeating" it is absolutely correct and is not violating the DRY principle.

On the other side, the intention of the whole method is to provide the absolutely same functionality for different data types. That means, the intention is, that those functions will evolve equally. Then those information are not just the same, but identical. Therefore from this perspective the documentation is violating the DRY principle.

When WE are in such a situation to decide how to write a documentation and should we follow DRY or not:

The question is what we want to achieve. DRY is not a goal. It's a strategy to achieve a goal.

If you want that you don’t have to change much in the documentation, when your code changes, then use DRY.

But, as in code, this comes with a cost. It means you will have to write more "generic" documentation. Generics are in most cases more complex, that means harder to understand. Hmm that is violating the KISS (keep it simple, stupid) principle now? Yep :-(

Therefore the first question is, what do you want to achieve. And then you have to balance the principles.

For example, if I have some code that will change very rarely, and people will often need some functions of it, but rarely all of them, then I would prefer the approach with describing each function independently. It makes understanding easier and the additional maintaining effort is not that important, because my expectation is that there will not be so many changes.

If my code changes often, and/or most people will need the whole thing and not only parts, then a more condensed, generic style would be appropriate.

Therefore, in my eyes we should know those principles. And never completely ignore them. But it's not about following a principle blindly, but about realising which principle will support me in the current context the best to achieve my specific goals.
In my experience, the hardest part is to determine good, precise, goals. But that's another topic. :-)

Updated (added the initial part) because the question was sharpened. Thanks @iwis for the question.

6
  • 9
    Exactly. If humans were computers then completely DRY documentation would work well. But humans forget things and have a small cache so it is great to repeat useful information so that it is readily at hand where needed. Another example... In perfectly DRY documentation there would be no examples because examples repeat the information that is already encoded in the docs.
    – Felix
    Commented Jun 24, 2021 at 23:55
  • 1
    DRY isn't intended to prevent the same information being presented in different ways. It's to avoid situations where different parts of the documentation lose their anchor to the shared underlying information. The documentation can then become inconsistent. A bit like Census data summary tables -- they are repeating information found in the base data, but are useful for understanding as long as they remain bound to the raw data and can be automatically regenerated if the raw data changes.
    – John D
    Commented Jun 27, 2021 at 0:52
  • @Felix I guess you could say that humans are WET (we encourage thinking) rather than DRY, which is not very generative. Commented Jun 27, 2021 at 11:55
  • Added an initial paragraph to answer the sharpened question of @iwis
    – JanRecker
    Commented Jun 28, 2021 at 7:36
  • I can recall coming across this "DRY documentation" style and hating it. You want to know what this function does, but the documentation won't tell you until you read through the tutorial for the entire library. It can even be something as simple as forwarding arguments in Python. "Unknown parameters will be passed to the transport." Okay? What the heck is a transport and what parameters does it accept? Oh there are different transports. Which one am I using, and what parameters does it accept? And then the transport accepts parameters for the underlying socket library... Commented Jun 29, 2021 at 16:33
20

Lets start with the copyOf example:

Is the second way compliant with the DRY principle?

No, it is not. The similarities between these methods and their intended behaviour are way too obvious to assume they were caused just by incident, and if Oracle will ever have to change something in these docs, or translate them to a new language, or add some specifics for a new Java compiler version, they will have to do it eight times, not just one. However, I am pretty sure Oracle does not care:

  • they have probably enough resources for maintaining the documentation in the current form and keep it in a consistent state.
  • for such old and widely used framework methods, changes in behaviour are not to be expected to happen frequently, that would break too many existing applications.
  • a documentation where developers can quickly find what they are looking for is probably more important for them than staying DRY.

However, the specific example from this question is probably not a typical one, hence it should not be taken as a general archetype for one's own documentation. As I wrote in a comment, the implementation code itself is duplicated most probably for two reasons

  • lack of generics in Java at the time when copyOf() was initially placed in the library

  • performance (array copying in a widely used general purpose lib of a standard framework should be as fast as possible, and Java's standard implementation of generics, which uses type erasure, isn't probably the best foundation for really fast copyOf implementation)

So this specific example aside, when is it a good idea to keep documentation DRY even when methods don't look so uniform?

In my experience, it not uncommon that a certain set of methods inside a library can share a common concept, a common convention, or certain common properties. Examples for this are often cross cutting concerns, like

  • naming conventions indicating certain meaning,

  • usage of a certain unit system for certain parameters,

  • transactional behaviour for a certain group of methods or classes,

  • debugging behaviour, logging behavior, error handling bahaviour,

  • assumptions we can make or should not make about side effects,

  • usage / meaning of certain frequently used terms from the domain, which occur in the API in several places.

Occasionally, we find an internal method with a lot of parameters, and an API which provides several different public entry points to it (often overloads), for simplification of usage, specific default parameters etc. This can guarantee a consistency in behaviour for all the different entry points.

Repeating such commonalities in each method's documentation over and over again can obviously lead to maintenance problems, just like non-DRY code leads to maintenance problems when something has to be changed afterwards. So how is this solved in documentation?

The standard solution here is write down the commonalities only in one place. In the doc section of all other methods where they also apply, one can place a link or reference to the place where the common parts are documented. For example, Javadoc has a link feature, which allows exactly this.

The downside of this is that if one overuses links and references, documentation can become pretty hard to read and understand. Jumping back and forth between two places in a document can become pretty annoying. Hence it is important to find the right balance between the part of the documentation which is written for each method individually (but may repeat certain things), and the careful usage of links / references to things which shall not be repeated.

8
  • 3
    Hm. These are all arrays of primitive types, not of references. Can Java generics handle them now? Commented Jun 24, 2021 at 20:46
  • 2
    The problem is not the lack of generics, but that Java still treats primitive types as something separate from reference types, so it needed separate methods (or an untyped method, like the old System.arraycopy, which just takes an Object (which must be an array of some kind)). Commented Jun 24, 2021 at 22:12
  • @PaŭloEbermann: as I wrote, the problem today is not the lack of generics, but performance (my second point on the list).
    – Doc Brown
    Commented Jun 25, 2021 at 4:45
  • 3
    I don't agree that this is a rare example. Yes the exact circumstance is rare, but in a language without default values for parameters (or languages like C# where using default parameters is ill-advised for compat reasons in frameworks and libraries) having overloads that provide defaults for some values is very common. You could link to the method that provides all parameters and rely on the documentation there, but that makes for an awful user experience (I want to see the documentation for the parameters a method takes without having to jump around!).
    – Voo
    Commented Jun 25, 2021 at 8:30
  • (That said I agree with the wider point about defining cross-cutting concerns only once).
    – Voo
    Commented Jun 25, 2021 at 8:34
15

You shouldn't seek to make your documentation more DRY than your code.

Documentation is random access. People don't generally read it straight through. So if someone happens to look for the seventh override of a function, they should be able to quickly find everything they need to use it. It's reasonable to assume a user learning how to use a method might read the documentation for a class as well, but you shouldn't make them find the documentation for all "similar" methods.

If you feel your documentation is too repetitive, fix the code. Make better abstractions. Factor common concepts out. If your language isn't expressive enough to avoid duplication, you shouldn't feel bad if your docs match. The duplication is serving a useful purpose in that case. Code is read significantly more frequently than written, so it's more than okay to optimize for the reading case.

4
  • 3
    This point of view does not convince me. If code is implemented in a DRY fashion or not is an implementation detail from the APIs point of view. For example, if code which was once DRY, with a non-repetitive documentation, is made repetitive for the sole purpose of optimization, why should the documentation then be changed?
    – Doc Brown
    Commented Jun 25, 2021 at 6:59
  • "If your map doesn't match the terrain, trust the terrain." (or change it) Commented Jun 27, 2021 at 12:02
  • @DocBrown for this Documentation is random access and because sometimes, the implementation details matter. For example, isEmpty(). This's the kind of function where implementation details matter because conditions vary from type to type. isEmpty(array) and isEmpty(String) have different semantics. For example, how many times have you wondered if "null" is checked as "empty" or it cast an exception? And whitespace? Does the method cast trim before checking it out? And tabs? What about collections? What makes a map to be empty? its length? the null entries? Etc.
    – Laiv
    Commented Jun 30, 2021 at 14:28
  • @Laiv: that's not my point. These examples are not showing cases where DRY code was made repetitive for optimization purposes.
    – Doc Brown
    Commented Jun 30, 2021 at 15:12
6

The DRY principle applies equally to documentation.

On the other hand, there might be shortcomings in the tooling used in the documentation process that make it hard or impossible to create the documentation in the format of your first example.

For example, the method documentation in Java is commonly generated from Javadoc comments in the source code. I am not sure if there is a way to write a Javadoc comment that is recognized by the tooling as applying to multiple different methods. And also, such a single comment block for multiple methods can make it harder to tell for developers looking at the code if a particular method is properly and correctly documented or not. So that are some forces working against DRY documentation.

In the end, you will have to find a balance between the desire to have DRY documentation and the forces working against it. Different people/organizations will put what is optimal for them at different points.

4
  • Applying a single comment to multiple different methods is possible in C#. On reddit.com/r/learnjava/ I read the opinion: "Overloaded methods are not the same methods. Which means they are not violating DRY." I am afraid that due to tool limitations, programmers of different languages may say that my example violates the DRY rule, or doesn't violate it. Is there reasoning I can use in the argumentation, regardless of the capabilities of the documentation tools? "The documentation is copied several times => violation of the DRY rule" - or is it more sophisticated?
    – iwis
    Commented Jun 24, 2021 at 7:57
  • 4
    My reasoning for calling something a DRY violation would be "The documentation is copied several times and the copies need to be kept consistent". However, tooling and culture factors will affect the ability and willingness of people to make the documentation more DRY. Commented Jun 24, 2021 at 8:36
  • 1
    @iwis: this reddit opinion is missing the point, even differently named methods can violate the DRY principle (and overloaded methods may or may not violate it). It depends on if there is a (part of) the behaviour which must be consistent (or not).
    – Doc Brown
    Commented Jun 24, 2021 at 8:41
  • Tooling is an important part of the question, as mentioned by @Bart van Ingen Schenau. In my documentation tool, we can abstract portions of code and use them in multiple places that are either identical, or substantially similar (then we use conditions to keep track of how they are different, when they differ). So in the documentation source there is only one file that contains that information. However, that file may be included in several different pages, if needed, to ensure the user has all the relevant information when they are learning about a feature or following a procedure. Commented Jun 25, 2021 at 21:09
3

From a DRY perspective

The second one is correct.

A common misunderstanding of DRY is that it applies to expressions of concepts, rather than to the concepts themselves.

This mostly seems to come from programmers being told that they shouldn't copy/paste things and thinking that means any sufficiently similar representations of concepts should be consolidated. This leads to people going on crusades in the codebase to rid it of any similar pieces of code. But this is wrong. When applying the SRP it's perfectly acceptable to have multiple classes containing essentially identical code as long as they are describing different system concepts.

In this case you've noticed that several system concepts (descriptions of methods) that can be expressed in a similar way. This is true, but by consolidating them you're mixing together multiple system concepts into a single, more complex, expression.

From a design perspective

Like any data structure the design of documentation depends on how you anticipate it will be updated and read. The downside of the first approach is that previously separate concepts are now mixed together in the documentation, which changes how they can be updated/read.

Consider the Single Responsibility Principle (SRP) here:

If any of those methods change their behaviour (unlikely in this specific case, but more likely in less platformy classes) it will require making a documentation change that will affect many classes. Changing the description of any one method is now harder because the updater will need to consider the impact of their change all the methods that the description applies to.

I would expect the most common operation will be someone looking up documentation for a method (rather than creating or updating). In that case it's a fair assumption they want be shown only the documentation relevant to that specific method, not other methods which happen to be similar. I certainly wouldn't want to have to look up tables and spent effort to disentangle the behaviour of other methods to get the information I want.

2
  • 5
    To my understanding, the different "copyOf​" overloads shown in the example are part of the same system concept. I would actually would have expected them to be implemented only once with Java's generics - but I guess that API exists longer than Java has generics, and the performance impact using generics for an API which is intended to provide a blazingly fast copy function would not be acceptable for lots of scenarios.
    – Doc Brown
    Commented Jun 24, 2021 at 8:34
  • @DocBrown I agree that for a generic method it would be reasonable to have a single piece of documentation for the method. However, I think the code and the documentation range over different systems. This is subtle, but I think what constitutes a system concept in the code and what constitutes a system concept in the documentation of that code differ. In this case the language limitations of java resulted in multiple similar methods being required to express a single domain-system concept, which in turn has given rise to multiple separate code-system concepts in the documentation. Commented Jun 24, 2021 at 8:56
2

The second style is far nicer for the end user of the documentation. Especially since documentation is almost used in "reference" mode, rather than in "novel" mode. If I'm trying to accomplish a task or understand a behavior, I'll consult the documentation for a particular function to see exactly how that function works. I don't care about the other overloads of that function, so I don't really want to have to expend the mental overhead to read everything, remove the irrelevant bits, and extract the relevant information. I'd much rather just go straight to the documentation about the overload of interest.

Now, you certainly have a point that the second style is to be feared and avoided by the developer (or whoever is writing/maintaining the documentation). It's a nightmare for all the same reasons that repetitive code is a nightmare.

So, a conflict emerges; what to do? It's better to have correct and up-to-date information than it is to have maximally convenient information, so, all else being equal, the maintainer of the documentation has to win out in this conflict over the consumer of the documentation.

But, there doesn't have to be a conflict. Just as we write source code which is then run through tools to generate final binaries—and "DRY" doesn't care whether these tools produce output that is DRY—we can write documentation that is designed to be run through tools to generate the final documents. Armed with a tool, you don't have to choose between the first and second style. You can write the first style, and the tool can generate the second style. Therefore, this is what you should do. Use a tool that essentially functions as a documentation compiler/generator, and get the best of both worlds.

1
  • If you only want to understand code written, instead of writing or modifying it, sure, only the overload called is relevant. Still, if you know any other overload, or need to know one later, having them described together helps even in that situation. Manually finding relevant differences is a pita. Commented Jun 27, 2021 at 18:57
1

The question is illustrated with an example where a method has multiple overloads with different signatures. But there's another example in the Java world, namely method overriding in subclasses. Should the Javadoc in a subclass repeat what's in the superclass?

In this case the Javadoc tooling gives you the option of avoiding the repetition, and the generated documentation for the subclass will pick up the details for the overridden method automatically. But that's not a perfect solution, because (a) documentation has two audiences, the user of the API and the maintainer of the code, and (b) you often want to say something more about the behaviour of an overriding method that can't be inferred from the generic information in the superclass.

Someone mentioned Scala documentation being generated from macros, and such a mechanism would be a great addition to the Javadoc toolset. But in the absence of such a mechanism, I think you have to treat the user of the API as your primary audience, and that means repeating yourself where necessary.

1
  • @InheritDoc is a thing.
    – meriton
    Commented Jun 27, 2021 at 1:59
1

Yes, documentation should be dry, in so far as things which are used and look identical except for trivial differences (types mostly, though they should still follow an obvious pattern, as the principle of least surprise demands) should be documented only once together.

And no, that the documentation is only written once is nearly completely uninteresting, if it has to be read multiple times. DRY applies to what the consumer interacts with too, not only with what the provider does to create it.

No in so far as there should be enough examples to demonstrate use of the API, and as a starting-point to doing things, and those are obviously repeating information.

Also, higher-level overviews can be extremely useful in exploring what something is about, what it could be used for, why it is as it is, and thus understanding capabilities and limitations. They summarize and set the details into context, thus per se repeating information.


Unfortunately, doc-comments and similar systems while quite good for documenting each entity (type, member, whatever) in isolation, are much harder to pretty useless for that.

At least merging the documentation of a group of entities defined together (same file, top of same scope) is not too hard to implement, even if each entity gets an additional notes-section. The first entity would add a new doc-comment like merge, while the others replace theirs. Merging those notes where appropriate under the same heading can get arbitrarily difficult though.

Linking to commonalities while far easier to implement, doesn't get rid of the repetition, and makes each part harder to read.

1

Programming principles are observations made by experienced, smart developers that have decided to distill some fundamental truth of programming for the rest of us to use as a rule of thumb. However, principles are more "very strong suggestions," not "immutable laws of the universe."

DRY is a rule to live by, not a rule to die by. So are KISS (Keep It Simple, Stupid), POLA (Principle of Least Astonishment), SOLID (Single Responsibility Open-Closed, Liskov Substitution, Interface Segregation, Dependency Inverson), etc. When we choose a principle to prioritize, we may sacrifice others. POLA may violate DRY, and DRY may sacrifice KISS, and SOLID may violate almost every other principle, although still important.

I would argue that, if most developers found the exact method they needed faster, on average, using the second form of the documentation, then it would be superior, as it implements POLA while sacrificing DRY. This is my opinion, and others will surely differ, as each person holds a set of values that informs their preferences.


That said, the second form of the documentation is definitely not DRY, but that may be acceptable if it allows the average developer to find and understand the purpose of a specific override faster.

0
0

Documenting the overloads individually does not violate DRY. DRY is not like a LWZ-compression scheme which compress all repeating substrings regardless of context. DRY is about a single canonical representation for a single piece of knowledge.

The different overloads of copyOf() are actually separate methods with separate implementations. They happen have the exact same blurb currently, but this is incidental. If the documentation had been written differently it might have gone into the specifics which differs between the overloads.

8
  • "They happen have the exact same blurb currently, but this is incidental" - this isn't incidental, this is because they have almost identical implementation - see the source code of Arrays.copyOf().
    – iwis
    Commented Jun 24, 2021 at 11:21
  • 3
    Sorry, but I don't believe this is incidental. Quite the opposite, it is pretty deliberate. See my comment below this answer.
    – Doc Brown
    Commented Jun 24, 2021 at 11:21
  • @iwis: The key word is "almost". If they had the exact same implementation there would not be a need for multiple overloads in the first place. So there is some difference, and that difference may or may not be surfaced in the documentation.
    – JacquesB
    Commented Jun 24, 2021 at 11:25
  • 1
    @DocBrown: I'm sure they copy-pasted the same text. The point is the documentation for each overload does not describe the exact same thing since there are implementation differences. If the documentation had been more detailed the implementation details might have surfaced in the text. So the text are not equal by necessity, and therefore there is no DRY violation.
    – JacquesB
    Commented Jun 24, 2021 at 11:32
  • 1
    @JacquesB: "But since these are separate implementations" - well, I did not look into the source, but from the OPs initial comment here, I assume the implentations themselves violate the DRY principle (intentionally), hence the docs do violate it, too.
    – Doc Brown
    Commented Jun 24, 2021 at 13:28
0

A computer doesn't care about how many levels it needs to dig into in order to access the thing it is interested in. A human, however, gets confused when they need to constantly look up things, even in the middle of sentences, to understand a part of that sentence.

In order to true-DRY your documentation, one specific overload of the copy method would only directly contain the information specific to that overload, and it would link to the more reusable parts of the documentation that would apply to multiple (or all) overloads of the copy method.

That's great and reusable, but it is a horrible reader experience. It breaks the flow of information by having the reader navigate to different pages, as opposed to reading one cohesive document.

The impact on the reader is so counterproductive that it is therefore better to compromise on the DRY so you can increase the actual educational quality of your documentation, which is its main purpose.

Similarly, even in code DRY violations are acceptable when pure DRY would cause other problems such as performance. E.g. in a web server backend scenario, in pure DRY, it would be preferable if the frontend were to retrieve an enum's possible values from the backend, so that there is only one source of the enum (i.e. the backend), as opposed to having the backend and frontend both define the enum.

However, that requires an extra network call. And that costs performance. And then you have to weigh if the performance cost outweighs the purity of your DRY. Barring more intricate solutions (for now), when the choice is between having the front and back end define their own enum, or having the frontend make web request to the backend to receive the enum; you'll generally prefer violating DRY in order to cut down on the extra web request (this is one of those "straw that broke the camel's back" type of situations).

However, as is the case with development, automation can really help give you best of both worlds. More intricate solutions can optimize the benefits you reap. For the enum example, you could generate the frontend enum based on the backend enum (using a template), to maximize both benefits (one source of enum information pre-compilation, and no network call needed at runtime).

For the documentation example, you could automatically load the linked information (i.e. the "base" copy documentation) in a panel on the page of the specific overload of the copy method; in a way that the user doesn't even notice that part of the page is being dynamically loaded from what is technically speaking another page/document.

That would be one possible solution to keep your DRY more pure, without negatively impacting the reader's experience.

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