How to manage risk and lower blood pressure in software projects

1. The only resource is human resource: track engineer and customer mentality

Machines are weak. They break down, become obsolete, and do only what we tell them to do. It is builders and users that give systems life.
Experienced people will tell you that you should start at the essence of the end product: what is it meant to do, and what purpose do all the actions have?
Now go one level deeper, and make explicit the way of thinking and working of the critical actors within the domain. It is valuable to pay close attention to the ways users and engineers approach problems, and how they interact with the domain through software solutions.

In most human endeavors, mentality decides a lot, before any step has been taken in the actual undertaking.
For instance: some spend most of their work time in the type of mental state that could be described as "greedy problem solving". Their mind grasps for quick success for an isolated issue.
Others work in a way that one could call "strict gardner", working to keep everyone's work in sync with the end-user domain. This helps in making technology mirror the expertise it supports.
Then there are visionaries, that are able to keep things on track towards a far-away goal.
There are also the "butchers" (meant in a good way), that are able to divide a large challenge into sub-issues that one or two people can solve in a day.
For the less technical side, there are the great "spiders" and their webs (again, meant in a good way), that keep track and soak up information, and help others stay on course.
To bring these together, it can be great to have a "poker player" type, that can take educated guesses, when there is no time to study all alternatives, and no budget to try things out.

It is imperative to track these ways of thinking and doing, and not approach team-building and product planning purely from an accountancy angle. Scalable, high-tech software products are not like linear brick making, and cannot be reduced to time KPI's.
There are plenty of resources on how to assess people's psychology. Applying knowledge of human nature is a must for teams comprised of tech specialists and domain experts, as it is the best way to utilize skills, preventing fundamental errors. It is also the only way to create synergy, and make use of everyone's abilities, while balancing their shortages.


2. Focus on fundamentals, not vendor fads

Overspecialisation and segmentation can be a challenge for many teams. Countless professional profiles are stories of improvement in one segment of one field. When these are assembled for a greater purpose, there is little overlap between their skills and approaches to problem solving. This lack of overlap makes the solution structure brittle, and prone to failure at the first obstacle.

In order to assemble better teams, more attention should go to basic skills, knowledge, and problem-solving approaches. That does not mean low-level math or language tricks. It does mean the abilities of choosing a practical algorithm, data structure, and architectural approach to a problem. It can mean coding automated tests for logic, performance, connection loss and restartability, for one's own and each other's work.
And it also means adjusting one's approach so that a large part of the team will find it workable, and being able to communicate intent and strategy though code alone.

Such foundations enable teams to build solutions that closely align to the domain they are working for. The closer this alignment, the more requirements become like grocery list of "get this data", "enrich these wrapper objects", "find matches for these targets".
In order to even get on track with this, one does need to outflank the gatekeepers of IT supply and demand, who have only read about "language x", "system y", even to the level of specific versions.

From the management side, it is important to heed the fundamentals of team relations:
  • seek second opinions, as cost-effective products might be available that already solve what you are planning to build
  • keep a good base of predictable actions and processes; preventing too much "and now for something completely different" situations
  • small teams should not promise/sell SLAs and such, expecting teams to be constantly on standby, and working on complex problems waiting for suddent alerts
  • do not treat engineers like fast-food order takers, treating complex exploratory projects like assembly line tasks that take a predicted amount of time
  • map risks and, together with the team, choose a way of handling them: avoidance, getting rid of, acceptance, insurance
  • actually make choices; you cannot have a product with crystal ball time predictions AND max uptime AND no give-and-take as far as data correctness AND extreme robustness and restartability AND have experts on constant standby; not making a choice = failure


3. Minimize complexity of code, regardless of what is solves

