5.11 Languages and Software Engineering

Programming languages that support

  • the construction of abstractions, and

  • ease of program modification

also support

  • ongoing development of a malleable program design, and

  • the evolution of a prototype into product.

Let us unpack these aspects of software development.

5.11.1 Building Blocks as Abstractions

An objective of this chapter is to demonstrate the ease with which data structures (e.g., binary trees) and reusable programming abstractions (e.g., higher-order functions) are constructed in a functional style of programming. While Lisp is a simple (e.g., only two types: atom and S-list) and small language with a consistent and uniform syntax, its capacity for power and flexibility is vast, and these properties have compelling implications for software development. Previously, we built data structures and programming abstractions with only the three grammar rules of λ-calculus. Functional programming is much more an activity of discovering, creating, and then using and specializing the appropriate abstractions (like LEGO® bricks) for a set of related programming tasks than imperative programming is. As we progress through this book, we will build additional programming abstractions without inflating the language through which we express those abstractions—we mostly remain with the three grammar rules of λ-calculus. “[T]he key to flexibility, I think, is to make the language very abstract. The easiest program to change is one that’s very short” (Graham 2004b, p. 27). [While Lisp is a programming language, it pioneered the idea of language support for abstractions (Sinclair and Moon 1991).]

5.11.2 Language Flexibility Supports Program Modification

Another theme running through this chapter is that a functional style of programming in a flexible language supports ease of program modification. We not only organically constructed the functions and programs presented in this chapter, but also refined them repeatedly with ease. A programming language should support these micro-level activities. “It helps to have a medium that makes change easy” (Graham 2004b, p. 141). Paul Graham (1996, pp. 5–6) has made the observation that before the widespread use of oil paint in the fifteenth century, painters used tempera, which could not be mixed or painted over. Tempera made painters less ambitious because mistakes were costly. The advent of oil paint made painters’ lives easier on a practical level. Similarly, a programming language should make it easy to modify a program. The interactive read-eval-print loop used in interpreted languages fosters rapid program development, modification, testing, and debugging. In contrast, programming in a compiled language such as C++ involves the use of a program-compile-debug-recompile loop.

5.11.3 Malleable Program Design

The ability to make more global changes to a program easily is especially important in the world of software development, where evolving specifications are a reality. A language not only should support (low-level) program modification, but also, more broadly, should support more global program design and redesign. A programming language should facilitate, and not handicap, an (inevitable) evolving design and redesign. In other words, a programming language should be an algorithm for program design and development, not just a tool to implement a design: “a language itself is a problem-solving tool” (Felleisen et al. 2018, p. 64).

5.11.4 From Prototype to Product

The logical extension of easily modifiable, malleable, and redesignable programs is the evolution of prototypes into products. The more important effect of the use of oil paint was that it empowered painters with the liberty to change their mind in situ (Murray and Murray 1963), and in doing so, removed the barriers to ambition and increased creativity and, as a result, ushered in a new style of painting (Graham 1996, pp. 5–6). In short, oil paint not only enabled micro changes, but also supported more macro-level changes in the painting and, thus, was the key ingredient that fostered the evolution of the prototype into the final work of art (Graham 2004b, pp. 220–221).

Like painting, programming is an art of exploration and discovery, and a programming language, like oil, should not only be a medium to accommodate changes in the software requirements and changes in the design thoughts of the programmer (Graham 1996, p. 27), but should also support those higher-order activities.

In programming, an original design or prototype is typically sketched and used primarily for generating thoughts and discovering the parameters of the design space. For this reason, it is sometimes called a throwaway prototype. However, “[a] prototype doesn’t have to be just a model; you can refine it into the finished product. . . . It lets you take advantage of new insights you have along the way” (Graham 2004b, p. 221). Program design can then be informed by an invaluable source of practical insight: “the experience of implementing it.” (Graham 1996, p. 5). Like the use of oil in painting, we would like to discover a medium (in this case, a language and its associated tools) that reduces the cost of mistakes, not only tolerates, but even encourages second (and third and so on) thoughts, and, thus, favors exploration rather than planning.

Thus, a programming language and the tools available for use with it should not only dampen the effects of the constraints of the environment in which a programmer must work (e.g., changing specifications, incremental testing, routine maintenance, and major redesigns) rather than amplify them, but also foster design exploration, creativity, and discovery without the (typical) associated fear of risk.

The tenets of functional programming combined with a language supporting abstractions and dynamic bindings support these aspects of software development and empower programmers to embark on more ambitious projects (Graham 1996, p. 6). The organic, improvised style of functional programming demonstrated in this chapter is a natural fit. We did little to no design of the programs we developed here. As we journey deeper into functional programming, we encounter more general and, thus, powerful patterns, techniques, and abstractions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.40.189