Most software engineers have found themselves in situations where they are asked by non-software people why some fundamental engineering principle is true. First you bug your eyes out and balk, then resist the urge to say "It's obvious!" and storm away, and then ponder that if it really is indeed so obvious, shouldn't the explanation also be obvious? I found myself in two such situations this week, and in both cases was able to use Big-O algorithm analysis (otherwise known as basic complexity theory) to explain my point. Which was also an excellent excuse to draw graphs on the whiteboard.
1. Why write unit tests?
Who likes to manually test software by hand? Not me. It's boring, repetitive, and time-consuming. There's a time and place for repetitive, time-consuming tasks and that's called knitting. So, how do you minimize your manual testing burden? By writing unit and functional tests. Why is it such a time saver? If you didn't write tests, then every time you changed a single piece of logic in your system, to be sure this change didn't cause any unintended side-effects, you'd have to go through and test the whole system. And of course most people don't have time to do that, so they only test everything before each release. So, if you make n changes or improvements to your system, and you manually test everything before every release, this is order-n work to make all your changes, then another order-n work before each release to test the system. In total you have to do n*num_releases testing work. So the amount of testing you need to do scales, at minimum, linearly with the number of changes you make to your system. If you were very virtuous (which you never have time for) and tested the whole system after every change you made, then the cost of each change would be n-squared work instead of n.
If you write a test for each piece of functionality you create (preferably before you create it), you only need to simply run all your automated tests after you make a change to see if you broke something. So let's say the cost of running the existing tests is negligible, and writing a test is about as much work as writing the functionality (though usually it's much easier). So if you make n changes to your system, for each change you write a test. Let's say this is 2*n total work for n changes made. You need to do no additional manual testing when you make a new change, you just run your existing tests. And before each release, you can just run all your existing tests. So the total amount of work you need to do is a constant factor of the amount of functionality you build: 2*n, and the amount of manual testing before each release is some constant. This scales way better than doing order-n manual testing work before each release (or not doing enough testing and having buggy releases). It's a slightly bigger initial investment, but pays off with less future maintenance work.
2. Why worry about limiting dependencies between people or teams? (aka, why you should leave the software engineers alone so they can just write code)
Let's say you have n entities in your corporate system. In a small company these entities may be individual people, and in a large company these entities may be groups or teams. Entities can have dependencies on each other: like engineers getting approval from management before releasing a new feature, or a software group needing a framework group to fix a bug in a framework before they can fix their performance problems. Let's think about these entities as nodes in a graph, and dependencies as edges between nodes.
A node with many edges is a process bottleneck. An example is a person who must personally oversee all changes before they are released on a website, or a framework that all projects depend on, or a scarce resource (like an Oracle DBA). If you don't limit dependencies in this graph, worst case you have a fully connected graph, which has order n-squared edges. Dependencies translate into added work, and lost time waiting on a blocking task or person. So let's say the number of edges in the graph correspond to the amount of work that needs to get done. If you don't explicitly limit dependencies between entities, you can easily get into situations where there are order-n entities (workers) and order-n-squared edges (work to be done). Not only is this more work than your workers can possibly accomplish even if they work twice as hard (n squared is still > 2n), at every time step the gap between work created and work finished grows bigger. This is bad- it means the farther you get into a project the more you get behind schedule. This can be avoided by explicitly limiting dependencies to a constant number of edges per node. This will ensure that you have order-n edges in your graph of n nodes, and your organization isn't creating more work for itself than it can handle. Ways to do this? Let people report to only one manager instead of several, don't page the whole company over a network issue- just page the networking team, let the software engineers just write code instead of additionally acting as tech support and project managers and deployment engineers all at the same time.