Most systems have a life-span. They can continue beyond their life-span, but become a net-loss as soon as changes are required, because of the piling up of quick & dirty fixes. If the roles not directly involved in dev have no understanding of software degeneration and technical debt, the life-span probability of systems drops with every change, until no-one wants to deal with it.
 

 A number of approaches can help, both when setting up new systems, and improving existing ones:

  • use the proper terms, either related to the discipline the system is for, or technical terms; don't invent your own terms, unless to simplify jargon
  • write code for the collective, not yourself; make things as understandable and reproducable for others as possible
  • agree upon code formatting rules, and make these formats easily applicable
  • invest in libraries of routines that you use for boilerplate work, and that helps reduce deeply nested genius code to simple grocery-list ABC's that are as close as they can be to requirements
  • channel operations via methods that allow simple adjustment, such as failing entire calls on 1 failure or letting as much through, or tweaking how many objects are transmitted per call
  • separate calls to different systems, such as (API) calls to outside services and "calls" to the DB
  • enrich most of your code with configurable steps, in order to be able to diagnose memory usage, time, performance per object, and extend unit testing
  • create and nurture neat wrapper objects and parameter wrappers, that you can "talk" to with simple requests that do exactly what their name says
  • where possible, shape code so as to be callable from outside systems or methods of input that can be configured by less technical people
  • let your team play with experimental projects regularly, in order to maintain creativity, playfulness, and effective communication between team members
  • try and work via a microservice-like architecture (even if there are no actual network-enabled microservices)
  • read the Bible (a.k.a. Refactoring by M. Fowler) when you start a productive day and before going to sleep; you will probably get a lot of Deja Vu (good) by reading up on patterns, and find some novel approaches to reduce risk (great)
  • find a pragmatic way to map the geography of the most important data, actions and interfaces between systems, so noone gets lost
  • discuss and agree on a balance between minimizing technical debt VS quick & dirty solutions


4. Focus on return-on-investment via reuse & resell

The goal of information technology is to develop once, sell many times. If this is not the case, something is wrong. The essence of IT as a business is that it enables going far beyond doing something and only reaping the benefits once. That is normal, traditional labour.
If the prior steps have been respected, it will be more practical to pick building blocks and build a solution that pays dividends. This frees up time and money for new creative ventures. If your business does not do this, others will, and it will become harder to gain on their advantage.
In your development cycle, numerous forks in the road will present themselves. It is wise to take the approach that enables future reuse, if other factors allow this. Simply thinking about possible reuse, and challenging each other with low-risk reuse options, will steadily build up systems that can keep their earning power in the future.
Together with keeping the focus on proper software construction fundamentals and risk reduction, this creates time and energy for playing around with new technology, because "the machine" keeps earning money while you sleep.
One concrete method to keep track of the value added of code is to enrich your (main) methods with logging that traces how much data or actions has been processed. If the business can come up with a value measurement, running a program will give an indication of its worth. This can be used with example data a potential customer gives you to prove the value of a software solution. Nothing sells better than demo-able solutions. This can enable you to be first in the market, and enable scale.


5. Always be closing

Divide and conquer large projects into small modules. Work based on agreed upon contracts/interfaces for these building blocks, and get the stakeholders to sign (close) each small module iteration, OR precisely indicate what they want changed in order for them to sign.
Do not allow projects to become promises that strech over many months, where customers can push drastic changes to base blocks in an advanced stage. Be always on the lookout for ways to focus development into definable modules, that can be both technically closed (work via interfaces, strict responsibilities) and contractually (signature before other modules based on this one are worked on).


6. And now your projects can run much smoother

If you've incorporated these approaches into your routines, you are ready to put it all together with a few more obvious actions.
  • Incrementalism: build reusable building blocks and test these until all stakeholders are happy, and the results can be used as the base for the next components
  • Incentives: make explicit what the incentives are of engineers and supporting roles, based on the fundamentals of software, minimization of complexity, and increasing of ROI. Configure these to be in sync with each other, both in your IT teams, and at client points of contact.
  • Responsibilities: discuss and agree upon individual and group areas, and prevent one role being responsible for something another role does. While domain knowledge should overlap in order to enable communication between disciplines, what roles are responsible for should have clear demarcations.
  • Planning: set up calendars per customer / supplier to plan relevant dates when systems change. This helps planning releases and upgrades. Set up simple project phase plan boards, and focus on tech and business goals, not fixed dates. Agree upon a "zoomed-out" capacity planning everyone can live with.
  • Improvement: keep training each other, but focus on fundamentals, not on x version of vendor y. Time-dependent knowledge is useful, but dangerous in the hands of those with not enough mastery of basic problem-solving patterns and risk reduction experience.

To sum up: track mindset, inspect each other's work and knowledge of the client domain. Build along the lines that the domain way of working and thinking indicates. Ensure overlapping knowledge between roles. This reduces information lost in translation, and enables collaboration. In this way, everyone will be able to track progress quicker. This will enable you to lift off from the crystal ball predicting of hours to the infinite possibilities of ROI.