Elegance is a word that traditionally conjures up images of tasteful opulence, refinement, and grace; of swans appearing to glide effortlessly across the surface of a lake or gentle, meandering river. Elegance is epitomised by a lack of clutter, fuss, and complication. Of course, behind the appearance of effortless elegance may lie considerable hard work. The swans may be paddling frantically under the surface of the water to counter a strong current, and a suite of elegant rooms may have taken hours of painstaking cleaning, arranging and rearranging.
In software development, as in mathematics and engineering, an elegant solution achieves the maximum desirable effect with the smallest or simplest effort. Many mathematicians, engineers, and computer scientists derive great satisfaction from discovering a simpler, less wasteful solution to a problem.
In software development, inexperienced developers are often tempted to include complicated, clever ticks or obscure programming language features in their work. Designers are often tempted to over-engineer by adding multiple levels of flexibility or a myriad of configuration options. In both cases, the price paid is unnecessary complexity, fuss, and clutter, adding significant time and effort to testing, reviewing, and documenting the designs and code. In addition, the software is likely to be harder to maintain and extend, and frequently harder for the users of the software to learn and use correctly.
Unavoidable complexity in software comes from a number of sources including:
- complexity in the problem domain (real world)
- the need for increased speed and efficiency (optimisation)
- the technical nature of the software (e.g. thin client, service-oriented, real-time, high-performance, etc)
Dealing with this inherent complexity is the job of abstraction and encapsulation, hiding the complex details of the specifics behind simpler interfaces, usually object-oriented or service-oriented. Picking better abstractions, better service, better classes requires ability, experience and insight. The most elegant, simplest design that does the job is rarely obvious at the start of a software development effort. It can take considerable, collaborative and iterative effort to arrive at what then seems obvious in hindsight. Software design is a process of ongoing discovery and refinement.
Fortunately, software development teams do not need to start the discovery process from scratch. Strategies, patterns and techniques like 'Modeling in color', 'Streamlined Object Modeling', and 'Domain-Driven Design' can significantly help pare down complexity in the problem domain. To optimise performance, proven, published algorithms, and data-structures can replace simpler, less-efficient implementations leaving interfaces unchanged. Finally, good design patterns, proven coding idioms, and effective libraries and frameworks (open-source or commercial) can help address the complexity inherent in type of software being constructed.
In recent years, Apple have come to be synonymous with elegance in the design of computer hardware including everything from desktops, laptops, and tablets to smart phones, music players, and related accessories. The harder challenge for Apple is to maintain, create and integrate the same level of elegant design throughout the software that runs on theses devices and behind them in 'the cloud'; something they have usually done very well when compared to their competition but far from perfectly when compared to the design levels of their own hardware.
In addition, I do not believe it is possible to analyze the functional requirements of a desired software system without making assumptions about the structural parts and components of that system. In making those assumptions we are synthesizing a solution, we are designing. You cannot ever fully separate requirements analysis from design, and analysis and design are an inherently iterative process. Nevertheless, iterative analysis and design does not mandate that it must always be done through the medium of source code.