Internal documentation is written in a program as comments.
External documentation is written in a place where people who need to use the software can read about how to use the software. External documentation can be broken down into library documentation, which describes tools that a programmer can use, and user documentation, which is intended for users of an application.
The line between internal and library documentation is not clearcut because the trend is to write library documentation inside a program as comments, relying on software that extracts the documentation and puts it into a form suitable for people who only want to use the library. For example, the extensive Java library documentation is created by software called javadoc that reads Java programs, including comments, and writes documentation.
We has met the enemy, and it is us. — Walt Kelly
Each function in a piece of software solves a specific problem. Before you try to solve any problem, you should have a good understanding of exactly what the problem is. It makes no sense just to start writing and then, afterwards, look at what you have come up with to see whether it solves any useful problem!
Inexperienced computer programmers imagine that they can keep all problem descriptions in their heads. Experience has shown that they can't. Three issues come up.
When writing a function definition without written documentation, you only have a rough idea of what it is supposed to do. While you write, the idea morphs in your head. A simple interruption can cause the idea to lose what focus it has. You start thinking about the program as a whole instead of thinking of just the function that you are working on, and the function starts to take on responsibilities that it should have nothing to do with.
Suppose that you test the function and find that it does not work. So you need to fix it. But during the process of fixing it, you have nothing but your memory telling you the function is supposed to do. It is difficult to keep that in your head along with the details of how the function is supposed to work, and the process of fixing a function definition takes the function further away from its original intent, not closer.
Later, when you need to use a function, you have forgotten just what it does. Unwilling to reverse-engineer it, you make a guess based on what you remember. You often forget important details, and your software does not work because of it. You are faced with laborious debugging to find out what is going on.
You might have heard of "self-documenting code". The idea is for functions to be written in a readable form so that, to find out what a function does, you just read the function's body. For very small pieces of software that can be achieved. But imagine a larger piece of software, say with about 1000 functions. Such software is built up function upon function; one function typically uses a few others that are defined in the same collection of 1000 functions, with the exception of the bottom-level functions that only use the library.
Suppose that the software has no internal documentation, and relies on "self-documenting code". Now you want to understand what a particular function does. But it uses 3 other undocumented functions, so you need to understand what they do first. Each of those uses 2 undocumented functions, so you must read their bodies too. It goes on and on. You find yourself reading thousands of lines of code to understand a single function whose body is only ten lines long.
The only way that anyone can work with undocumented software is to reverse-engineer the whole thing and add documentation that should have been written by the developer. Most of the time, that is too difficult. Undocumented software is often just thrown away as unmaintainable.
What is the difference between internal and external documentation? Answer
Why isn't the idea of self-documenting software viable for large pieces of software? Answer
What happens to undocumented software? Answer