How could I best explain software dependencies to a non-software, non-tech person? What are software dependencies, such as package dependencies or linking dependencies? And why does it matter to know about these dependencies in the context of free, libre and open source code?
What are software dependencies, and what are the implications of FLOSS dependencies for other projects?
copyleft;dependencies
Software dependencies: A not-too-technical introductionSummaryPrograms depend on other programs, often with many deep levels of indirection. Million of packaged FLOSS programs are available through public repositories for easy dependencies download and installation.How dependent programs relate to and interact with each other can be more or less intimate.Each program's license FLOSS requirements and obligations vary based on the relationship and interaction between dependent.You need to know:The whole chain of program or package dependenciesThe purpose and use of each program or package in that chain (test, tool, runtime)Which dependent are shipped and redistributed with your product, application or library vs. which may be installed by your userThe license of each dependency in this chainHow software is builtLarger software systems and products are commonly assembled from software components.  Each component is some collection of programs. And components frequently re-use other components.  Each component is usually delivered as a package. A package is typically an archive that contains the programs. A package also commonly contains information about the component name & version, what it is about, who wrote it, sometimes its license, etc. And also what other components may be required by this component: this is called a dependent component or a dependency. In formal terms, I would define a package as the set of exact software programs and files that are distributed or used for a given component.DependenciesA program may require one or more other programs to run (the dependency-ies). The dependencies can be recursive potentially creating very deep relationships. Sometimes the dependency is only for testing or building/compiling the program - i.e. a development or dev dependency. Sometimes it is needed to run the program or sometimes it can be optional to provide extra  features. Some dependencies for a program may be rather generic and sometimes implied. At a top level many programs can have a dependency on the operating system, an application server, a database server, etc.  These type of dependencies are often not stated explicitly. For example a Java program requires a Java Virtual Machine (JVM) to run and the fact a program is written in Java implies this and is not explicitly stated by most Java packages as many/most Java programs will not depend on a specific version of that JVM.Dependency management is the approach practiced by software programmers to specify, provision/download, install, update and generally manage the set of dependent code that their product or application relies on.Managing dependencies is evolving to be rather sophisticated and several tools and public package repositories are helping programmers dealing with eventually large volume of dependencies. A large number of these dependencies are for free, libre and open source-licensed (FLOSS) components and their packages.Package dependenciesEach operating system / language / framework tends to have its own (eco) system for FLOSS components:Documenting dependencies in one or more configuration or meta files,Downloading (aka. provisioning) the dependent components from a public FLOSS or private repository of pre-built or pre-packaged programs. This provisioning may occur at build-time or run-time; for instance when JavaScript code is fetched from a remote repository or CDN when you load a web page.These systems are common in Linux distros, Java/Maven, JavaScript, Ruby, Python. And there are millions of these FLOSS packages readily available for download and installation. Some of these repositories and tools include:JavaScript - NPMs for NodeJS,Ruby - GEMs from RubyGems,Python - Wheels from Pypi,Java - JARs from Maven,Linux packages such as RPM and Debian,and many more.Dependencies are often weakly defined and variable: A dependency statement may include a range of possible versions for a dependent package and if a dependecy is required or optional. Package systems compute (aka. resolve) a list of concrete dependencies when you provision packages using these definitions.The dependency relationship between two programs may be more or less intimate:At arm's length, when the programs are entirely separated and may only communicate by writing or reading files, or by network interactionAt a handshake level - where the programs call each other's subroutines (aka functions) directly and exchange data directlyOr extremely intimate when merged or combined into a single larger (executable) programProgram dependencies: programs can be compiled and combinedOften programs are compiled: the text of the programs source code is transformed in a binary code that the machine can understand and execute. For instance programming languages such as C, C++, Java, Go require this compilation. But not always: some programming languages are executed directly from the source code when you run them and do not require pre-compilation (or are compiled on the fly when you run them). For instance JavaScript, Python, Ruby or Perl code does not require ahead-of-time compilation, though it is sometimes compressed or minified or pre-compiled.With the compilation process, several programs can be combined into larger (binary) programs. Combining programs together this way is often called static linking when things are merged into a larger binary program.Free, libre and open source licensing and dependenciesMany software licenses have different requirements for source code and binaries (BSD, MIT), have specific terms about the implication of how programs are combined and depend on each other (L/GPL).  Limited Copyleft and Copyleft licenses impose some constraints on how other (proprietary or not) programs can be combined or interact with copyleft code. For instance, the LGPL explicitly discuss static vs. dynamic linking. These are concepts originally defined in compiled languages such as C and C++. They do not always translate well to other dynamic languages and this require some adjustments to apply these terms in these other language contexts. Permissive licenses typically impose few constraints on how you can combine programs. For Copyleft licenses, how (proprietary- or non-Copyleft- licensed) programs and Copyleft-licensed programs are used together, how they depend and interact with each other is the essence of what triggers the Copyleft clauses of the GPL and LGPL. Remember that the relationship between programs and their dependencies can be more or less intimate: Arm's length, Handshake, Merged. Copyleft licenses may impact proprietary or non-copyleft code based on the nature of the dependencies and interaction between programs:Any Handshake or Merged relationship with a GPL-licensed program implies that GPL becomes the primary license for that combined programAny Merged relationship with LGPL-licensed programs implies that LGPL becomes the primary license for that combined programArm's length is similar to independent process or command line, Handshake is similar to dynamic linking, Merged is similar to static linking.Relationships may flow through the Dependency chains and the related licensing requirement may also follow through. What if a  proprietary program depends on a program that depends on a program that depends on a program that is GPL-licensed? It depends!What is the type of relationships at each step?What is the license of the intermediate programs?Eventually the GPL license may flow up or down to the proprietary program for an Handshake or Merged style of relation, unless some licenses have exception to stop this flow (e.g. such as the Linux in user space exception to the GPL license) or the nature of the interactions changes through this chain. (such as when a dependent program is used at Arm's length).An approach to handle dependencies and license complianceTo properly handle dependencies -- whether you write proprietary or FLOSS-licensed code -- my recommended approach would be to:Evaluate the likely dependencies for a new component or package during selection / evaluationConfirm actual dependencies when you build for your product, application or libraryEnsure that you consider the whole chain of dependencies, both direct and indirect and at full depthConsider the purpose of each program or package in that chain (test, tool, compilation, runtime, etc.)Determine which dependent are used only at development time, which redistributed with your product, application or library vs. which may be installed by your userDetermine the license of each dependency in this chainEvaluate what licensing requirements flow up or down this chain and determine what actions are required to comply with licensingUsing these elements you can define a policy for which relationship may be acceptable or not in your context and what are the obligations derived from using dependent packages or programs.