Sergey Nivens - Fotolia
When developers create software, the end product is rarely ever a self-standing entity. Software development is not an island but an ecosystem of libraries, components and interrelated applications. It's the whole interconnected nexus that actually provides users tangible benefits.
Dependencies are the relationships between components, and they enable applications to have more features and functionality. Simple dependencies can include certain OS versions, application servers, database servers or a Java virtual machine. But some dependencies are complex, such as those comprised of varied packages in Linux, Java and scripting languages, like Python and Ruby.
However, complex dependencies can drag down software installation and reliability. In fact, when dependencies are missing, outdated or incompatible, they can prevent proper installation, stop the software from running, spawn unexpected exceptions, cause crashes or otherwise impair performance. Such conditions result in more support calls, user dissatisfaction and depressed product adoption.
Organizations must commit time to software dependency management to alleviate many of these problems. With dependencies under control, developers can deliver products that install and run more easily across a greater variety of platforms.
Dependencies exist at several levels. At the highest level, a dependency might not relate directly to the software at all but simply share files and communicate across a network. High-level dependencies typically include OSes and web servers -- the aforementioned simple dependencies. At another stratum, handshake dependencies can initiate functions in other programs and exchange data with them, as is common when one program uses another through an API. The deepest dependencies occur when developers combine programs into a larger program. These couplings manifest with many compiled products, such as Linux distributions, that combine to create a uniquely tailored offering.
Since dependencies can take numerous forms, it's easy to end up with too many. When software depends on many packages or components, the application might have significant compatibility problems and can be plagued by long downloads, plus require lots of storage space. Similar problems occur with long dependency chains, where components depend on other components, and so on.
Dependencies can conflict when multiple applications rely on different, incompatible versions of the same dependency. For example, if an application depends on component A.1 and another application depends on component A.2 but apps cannot install A.1 and A.2 together, a conflict occurs, and many conflicts are more convoluted than this example. In such circumstances, both apps cannot run on the same system at the same time, or the application with the older dependency might need an update to use the current dependency.
Circular dependencies can affect software applications or constituent components. Suppose that application A.3 depends on application B.6, and application B.6 simultaneously depends on application A.3. In this case, it's impossible to update either application without causing problems for the other. So, it might be necessary to update both applications to compatible versions or continue to work with the old versions if both cannot be updated.
The litany of potential problems led to the discipline of software dependency management. When practiced properly, dependency management helps developers discover, monitor and -- ideally -- mitigate onerous effects from libraries, components and other applications upon which software depends.
How to overcome dependencies
Software dependency management doesn't try to remove all connections between app components, as that goal is impractical and perhaps not even desirable. No developer would create a server OS when it's far easier to rely on a well-regarded OS, such as Windows Server or Red Hat Enterprise Linux. Similarly, it's often far more efficient to use existing graphics libraries, databases and other mature components than it is to invest time and resources to create everything from scratch. Instead, with software dependency management, teams try to identify and understand any prevailing dependencies and then minimize dependencies wherever it makes sense for the project at hand.
So, once you understand the nature of dependencies, here are several ways to manage them.
Map dependencies. If you don't know where the dependencies are, you can't optimize them. There are many tools available to help map dependencies, such as automated build tools, like Apache Maven and Ant -- and, specifically, the Apache Ivy dependency manager. These tools help you detail and track software dependencies through the build and deployment process. When you map dependencies at the outset, you can look for opportunities to optimize.
Eliminate unnecessary dependencies. Think about how an application uses libraries and components. One app might only use a small subset of a large library's features or capabilities, while another might use a large number of small components. In such cases, it makes sense to code those smaller features and functions directly into the application, rather than rely on other components.
Improve dependency checking. If you cannot use dependency checking as part of a managed package, other tools can help identify dependencies and even recommend dependency updates at installation time. Microsoft's Dependency Checker can verify that prerequisite files are present on a target machine upon installation. And Open Web Application Security Project's Dependency-Check identifies Java and .NET project dependencies and checks if there are any known vulnerabilities.
Dependencies are unavoidable in modern software development, so organizations must identify and manage dependencies with diligence and care.