Guidelines for Choosing a Computer Language:|
Support for the Visionary Organization
Appendix C: Language Characteristics
The following language characteristics are used in Table 2 in the main document. They are defined below [Lawlis 89] [Pratt 84], along with an explanation of what each characteristic contributes to software development. Although these characteristics are not entirely independent, they are the characteristics of common interest to most decision makers. The value assigned to each characteristic is a number between 0 and 10, where 0 means the language support for this characteristic is extremely poor or non-existent, and 10 means the language support for this characteristic is extremely good or as good as it could possibly be.
It should be emphasized that the ratings given to the characteristics from this appendix are an indication of the extent of language support for the characteristics. Actual programs written in a particular language will vary widely with respect to these characteristics, depending on both the support provided by the language and the skill and discipline of the programmers.
Clarity of source code – the extent to which inherent language features support source code that is readable and understandable and that clearly reflects the underlying logical structure of the program.
Most of the life cycle cost of a software system (usually between 60% and 80%) will come during the time after its initial development has been completed [Schach 93] [Sommerville 89]. This includes all efforts to change the software, whether it is to fix problems or to add new capabilities. Regardless of the purpose, changing the software implies that a significant cost will be associated with understanding the program and its structure, since this is a necessary first step before any changes can be made. Although it is always possible to use techniques to make a program easier to understand, language support for source code clarity can facilitate this process considerably. Note that clarity is a readability issue, not necessarily an ease of use issue. It is not unusual for languages with good readability to be somewhat more verbose than less readable languages.
Complexity management (architecture support) – the extent to which inherent language features support the management of system complexity, in terms of addressing issues of data, algorithm, interface, and architectural complexity.
The more complex a system becomes, the more important that its complexity be managed. Waiting until a system gets large enough to manifest complexity before preparing to manage that complexity does not work well. Properly structuring a system from the beginning, as well as using appropriate supporting tools, is essential. However, complexity management is always difficult, and it is very helpful if the language can facilitate this goal.
Concurrency support – the extent to which inherent language features support the construction of code with multiple threads of control (also known as parallel processing).
For many types of applications, multiple threads of control are very useful or even necessary. This is particularly true of real-time systems and those running on hardware with multiple processors. Concurrency is rarely directly supported by a language, and, in fact, the philosophy of some languages is that it should be a separate issue for the operating system to deal with. However, language support can make concurrent processing more straightforward and understandable, and it can also provide the programmer with more control over how it is implemented.
Distributed system support – the extent to which inherent language features support the construction of code to be distributed across multiple platforms on a network.
It is becoming more and more common for the software components of systems, particularly very large software systems, to be distributed across multiple platforms on a network. In this networked configuration, each platform performs some portion of the system processes, communicating with the other platforms to accomplish the overall system functions. This makes sense for various reasons, with performance right at the top of the list. However, distribution creates many new problems, not the least of which is that the multiple platforms are generally heterogeneous (different hardware and/or operating systems). The problems of distribution can be dealt with by tools rather than language (see the software engineering factor Tool support for interoperability requirements). However, some newer languages also address the issues of distribution.
Maintainability – the extent to which inherent language features support the construction of code that can be readily modified to satisfy new requirements or to correct deficiencies.
Support for code clarity has already been mentioned above as one type of support for maintainability. Maintainability is actually facilitated by many of the language characteristics mentioned in this appendix—those which make it easier to understand and then change the software. The structure of the code also has a significant impact on how easy code is to change. The technique of encapsulating units and limiting their access through well-defined interfaces greatly facilitates maintainability. Hence, language features which facilitate encapsulation can be very beneficial.
Mixed language support – the extent to which inherent language features support interfacing to other languages.
This should not be confused with the complementary product support that provides calling interfaces (called bindings) for specific languages. Bindings are discussed in Appendix F, under the product characteristic tool support for interfacing with other languages. Mixed language support, from the perspective of the language, means the provision of specific capabilities to interface with other languages. This type of support can have a significant impact on the reliability of the data that is exchanged between languages. Without specific language support, no checking may be done on the form, or even the existence, of data exchanged on a call between units of different languages, and the potential for unreliability is high. Specific language support can provide the expected reliability.
Object-oriented programming support – the extent to which inherent language features support the construction of object-oriented code.
There is general agreement that object-oriented programming support means specific language support for the creation of code with encapsulated classes and objects, inheritance, and polymorphism. This form of programming is associated with software that has good maintainability characteristics because of the encapsulation of classes and objects. It also facilitates the creation of reusable software because it encourages well-structured software with well-defined interfaces, and it encourages extending existing abstractions. There are two different ways a language can provide object-oriented programming support. Some languages are strictly object-oriented and do not support any other form of programming. Other languages provide object-oriented capabilities along with more conventional programming capabilities, and the programmer determines whether or not the language is used to create object-oriented software. For this language characteristic, the specific mechanism for providing the capability is not the issue, the extent of support is.
Portability – the extent to which inherent language features support the transfer of a program from one hardware and/or software platform to another.
To make software readily portable, it must be written using non-system-dependent constructs except where system dependencies are encapsulated. The system dependent parts, if any, must be reaccomplished for the new platform, but if those parts of the software are encapsulated, a relatively small amount of new code is required to run the software on the new platform. Language support for portability can come from support for encapsulation, and it can also come from support for expressing constructs in a non-system-dependent manner. Language standardization has a significant impact on portability because non-standard language constructs can only be ported to systems that support the same non-standard constructs—for example, if both systems have compilers from the same vendor. In some circles, the issue of existing compatible support products, including compilers, on many different platforms is considered in the concept of portability. Note that a language’s portability characteristics can be severely compromised by poor programming practices.
Real-time support – the extent to which inherent language features support the construction of real-time systems.
Real-time systems have mandatory time constraints, and often space constraints, that must be met. These will usually tax both the software and the hardware of the system, and system performance predictability becomes an important issue. Language can support real-time systems in two ways. A language can provide specific constructs for specifying the time and space constraints of a system. It can also support streamlined ways to express program instructions. For example, real-time systems often have unique requirements in areas such as device control and interrupt handling, and a language can support managing these in a straightforward, predictable manner. Since many real-time systems are concurrent systems, real-time support and concurrency support are closely related.
Reliability – the extent to which inherent language features support the construction of components that can be expected to perform their intended functions in a satisfactory manner throughout the expected lifetime of the product.
Reliability is concerned with making a system failure free, and thus is concerned with all possible errors [Levesen 86]. System reliability is most suspect when software is being stressed to its capacity limits or when it is interfacing with resources outside the system, particularly when receiving input from such resources. One way that interfacing with outside resources occurs is when users operate the system. Reliability problems often surface when novices use the system, because they can provide unexpected input that was not tested. Interfacing with outside resources also occurs when the system is interfacing with devices or other software systems. Language can provide support for this potential reliability problem through consistency checking of data exchanged. Language can provide support for robustness with features facilitating the construction of independent (encapsulated) components which do not communicate with other parts of the software except through well-defined interfaces. Language may also provide support for reliability by supporting explicit mechanisms for dealing with problems that are detected when the system is in operation (exception handling). Note that poor reliability in a safety-critical portion of the software also becomes a safety issue.
Reusability – the extent to which inherent language features support the adaptation of code for use in another application.
Code is reusable when it is independent of other code except for communication through well-defined interfaces. This type of construction can occur at many levels. It is very common, for example, to reuse common data structures, such as stacks, queues, and trees. When these have been defined with common operations on the structures, these abstract data types are easy to reuse. When reusing larger portions of code, the biggest issue for reusability is whether the interfaces defined for the code to be reused are compatible with the interfaces defined for the system being created. This is significantly facilitated by the definition of a software architecture for the domain of the system under construction. If those defining the components to be reused are aware of the architecture definition, then they can follow the standard interfaces defined in the architecture to ensure the code is reusable for other systems using the same architecture. Reuse at any level can be facilitated by language features that make it easy to write independent (encapsulated) modules with well-defined interfaces.
Safety – the extent to which inherent language features support the construction of safety-critical systems, yielding systems that are fault-tolerant, fail-safe, or robust in the face of systemic failures.
Safety is related to reliability, but it is a great deal more. The more reliable a system is, the more it does what is expected. A system is safe if it protects against physical danger to people, as well as against loss or damage to other physical resources, such as equipment. This implies that the system must always do what is expected and be able to recover from any situation that might lead to a mishap or actual system hazard. Thus, safety tries to ensure that any failures that do occur result in minor consequences, and even potentially dangerous failures are handled in a fail-safe fashion [Levesen 86]. Language can facilitate this through such features as a rigorous computational model, built-in consistency checking, and exception handling.
Standardization – the extent to which the language definition has been formally standardized (by recognized bodies such as ANSI and ISO) and the extent to which it can be reasonably expected that this standard will be followed in a language translator.
Most popular languages are standardized through at least ANSI and ISO, but an important issue here is that the language definition that is supported by a compiler product may not be that which is standardized. Most languages have evolved in a manner that has produced a proliferation of different dialects before the language was standardized, and the result has been that most compiler products support non-standard features from these dialects in addition to the standard language. Some of these products also support a mode that enforces the use of only the standard language constructs, but programmer discipline is still required to use this mode.
Support for modern engineering methods – the extent to which inherent language features support the expression of source code that enforces good software engineering principles.
Support for modern software engineering methods is support that encourages the use of good engineering practices and discourages poor practices. Hence, support for code clarity, encapsulation, and all forms of consistency checking are language features that provide this support. Also, support for complexity management and construction of large systems and subsystems support software engineering tenets.
|< Previous Page||Search||Contents||Tables||Next Page >|