The word “module” is used in software engineering by analogy with the way it is applied to physical modules. We speak of modular housing, or modular container systems, or a plug-in module for an oscilloscope, and then turn around and put some bits on a disk or in RAM and call them a “module” too.
To be a module, something has to connect to something else in a general, intentional manner. That is, we have entities A and B that connect successfully, and they do so not because A has properties that make it compatible with B in particular or vice versa, but because they both have known, general properties that make them compatible with one another. In other words, you can change some properties of A or B, or swap A or B for things that have different properties, and they’ll remain compatible because of the compatibility-related properties that didn’t change. When you put together a modular home, the bathroom unit is a module because you might have connected a kitchen unit at that point instead.
In the software world we keep our software in files, we copy the files from one place to another, and we process them in various ways to get digital artifacts located either in files or in an address space (where the distinction between these two locations is a waning technical artifact). Now some artifacts you would call “modules” and some you wouldn’t. A software application that can be run on any copy of a particular software platform could be a module, because any copy of the application can run on any instantiation of the platform: Omnigraffle is a module because any copy of Omnigraffle is compatible with any Mac (within certain parameters such as OS version and so on). So my definition is pretty broad. (We could tighten this up if you like, e.g. to require that the thing you’re plugging it into has a specific place to attache it, not just a pile such as the Applications folder.)
But the idea does not apply to all software artifacts. A program that will only run on my computer – say, a script that touches particular files on my computer in a manner that’s difficult to reproduce – is not a module. After I link or load a file into a larger application, e.g. when I run Omnigraffle by copying it into an address space, it stops being a module, because after the linking or loading step it (the in-process version) is no longer compatible with any situation other than the one it’s in.
So when I read a programming language description that speaks of a “module” M, meaning a copy of some original module (from a file, say) that has been processed (linked, loaded) to such an extent that it is no longer compatible with any context except the one in which it is lodged, I bristle. A better word for such a thing would be “structure” (Standard ML, Scheme 48) – just about anything other than “module”. “Interface” works too, at least for place where you connect to the module-derived-thingy-structure. I can’t remember where I’ve seen the word “interface” used in this way – maybe Mesa.
The confusion arises, as usual, from metonymy. The module name may stand in for the structure name, and this is sort of OK if there is no ambiguity (only one structure per module). The danger with metonymy is the preemptive assumptions it makes: that there will always be only one structure per module, and that no one will ever get confused between the proper meaning and the metonymical one. These assumptions might be true in simple systems, but they become a severe limitation as systems integrate and scale through social space (changing developer community, redeployment) and through time (dynamic loading/linking, change management).
But why does one divide any system into identifiable pieces – e.g. why would one divide program source code into two files? So that you can change the two parts independently, i.e. vary properties of one without varying the other. Suppose you have a working program in files A and B, and you make a change to A and get a new working program. Then old A, new A, and B are all modules if we can convince ourselves that there is something general and intentional about the compatibility of the A’s to B. Because of the vagueness of the word “general”, this requirement could be easy to meet, especially when relaxed to some uninteresting condition that can be tested by machine, such as type compatibility or use/definition satisfaction. But to prove “intentional” you would have to write down what conditions make the files compatible with one another. This piece of writing is often called an “interface” (Java, Scheme 48), which relates metonymically metonymically to the definition of “interface” I gave above. “Interface specification” or “interface definition” would be a better term.
Exercise: What is a “component”, and what are its risky metonymical uses?