National Research Council: Ada & Beyond
[Contents] [Part 1] [Part 2] [Part 3] [Part 4] [Part 5] [Part 6]
DOD Draft Software Management Policy Directive
with Further Modifications Suggested by the Committee
The Committee on the Review of the Past and Present Contexts for the Use of Ada in the Department of Defense reviewed the DOD policy currently in use for programming language selection ("Computer Programming Language Policy," DOD Directive 3405.1, dated April 2, 1987), as well as two different draft revisions of that policy. This appendix contains the most recent draft (dated May 15, 1996) reviewed by the committee and incorporates modifications suggested by the committee to make the directive consistent with the recommendations presented in the main text of this report. Modifications are noted in italic font.
This modified draft directive is intended to serve as a "template" for development of the new DOD Directive 3405.1. The "enclosures" that are typically attached to DOD directives have been omitted for brevity. However, a list of references follows the text of the draft directive, and technical terms are defined in Appendix C of this report; both sets of documentation are suitable as enclosures for the revised formal DOD directive. The enclosure titled "Ada Waiver Procedures" has been omitted from the template because the committee eliminated the waiver process in its recommended policy. Other emendations of the draft text to condense wording or otherwise revise original text are not strictly documented; comparison with the May 15, 1996, draft directive shows minor changes not accommodated by the device of italicizing more substantial revisions.
PROPOSED TEMPLATE FOR DOD DIRECTIVE ON SOFTWARE MANAGEMENT
A. REISSUANCE AND PURPOSE
|76||Ada and Beyond: Software Policies for the Department of Defense|
1. Updates and establishes policy for management of software developed, used, or maintained by, or for, the Department of Defense (DOD).
2. Is used in software management decisions across a functional or mission area, domain, or product line. It contains broad software engineering and programming language policy that will be followed by DOD.
3. Establishes the requirement for a Software Engineering Plan Review Board (SEPRB) by the Office of the Secretary of Defense (OSD), the Military Departments (including the National Guard and Reserve Components), and the DOD components.
4. Supersedes reference (a); cancels references (b) and (c); implements Federal Information Resource Management Regulation (FIRMR) Subpart 201-24.201, Federal Software Exchange Program (reference (d)); and supports DOD Directive 8000.1 (reference (e)) and DOD Directive 5000.1 (reference (f)) and DOD Instruction 5000.2 (reference (g)).
5. Authorizes publication of DOD Instruction 3405.1, "Software Management Implementation."
B. APPLICABILITY AND SCOPE
This Directive applies to:
1. The Office of the Secretary of Defense (OSD), the Military Departments (including the National Guard and Reserve components), the Chairman of the Joint Chiefs of Staff and the Joint Staff, the Unified Combatant Commands, the Inspector General of the Department of Defense, the Defense Agencies, and the DOD Field Activities (hereafter referred to collectively as "the DOD Components").
2. All software developed, acquired, or used by the DOD, including that managed in accordance with DOD Directive 5000.1 (reference (f)).
3. DOD research and development activities funded by 6.4 and 6.5 appropriations as defined in Volume 2, DOD 7000.14-R, (reference (1)).
4. Software developed, acquired, or used by DOD research and development activities, and funded by 6.1, 6.2, and 6.3a appropriations, is exempted from this directive.
Committee note: Terms used in this directive and modifications to it are defined in Appendix C of this report, and those definitions are suitable for inclusion as an enclosure in a new DOD directive.
It is DOD policy to:
1. Perform trade-off and business-case analysis in the development and acquisition of affordable, rapidly produced, high-quality software. Quality includes functionality, fitness for a purpose, assurance (i.e., reliability, survivability, availability, safety, security), efficiency, ease of use, interoperability, future adaptability (i.e., extensibility, maintainability, portability, and compliance with standards), and the development of DOD software expertise. Cost includes full life-cycle cost, consequence of system failure, impact on system operational costs, and use of other scarce resources such as expert personnel.
2. Exploit and contribute to open standards-based technical architectures that support rapid, flexible, and incremental software improvements, and that accommodate increasing reliance on the commercial sector to satisfy evolving mission and functional requirements. Exploit and contribute to
software architectures that serve as the basis for management and investment decisions for reuse opportunities, interoperability requirements, and development or product lines and product-line components. Facilitate the reuse of software assets.
3. Define mission and functional requirements so that commercial and non-developmental items may be used to fulfill such requirements. To the maximum extent practicable, modify requirements and conduct market research and analysis, prior to commencing a development effort, to take advantage of a commercial or non-developmental "best value" solution. Give preference to commercial off-the-shelf (COTS) items first and non-developmental items (NDI) second when satisfying software asset requirements.
4. Implement and continuously improve software process management and software engineering disciplines. Use software engineering environments that facilitate software process management and software engineering disciplines.
5. Employ software developers who possess mature software engineering capabilities. Software developers should have a successful past performance record, experience in the software domain or product line, a mature software development process, and evidence of use and adequate staffing and training in software methodologies, tools, and environments.
6. Use metrics when monitoring and managing production and delivery of software assets, evaluating maintenance and management practices, implementing software architectures and product lines, and effecting continuous software process improvement.
7. Enforce compliance with contractual terms and conditions for use of software, including copyright and license agreements. Centralize this function to the maximum extent practicable.
8. Use commercial fourth-generation programming languages (4GLs) where appropriate, when they provide significant improvements in productivity, usability, maintainability, and portability. Selection of 4GLs and associated tools must be based on established acceptance in the commercial marketplace where benefits of the technology have been demonstrated. Any software code generated using a 4GL must also be maintained in the 4GL.
9. Use the highest-level language meeting quality, cost, and scheduling constraints for each software component. Principles for choice of this language are as follows:
b. Standardized and non-proprietary languages are preferred. Using standards increases portability of code and programmers. Non-proprietary languages reduce the risk of vendor lock-in.
c. New languages must not be developed as part of a system development, except for domain-specific languages providing directives for application generators.
d. Quality, time, and cost factors should be considered in selecting a language.
10. Use the Ada programming language (reference (i)) to develop software subsystems when all of the following apply:
b. Maintenance will be government-directed.
c. The expected size of the subsystem exceeds 10,000 lines of code, or the subsystem is critical.
d. There is no better COTS, NDI, 4GL, or higher-level solution consistent with quality and cost goals.
e. There is no life-cycle cost-effectiveness justification for using another programming language.
f. The code is new or re-engineered.
|78||Ada and Beyond: Software Policies for the Department of Defense|
In cases meeting the above criteria, the required compliance level is set at 95% of the source lines of code. Up to 5% of the code can be written in other languages to facilitate component integration.
11. When the application is in a non-warfighting application area (e.g., office and management support, personnel, logistics, medicine, routine operations support), Ada will be analyzed as an option when substantial 3GL development is to be performed. The analysis will be in accordance with the principles set forth in D.9 above.
1. The Under Secretary of Defense (Policy) shall ensure that requests from DOD Components for guidance on international transfer or export of DOD software are processed and appropriate guidance on such release is provided.
2. The Office of the Assistant Secretary of Defense (OASD) for C3I shall:
a. Provide policy, guidance, and oversight for the management of software consistent with applicable directives, and may issue additional instructions related to implementation of this Directive.
b. Issue policies and guidance to implement DOD software reuse practices and the Federal Software Exchange Program (reference (d)).
c. Direct DOD Components to establish programs, as appropriate, to enhance the software engineering processes and the transition of technologies from commercial and research programs into applications within weapon, automated information systems (AISs), and command and control systems.
d. Establish an OSD-level Software Engineering Plan Review (SEPR) process that will review all software architecture plans for any acquisition subject to OSD milestone decision authority (MDA). The purpose of this review will be to approve and certify the software engineering plans for the system software prior to Milestone I and II reviews. Certification indicates that the software plan conforms to the policy and principles contained within this Directive. For these reviews, the acquisition program shall establish a program-specific Software Engineering Plan Review Board (SEPRB) The SEPRB will be composed of at least 5 members who are software experts, will include key system stakeholders (e.g., users, maintainers, interoperation experts), and will be chaired by a representative of the OASD (C3I).
e. Establish a process for periodic review of SEPRB reviews performed by DOD components.
f. Identify research and development requirements to the Director, Defense Research and Engineering, for inclusion in research and development programs.
3. The Head of Each DOD Component shall:
a. Initiate appropriate strategies and actions to implement the policies in Section D within their areas of responsibility.
b. Establish a component-level SEPR process that will review all software architecture plans for any acquisition subject to component MDA. The purpose of this review will be to approve and certify the plans for the system software prior to Milestone I and II reviews. Certification indicates that the software plan conforms to the policy and principles contained within this Directive and applicable component policies. For these reviews, the acquisition program shall establish a program-specific SEPRB. The SEPRB will be composed of at least 5 members who are software experts, will include key system stakeholders (e.g., users, maintainers, interoperation experts, program executive officials), and will be chaired by a member appointed by the service or component acquisition executive.
d. Delegate to appropriate subordinate organizations the authority to release software assets, as appropriate, to the Federal Software Exchange Program (FSEP), reference (d), and for DOD reuse purposes.
e. Specifically address investment strategies, including use of modern software technology and the transition to newer technologies, in the DOD Component planning, programming, and budgeting process.
F. EFFECTIVE DATE AND IMPLEMENTATION
This Directive is effective immediately.
|(a)||Department of Defense (DOD) Directive 3405.1, "Computer Programming Language Policy," April 2, 1987 (hereby canceled)
|(b)||Assistant Secretary of Defense for Command, Control, Communications and Intelligence (C3I) Memorandum, "Delegation of Authority and Clarifying Guidance on Waivers from the Use of the Ada Programming Language," April 17, 1992 (hereby canceled)|
|(c)||DOD Instruction 7930.2, "ADP Software Exchange and Release," December 31, 1979 (hereby canceled)|
|(d)||Federal Information Management Regulation (FIRMR) Subpart 201-24.201, Federal Software Exchange Program|
|(e)||DOD Directive 8000.1, "Defense Information Management Program," October 27, 1992|
|(f)||DOD Directive 5000.1, "Defense Acquisition," March 15,1996|
|(g)||DOD Instruction 5000.2, "Defense Acquisition Management Policies and Procedures," March 15,1996|
|(h)||DOD Directive TS-3600.1,"
Information Warfare," December 21,1992|
|(i)||International Organization for Standardization (ISO/IEC 8652:1995), "Ada," February 15, 1995|
|(j)||DOD Directive 5200.28, "Security Requirements for Automated Information Systems (AISs)," March 21, 1988|
|(k)||DOD Regulation 5200.1-R, "Information Security Program Regulation," December 1987, authorized by DOD Directive 5200.1, "DOD Information Security Program," June 7, 1982|
|(l)||DOD 7000.14-R, "DOD Financial Management Regulation," Volume 2, "Budget Presentation and Formulation," May 1994, authorized by DODI 7000.14, "DOD Financial Management Policy and Procedures"|
Standardization (ISO) endorsement of the ANSI standard in 1987. The actual design work was performed by a design team, with review by a panel of experts and the interested public at large.
Major concerns in the design of Ada 83 were reliability, maintainability, human engineering, and efficiency. Human engineering refers to choosing keywords, syntax, and semantics to maximize readability, while trying to minimize "surprise" and error-prone constructs. For example, all control flow constructs have a distinct "end," marker (e.g., "end if," "end loop"), and all program units allow the name of the unit to be repeated (and the compile time to be checked) at the end marker. Parameters may be specified as "in," "out," or "in out" to indicate the direction of information flow upon subprogram call. Formal parameter names may be used at the call point to identify unambiguously the association between formal and actual parameters.
Ada 83 supports strong type checking, extended to provide strong distinctions between otherwise structurally equivalent numeric types, as well as between otherwise structurally equivalent array types and pointer types. Ada 83 is unusual in that it allows the programmer to distinguish two same-sized integer types as representing distinct abstractions, and to specify that an array is meaningfully indexed by one, but not the other, or that a subprogram can meaningfully be passed by one, but not the other. For example, the two integer type declarations
type Month_Number is range 1..12
type Hour_Number is range 1..12
introduce two distinct integer types, and the fact that they have identical ranges does not alter the fact that they are distinguishable at compile time when used as array indices, subprogram parameters, and record components. The compiler will detect the use of a value of one type when the other is expected. Furthermore, a change to one, such as switching Hour_Number to be range 0.23, does not have an unintended effect on some other abstraction.
Ada 83 supports data abstraction, modularity, and information hiding through a module construct called a "package" and through "private" types, types whose internal structure is hidden from code outside the defining package. Objects, subprograms, and any other language entity may be declared in the private part or body of a package, thereby hiding it from external access, and allowing revision during maintenance without disturbing external clients of the package.
Program units may be separately compiled while preserving full compile-time consistency checking across units. All program units may have a separate specification and body, allowing the physical configuration control of interfaces to allow productive parallel development of large systems, and enabling interface integrity to be verified before, rather than after, the code is developed.
Packages and subprograms may be defined as "generic" units, which are parameterized by types, objects, and subprograms. Such generic units must be explicitly instantiated with appropriate actual parameters prior to use. Like other units, generic units have a separate specification and body. When a generic unit is compiled, it is checked for legality. Further checks are performed when the unit is instantiated.
Ada 83 defines a complete set of run-time consistency checks to enforce range constraints on numeric types, index constraints on array types, and "discriminate" constraints on other composite types. In addition, all pointers are default initialized to null, and checked for null prior to dereferencing. Ada 83 defines an ability to raise and handle run-time exceptions. The predefined run-time checks all raise such run-time exceptions, allowing the programmer to write fault-tolerant code that catches unanticipated software problems, and performs appropriate recovery or disciplined shutdown actions.
Ada 83 includes a standard multithreading model, with a rendezvous construct to support interthreading communication and synchronization. Explicit delays are supported, as is timed
|82||Ada and Beyond: Software Policies for the Department of Defense|
rendezvous. Finally, Ada 83 includes constructs for explicit user control over representation of types, as well as a "pack" directive to influence the compiler's selection of representation.
The current Ada standard, Ada 95, was developed between 1990 and 1995. As with Ada 83, the development was performed by a language design team, and requirements and review were provided through an open forum. In February 1995, the revised language was approved as an ISO standard, replacing the former edition of the standard. The overall goal of the Ada 95 design process was to maintain the reliability, maintainability, human engineering, and efficiency of Ada 83, while enhancing the flexibility and extensibility of the language, and the programmer's control over storage management and synchronization.
Ada 95 generalized the type definition mechanisms of Ada 83 to allow a type to be defined as an "extension" of another type, and to treat a type and all its extensions, direct and indirect, as a "derivation class" of types, with "class-wide" operations and dynamically bound implementations of operations. Added to the existing support for abstraction and modularity, type extension and dynamic binding give Ada 95 support for the object-oriented programming paradigm.
Ada 95 also enhanced the multithreading model, by providing "protected objects" that allow the programming of data-oriented synchronization mechanisms, without introducing additional threads.
Ada 95 added support for pointers to subprograms, as well as pointers to declared, as opposed to heap-allocated, objects. All access types include an "accessibility" level, which is checked by the implementation, generally at compile time, to prevent the creation of dangling references.
The numeric model was enhanced with the addition of modular (unsigned, wraparound) integers with bit-wise logical operators, and decimal fixed-point types, to support exact financial calculations.
The generic facility was enhanced to allow parameterization by packages that are instances of other generics, so that layered generic abstractions may be defined. In addition, the generic "contract" model was strengthened so that the legality of an instantiation is fully determined by the actual parameters and the generic specification, allowing the body of the generic to be altered during maintenance without endangering the legality of existing instantiations.
Where appropriate, additional run-time checks were defined in Ada 95 to support the enhanced features. In particular, a conversion from a class-wide type to an extension of its root type involves a run-time check to ensure that the conversion is meaningful, as does a conversion from an "anonymous" access type to a named access type to prevent the creation of a dangling reference (based on the "accessibility" level mentioned above).
In addition to these syntactic and semantic enhancements to the language, a number of additional standard packages, pragmas, and attributes are defined in "annexes" to the standard. Some of these packages, pragmas, and attributes must be supported by all implementations, such as packages for string manipulation and random number generation and pragmas for interfacing to other languages. Others are specifically designed to support particular application domains, such as real-time, distributed systems, and safety/security-critical systems.
The C language was designed at Bell Laboratories in the early 1970s, as a successor to the language BCPL, for the purpose of writing an operating system (Unix) and associated utilities for minicomputers. During the late 1970s, C and Unix were used widely in universities, and during the 1980s C emerged as the language of choice for systems programming on minicomputers, workstations,
and personal computers. The ANSI standard for C was approved in 1989, and the ISO standard based on ANSI C was approved in 1990.
C has a sparse syntax, with braces used for begin and end markers in all control flow, program unit, and type declaration constructs. Single-character operators are provided for assignment, indirection, address-of, bit-wise and, or, "xor," and not, and the usual arithmetic operations. Operators are also provided for pre- and post-increment and decrement, operate-and-assign, and left- and right- shift.
Numeric data types are selected by names, such as "short int" or "long float." There is no capability to select a numeric type by required range or precision, and there is no notion of implementation-enforced range constraint. Enumeration data types are supported, but are implicitly convertible to and from integer types in any context.
Historically, interface definitions have not been necessary for C functions, with the default being that a function returns an "int" and takes any number of parameters. ANSI C introduced the notion of a function "prototype" to specify the function interface, and some implementations can be directed to require the presence of a prototype for all functions.
All arrays are indexable by any integer or enumeration type; all arrays have a low bound of zero, and a high bound of one less than the specified size. No bounds information is carried with array parameters, and no bounds checking is defined by the language standard, although some tools exist that will check for out-of-bounds references. Arrays are treated by the language as essentially constant- valued pointers, and array indexing is defined in terms of an indirection applied to the addition of a pointer and an integer index.
Strings in C are represented by a pointer to their first character, with a null character used by convention to signify the end of the string. There is no language-defined checking for running off the end of a string.
Record-like "structs" are supported, but there is no language-defined data abstraction mechanism. Opaque, incomplete pointer types can be used to provide some degree of data abstraction. A "union" construct allows the creation of an undiscriminated union of types. There is no language- defined check for accessing the "wrong" member of a union.
The "cast" construct may be used to explicitly convert between numeric types (although implicit conversion is performed as part of a function call, and implicit widening is performed during arithmetic). The cast construct may also be used to convert between pointer types, or between an integer and a pointer type. There is no language-defined check associated with a cast.
No default initialization is defined by the standard for local variables; pointers, in particular, are not default initialized. No null-checking is defined for pointer indirection.
There is no language-defined construct for raising and handling exceptions, although there are standard functions for sending and handling "signals," which can be used to emulate exceptions in certain circumstances.
C provides some control over representation by the use of bit field indicators on "struct" components. However, it does not define the ordering of bit fields within a word. Some implementations provide "pack" pragmas or other means of providing more representation control.
There is no language-defined "module" construct other than a source file; objects and functions declared "static" are local to the source file. Objects and functions not declared "static," when defined at the top level, are externally visible from any other file that includes an "extern" declaration for the entity. By convention, the "extern" declarations for a source file, and associated type definitions, are usually grouped into a header file (".h" file), which can be textually included ("#include") in any source file requiring access to the type, object, or function.
C includes a standard preprocessor that supports textual include, conditional compilation, and parameterized textual macros.
|84||Ada and Beyond: Software Policies for the Department of Defense|
The ANSI C standard includes a full set of library functions to support string manipulation (where a string is a null-terminated array of characters), random number generation, and input/output, among others.
The C++ language was first released in 1983 as an enhancement to C, with the major enhancement being the addition of a "class" construct inspired by the same-named feature of the language Simula-67. The language was initially defined by the implementation available from AT&T ("cfront") that translated C++ to C. Cfront, and hence C++, went through several major updates that added features such as multiple inheritance, generic templates, and exception handling. In the early 1990s, ANSI and ISO committees were formed to produce a standard for the language. A few additional features, such as run-time type identification and "namespaces," have been added during the standardization process. Approval of the ISO C++ standard is expected within the next year.
C++ includes all the features of C, although some features are revised to be more strongly typed. For example, enumeration types in C++ are implicitly convertible to integer types, but not implicitly convertible back. Also, function prototypes are required for all C++ functions. C++ adds to C support for data abstraction, type inheritance, and dynamic binding (virtual functions). Two kinds of multiple inheritance are supported: the default inheritance replicates the fields if the same base class is inherited through multiple paths, and the virtual inheritance shares fields if the same base class is inherited through multiple paths.
C++ also supports a generic template facility. No checking is defined for templates prior to instantiation; there is no template "contract" model. Instantiation is implicit by referring to an instance via "template_name<parameters>." Template functions are also supported; instantiation of a template function is automatic at a call, with the template parameters determined implicitly by the types of the call parameters.
C++ supports "throw"ing and "catch"ing exceptions. Exceptions can be represented by objects of any type; the "catch" is based on a type matching. The standard C++ library defines certain exception types, instances of which are thrown when an allocator fails to allocate storage, or when other errors occur.
The array indexing and cast constructs inherited from C remain unchecked in C++. There are standard templates for defining checked arrays and checked casts. Local pointers in C++ are not default initialized, and there is no language-defined check for dereferencing a null pointer. " Smart pointer" abstractions can be developed to check for null pointers, or to implement persistence or similar capabilities.
As in C, all numeric types are implicitly convertible on assignment and parameter passing, and implicitly "widened" in calculations.
C++ supports information hiding through the notion of protected and private data and function members. Private members are visible only inside a class (and to its "friends"). Protected members are visible inside all descendants of a class. C++ supports a multilevel namespace though a "namespace" construct, which provides no information hiding (there is no "private" part of a namespace) and is simply a hierarchical naming mechanism.
Java was developed over the past 5 years at Sun Microsystems. It was originally called "Oak" and was intended for use in small appliances, set-top boxes, and other embedded applications. In April
1995, a World Wide Web browser written in Java, called HotJava, was announced by Sun. Hotjava had the ability to download small programs written in Java over the Web and execute them in the context of a Hypertext Markup Language (HTML) page being displayed by the Web browser. Since then, Sun's Java technology has been licensed by essentially all other Web browser developers, including Netscape and Microsoft, and has achieved widespread attention for its potential to provide many of the capabilities of client/server systems without many of the attendant complexities.
Java is syntactically based on C++ but semantically is closer to Modula-3 or Ada 95. It provides modularity through a combination of a "package" concept, which is a namespace with some information hiding associated with it, and the "class" construct, which is modeled closely on the C++ (and Simula 67) class construct. To support information hiding, methods (called "member functions" in C++) and data components may be marked as public, protected, or private, much as in C++, but with the added notion that, by default, methods and data are visible only to classes within the same package. Unlike C++, there is no textual "include" in Java; instead, individual classes, or a whole package of classes, are explicitly imported using an "import" statement at the top of the source file defining a class.
All code and objects in Java must be inside some class. The methods of a class are by default "virtual" in Java; calls to such methods are "dynamically" bound. Methods may be explicitly specified as "static"; calls to such methods are "statically" bound. The data components of a class are by default "per-instance," as in C++. Data components may be marked "static," which means that they are "statically" allocated and shared across the class, rather than one per instance.
Java fully supports single inheritance between classes. By default a class inherits from the single "root" type called "java.lang.Object." Alternatively, it may explicitly specify one parent class from which it inherits non-static methods and data components. Java provides a limited kind of multiple inheritance through the concept of an "interface" type: a list of methods that any "implementor" of the interface must provide. A class may specify any number of interface types that it claims to "implement." The compiler verifies that the methods required by each identified interface are present in the class. There is no separate specification for a class (other than that provided by interface types it implements). There is no separate "prototype" for a method of a class. A tool may be used to extract the documentation and specification for class.
Java has no direct support for enumeration types. Named integer constants may be used, but the compiler provides implicit widening between integer types on assignment and parameter passing and allows any integer type to index any array. Arrays in Java are indexed from zero, as in C and C++, but unlike C or C++, their semantics are not defined in terms of pointer arithmetic. In fact, Java does not support pointer arithmetic. Arrays are first class types, and carry a length at run time against which all indexing is checked.
Pointers ("references") in Java are default initialized to null, and all pointer dereferences are checked for null. Conversions between references are checked at run time for meaningfulness.
Java has exceptions, much as in C++, except that it enforces compatibility and completeness of "throw" signatures at compile time (C++ enforces "throw" signatures at run time). Failures of run-time checks, such as an array-bounds check, or a null-pointer check, result in a "throw" of a predefined. exception. Run-time error exceptions do not need to be mentioned in a "throw" signature; other exceptions, including user-defined exceptions, do need to be mentioned in the "throw" signature of a method if it is going to throw or propagate the exception.
Java has no generic templates; the root type java.lang.Object can be used in some contexts to define (heterogeneous) "generic" data structures. Proposals exist to add a parametric polymorphism facility to Java, which could provide some of the added compile-time type checking associated with "homogeneous" data structures provided by the generic template features of Ada and C++.
Java has largely the same control flow constructs as C++. As in C and C++, switch statements rely on a programmer-inserted "break" to terminate a case. Java defines a special type "boolean" and requires a value of boolean type in the expression of an "if;" "while," or "for" test. There is no implicit
|86||Ada and Beyond: Software Policies for the Department of Defense|
conversion to "boolean"; the relational operators return boolean, as do the logical operators. The operator "=" is for assignment; "==" is for equality. A "break" or "continue" statement may have an identifier to identify the particular construct being exited or continued, providing some additional flexibility and maintainability relative to C and C++.
All class and array instances are allocated dynamically on a garbage collected heap. That is, there are no " stack-resident" arrays or class instances. All implementations of Java provide a garbage collector. There are no class instances "nested" inside other class instances, only references to dynamically allocated class instances. The same goes for arrays.
There is no user control over representation of data objects. There is no user control over storage management, other than a system method to force a garbage collection.
Java has a large standard library of classes and includes support for multithreading through a combination of a standard thread class and the notion of "synchronized" methods.
In comparing the features of Ada, C, C++, and Java, various principles underlying each language can be identified.
With C, the underlying goal is to provide reasonable portability (certainly when compared with assembly language) while giving the programmer full control of the machine. There is little attempt to provide strong consistency checking at compile time, and no notion whatsoever of run-time checking built into the language (other than via use of the standard "assert" macro).
C++ provides more tools for defining abstractions, and increases the strength of the type checking on enumeration types. However, the default run-time behavior in C++ is still inherited from C, which means no run-time initialization or checking of pointers, no checking of array indexing, and no notion of range checking. The default conversion syntax, the simple "cast" inherited from C, does no checking. The basic primitives of C++ remain unsafe, although there are additional mechanisms available for creating safe abstractions.
Java takes the route of strongly enforcing run-time consistency, with all the necessary checks to ensure that a program does not corrupt data outside its prescribed space, including pointer initialization and null checking, array-bounds checking, and conversion checks. However, at compile time, Java has essentially gone one step backward from C++ by dropping support for enumeration types, thereby eliminating an important source of compile-time consistency checks. Java very successfully creates a language that prevents code from corrupting data outside its purview, but it fails to provide tools for supporting thorough compile-time enforcement of interface consistency.
A second area of concern with regard to use of Java for critical systems development is that it is inextricably tied to a dynamic storage allocation model. Garbage collection is certainly less error-prone than is manual storage reclamation, but any use of dynamic storage allocation opens up the possibility of eventual storage exhaustion, as does dynamic stack extension. For an embedded or critical system, it is standard practice to require that all storage be allocated statically (at link time), including the stacks for all threads of control; recursion is also disallowed.
In comparison to the above languages, Ada 83 and Ada 95 attempt to provide more features to make compile-time consistency checking useful for finding mistakes, backed up by run-time consistency checks for cases in which only a dynamic check is meaningful. As mentioned above, Ada is one of the few languages that allows the programmer to create strong distinctions between structurally equivalent numeric, array, and pointer types. These distinctions allow an Ada interface to capture more of the semantics, and allow the Ada compiler to catch more mistakes in the use of an interface. The last decade has seen an explosion in the number of application programming interfaces (APIs) used to build systems. Inappropriate uses of an API are among the most common mistakes in such systems. By creating
stronger distinctions between numeric, enumeration, array, and pointer types, an Ada version of an API can reduce the likelihood of inappropriate use, and identify more such errors at compile time.
At run time, Ada has pointer default initialization, pointer null checking, array bounds checking, with user control over both the low and high bound, and conversion checking. In addition, Ada provides range checking, variant record checking, and, in Ada 95, both compile-time and run-time checks designed to eliminate "dangling" references associated with pointers to deallocated stack variables. This set of "dangling reference" checks ("accessibility checks") allows an embedded or critical program to avoid completely the use of dynamic storage allocation, while still providing the convenience of using pointers.
Both Ada and Java have support for multithreaded applications as a standard, portable part of the language, whereas C and C++ support multithreading generally through operating-system-dependent libraries. The Ada multithreading support includes various real-time-oriented features, such as timed entry calls and selective accepts with delay alternatives, whereas Java has only a basic timed "sleep" operation. To the basic Ada 83 multithreading support, Ada 95 adds protected objects, which are designed to support real-time systems by reducing overhead, minimizing "priority inversion," and generally improving predictability of thread synchronization. Java's synchronized methods, with wait/notify operations, provide similar capability, although with less encapsulation of the fields requiring synchronized access, a more race-prone "notification"-oriented synchronization model, and no particular concern for priority inversion.
Although Ada is a general-purpose 3GL, it was designed with extra attention to the concerns of real-time, embedded, and critical systems developers, namely very thorough consistency checking, mechanisms to support a very "static" storage allocation model, and multithreading support with time- and priority-cognizant constructs. As such, at a technical level, it is a better fit to the needs of DOD critical and embedded systems development than are the other languages in widespread commercial use. These reliability-oriented features of the Ada language make development and maintenance more cost- effective, when cost to achieve the required level of quality and correct functionality is included. Of course, there are other non-technical issues involved in language choice (as discussed in Chapter 1), and other non-language issues involved in managing successful software development (discussed in Chapter 2).
Application Programming Interface (API). A set of procedure and function specifications providing access to the capabilities of a reusable software component, such as a "windowing" or network communication operating subsystem.
Architecture. The structure of a system's components and connectors, their interrelationships, and the principles and guidelines governing their design and evolution over time.
Automated Information System (AIS). A combination of computer hardware and computer software, data, and/or telecommunications that performs functions such as collecting, processing, transmitting, and displaying information. The function of such systems is primarily administrative. Excluded are computer resources, both hardware and software, that are physically part of; dedicated to, or essential in real time to the mission performance of weapon systems; used for weapon system specialized training, simulation, diagnostic testing and maintenance, or calibration; or used for research and development of weapon systems.
Commercial Item. An item regularly used in the course of normal business operations for other than government purposes that has been or will be sold or licensed to the general public, and that requires no unique government-directed modifications or maintenance over its life cycle to meet the needs of the procuring agency.
Commercial Off-the-Shelf (COTS) Software. COTS software products are commercial items that have been sold, leased, or licensed in a quantity of at least 10 copies in the commercial marketplace, at an advertised price. COTS software products include a description or definition of the functions the software performs, documented to good commercial standards, and a definition of the resources needed to run the software.
Domain. A distinct functional area that can be supported by a class of Systems and assets with similar requirements and capabilities.
Fourth-Generation Programming Language (4GL). A 4GL differs from a third-generation programming language (3GL) in that it removes the need for a programmer to explicitly make many of the design decisions about data structures and algorithms. 4GLs allow programmers to express instructions in terminology and at a level of abstraction that are natural for communication between humans who are familiar with the application domain. The programmer interaction may even be in a graphical, or menu-based, form. 4GLs typically incorporate domain-specific knowledge and notation, and so are not "general purpose" in the sense that 3GLs are, although they may include a 3GL component that permits general-purpose programming. 4GLs are associated with "frameworks," "templates," "automatic program generators," "middleware," and "graphical user interface builders." Some examples of 4GLs are Visual Basic, PowerBuilder, Delphi, and SQL.
Function Point. A measure of software functionality that is independent of differences in lines of code required to implement a given function in different programming languages.
Glue Code. The relatively small parts of computer programs, or operating system "shell" scripts, that are written to integrate non-developmental items into a larger system, without modification to the components themselves.
Government-directed Software Maintenance. Maintenance required for software changed in response to government specification or direction. Government-directed maintenance may be done by the government or by a commercial organization paid by the government. In contrast, with vendor-directed maintenance, a vendor chooses which changes are made to the software, and when they will be made.
Non-Developmental Item (NDI). Any software asset that is available in the commercial marketplace; or any software asset that is available to the public for free use; or any previously developed software asset that is in use by a department or agency of the United States, a state or local government, or a foreign government with which the United States has a mutual defense cooperation agreement.
Product Line. A set of similar products or a family of systems that share common architectures and satisfy the mission requirements of one or more domains.
Re-engineering. The process of examining and altering an existing system to reconstitute it in a new form. Re-engineering may include reverse engineering, restructuring, re-documenting, forward engineering, re-targeting, or translation.
Reuse. The process of developing or updating a software-intensive system using existing software assets.
Software Asset. Any software-related product of the software life-cycle.
Software Engineering Environment. The set of tools (including supporting hardware, software, and "firmware") used in the production and maintenance of software throughout its life-cycle. Typical elements include computer equipment, compilers, operating systems, "debuggers," simulators, emulators, computer-aided software engineering tools, and database management systems.
|90||Ada and Beyond: Software Policies for the Department of Defense|
Software Maintenance. Maintenance of software includes, but is not limited to, activities generally referred to as enhancement, evolution, post-deployment software support, or error correction.
Software Metrics. Quantitative values used to make an assessment of software condition, products, or processes. Representative metrics are effort, schedule, cost, quality, size, and rework.
Standards-based Technical Architecture. An architecture that defines the standards, services, topology, data definitions, and common framework that enable systems developed to the architecture to interoperate.
Third-Generation Programming Language (3GL). Third-generation programming languages generally differ from second-generation languages in being machine-independent, providing built-in control structures, and supporting user definition of abstractions, including subprograms and data types. They differ from fourth-generation languages in continuing to require the programmer to deal explicitly with the design of data structures and algorithms. Some examples of 3GLs are Ada, C, C++, Cobol, Fortran, Java, Jovial, Pascal, and SmallTalk.
Warfighting Software. There are two primary criteria for determining whether a subsystem belongs in the "warfighting" category:
1. Relatively little commercial software and expertise is available for implementing the desired functions. For example, even though intelligence analysis is involved in warfighting, many of its functions (database update, query and visualization, report generation) can be readily satisfied via non- warfighting commercial software.
2. The application requires software quality attribute levels higher than those supportable by commercial software. For many warfighting functions, these involve real-time performance, reliability, and survivability, particularly in high-stress, crisis-mode situations in which DOD information processing functions may be under attack.
The application domains for warfighting software include, but are not necessarily limited to, the following areas:
Weapon control, which includes software involved in weapon sensor processing; guidance, navigation, and control; combat-oriented weapon-delivery platform control; and software for special weapon delivery platform operator devices such as heads-up displays. Weapon control does not include administrative functions and "hotel services" for large weapon delivery platforms such as aircraft carriers, or support subsystems performing mainstream data management, networking, and graphical user interface functions.
Electronic warfare, which includes software involved in rapid-response electronic detection, identification, discrimination, tracking, platform-based communication, and associated countermeasure/counter-countermeasure applications, but does not include support subsystems performing mainstream data management, networking, and graphical user interface functions.
Wideband real-time surveillance, which includes software involved in hard or soft real-time image, infrared, radar, or other sensor processing, but does not include off-line query and analysis of surveillance archives or support subsystems performing mainstream data management, networking, and graphical user interface functions.
Battle management and battlefield communication, which includes hard or soft real-time weapons allocation, targeting, control, coordination, damage assessment, and associated battlefield communications requiring such special capabilities as spread spectrum, anti-jamming, and frequency-
Detailed Comparisons of Ada and Other Third-Generation
This appendix presents details of studies, summarized in Chapter 2 in the sections titled "Analyses of Language Features" and "Comparisons of Empirical Data," that have analyzed the technical features of programming languages and have used empirical project data to compare languages' relative strength with respect to desired characteristics. Given the unscientific nature of most of the data, no strong conclusions are warranted. But in a general sense, most experience with Ada supports the conclusion that it benefits DOD warfighting applications; few data were found to refute such a conclusion, although the absence of such data may reflect a lack of any organized effort to promote the use of languages other than Ada in warfighting systems.
EVALUATIONS OF LANGUAGE FEATURES
A 1985 Federal Aviation Administration (FAA) study compared Ada with four other languages by conducting expert evaluations based on 48 technical language features arranged in six categories, and combining the evaluation results with the results of performance benchmark test results (IBM, 1985). A follow-on study was conducted by the Software Engineering Institute (SEI) in 1991 using the same expert evaluation methodology as the original study to compare Ada 83 with C++, but without the benchmark tests (Weiderman, 1991). The studies, the results of which are presented in Table D.1, compared the languages against the maximum possible scores for each of the six categories, which can be summarized as follows:
Capability facets of the implementation language relevant to programming or software engineering;
Efficiency factors relevant to optimization of generated code and run-time utilization of resources;
|Table D.1 Language Functionality Attributes|
|FAA/IBM Study||SEI Study|
Availability/Reliability factors influencing day-to-day safety of operational systems;
Maintainability/Extensibility factors influencing long-term viability of operational systems;
Life-cycle cost elements of cost associated with or affected by the implementation language; and
Risk areas of uncertainty or concern associated with or affected by the implementation language.
Ada scored the highest overall in both studies. It scored the highest in each individual category, except for efficiency, where it was ranked last, and risk, where it was ranked first in the SEI study and third in the FAA study.
PROJECT EVALUATION DATA
In comparisons of Ada with other programming languages in actual development projects, empirical data on characteristics such as expressibility, maintainability, defect rates, reusability, and cost factors are of particular interest. Since Ada has been used in relatively large programs, a larger proportion of data has been collected for Ada than for contemporaneous commercial programming languages like C and C++
Much of the data are subjective in nature, and care must be taken in drawing conclusions from such studies. For instance, the data in Table D.2 are confounded by differences in the expressive power of a source line of code in different programming languages. One way of normalizing uses tables of source lines of code per function point (Jones, 1995). However, as shown in Table D.2, these ratios have wide variability. Lubashevsky (1996) reports variations in source lines of code per function point exceeding factors of 2 for C and 6 for C++. Finally, there are differences in expressiveness for the same language across different application domains.
|94||Ada and Beyond: Software Policies for the Department of Defense|
|Table D.2 Source Lines of Code per Function Point|
SOURCE: Data from Jones (1995).
The Verdix Ada Development System (VADS) data (Zeigler, 1995) covers a period of approximately 10 years of development and enhancement of VADS compilers, debuggers, builder tools, and run-time support systems using both C and Ada. Table D.3 summarizes the comparative C and Ada experience data over this period.
Zeigler analyzed potential confounding effects of relative C and Ada software complexity, personnel capability, and learning curve effects and found that these factors did not cause any significant bias. The study thus provides a strong case that Ada was significantly better than C, in terms of both life-cycle cost and freedom from defects, for this large (over 1 million lines of both Ada and C) project in the compiler and tools area. However, the study can only be suggestive rather than definitive about the applicability of this result to other domains and other teams (the Verdix teams were both composed of high-capability, low-turnover personnel).
Since 1976, NASA's Software Engineering Laboratory (SEL) has been carefully collecting software data on non-embedded, non-real-time satellite flight dynamics software. Figure D. 1 (McGarry et al., 1994) summarizes SEL's history of development error rates over this period. The data show a significant general decrease in error rates over the period, due to such techniques as code reading, systematic testing, and Cleanroom techniques. The data from 1988 to 1994 also show significantly lower error rates for Ada than for Fortran, measured per 1,000 lines of delivered code, or KDLOC (an average of 2.1 defects/KDLOC for Ada vs. 4.8 defects/KDLOC for Fortran). SEL's analyses for Ada initially concluded that owing to reuse, Ada projects experienced significant cost and schedule reductions compared to Fortran projects. Subsequently, however, the Ada object-oriented reuse approach was applied to Fortran projects, resulting in comparable gains.
This section summarizes proprietary data from Reifer (1996) and Jones (1994) that compare Ada to other programming languages with respect to cost, delivered defects, reliability, and productivity. Because the source data and detailed analysis are unavailable, these results are difficult to assess.
Data on cost, reliability, and maintainability have been compiled in a proprietary database of outcomes of 190 software projects 3 years old or less (Reifer, 1996). These projects were written in Ada 83, Ada 95, C, C++, and other third-generation programming languages (3GLs, such as Cobol or Fortran) and were compared to a norm for each domain, drawn from a database of over 1,500 projects 7 years old or less.
|Table D.3 Verdix Ada Development System Development Data|
|Characteristic||C||Ada||Script Files||Other Files||Totals|
aSLOC: Source lines of code.
bKSLOC: 1,000 SLOC.
SOURCE: Zeigler (1995).
Reifer's project cost data, shown in Table D.4, indicate that, in general, Ada, C, and C++ programs were less expensive per delivered source line of code (SLOC) than other 3GL programs or the domain norm for military applications, although C and C++ programs were less expensive than Ada programs in all military domains except airborne and spaceborne weapons systems. In commercial domains, the development cost of C and C++ code was again less than or equivalent to the cost of Ada, and Ada was roughly equivalent in cost to other 3GLs and the domain norms. However, the wide variations in expressive power of a line of code in Ada, C, and C++ (see Table D.2) tend to overshadow the cost/SLOC differences shown in Table D.4.
Another study used telecommunications systems to evaluate object-oriented programming languages (Jones, 1994). The study used as a baseline a private branch exchange switch software application of 1,500 function points in size, compared across several telecommunications companies. Based on these data, Table D.5 shows the cost of developing the project in different languages, in dollars per function point. The results indicate that, in this domain, coding in C++ was less expensive than coding in Ada, while using C was more expensive.
Reifer's (1996) data, shown in Table D.6, indicate that in the 190 software projects represented, Ada code had fewer delivered defects than C and C++ code, which, in turn, had fewer defects than other 3GLs. In command and control and telecommunications applications, the difference between Ada and C/C++ was smaller than the difference between C/C++ and other 3GLs and the norm. In commercial products, information systems, and weapons systems, Ada code clearly had fewer defects than code in C, C++, and other 3GLs.
Based on Jones's (1994) data, Table D.7 indicates that, for telecommunications applications, the reliability in delivered defects per function point was roughly equivalent for C++ and Ada, and higher for C code.
|96||Ada and Beyond: Software Policies for the Department of Defense|
|Table D.4 Cost Data by Language (dollars per delivered source line of code)|
|Application Domain||Ada 83||Ada 95||C||C++||3GL||Norm|
|Command & Control|
|Airborne & Spaceborne||150||n/a||175||n/a||250||200|
SOURCE: Reprinted from Reifer (1996).
|Table D.5 Telecommunications Project Costs by Language (dollars per function point)|
|Assembly||C||CHILL||Pascal||Ada 83||Ada 9Xa||C++||Smalltalk|
aAda 9X figure based on simulation.
bAt a monthly salary rate of $10,000.
SOURCE: Data from Jones (1994).
The fairly consistent factor-of-10,000 relationship between the data on cost per function point shown in Table D.5 and the data on defects per function point shown in Table D.7 suggests that Jones's cost and defect data are highly correlated to some third factor. This third factor appears to be the mean SLOC/function point ratio from Jones (1995), shown in Table D.2. Comparing these ratios across C, Ada, and C++ indicates that they are approximately, although not exactly, equal, as shown in Table D.8.
Data from Reifer (1996) in Table D.9 indicate that the incidence of failure for Ada programs was lower than that with C, C++, and other 3GLs. The outcome of this reliability comparison is similar to the defect comparison; Ada was superior to C and C++, which were better than other 3GLs.
|98||Ada and Beyond: Software Policies for the Department of Defense|
|Table D.6 Delivered Defect Data by Language (post-delivery errors per KSLOCa|
|Application Domain||Ada 83||Ada 95||C||C++||3GL||Norm|
|Command & Control|
|Airborne & Spaceborne||0.3||n/a||0.8||0.6||1.0||1.0|
aKSLOC: 1,000 source lines of code.
SOURCE: Reprinted from Reifer (1996).
|Table D.7 Defects for Telecommunications Applications (delivered defects per function point)|
|Assembly||C||CHILL||Pascal||Ada 83||Ada 9Xa||C++||Smalltalk|
aAda 9X figure based on simulation.
SOURCE: Data from Jones (1994).
|Table D.8 Correlation in Function Point (FP) Measures|
|SLOCa/FP (Jones, 1995)||Dollars/FP (Jones, 1994)||Defects/FP (Jones, 1994)|
|Table D.9 Reliability Data by Language (weeks until next major repair incidence)|
|Application Domain||Ada 83||Ada 95||C||C++||3GL||Norm|
|Command & Control|
|Airborne & Spaceborne||8.0||n/a||3.0||n/a||2.5||2.5|
SOURCE: Reprinted from Reifer (1996).
As described in Chapter 2 in the section titled "Software Engineering Process and Architecture," one of the key relationships in software development productivity is the relationship of development effort to program size-that is, the value of the "process exponent." A MITRE study (Giallombardo, 1992) found substantial improvements in productivity for large embedded military software developments provided by Ada compared with other 3GLs. The study found that effort, as measured by staff-months required per 1,000 equivalent delivered source instructions (KEDSI; which counts terminal semicolons rather than source lines of code), increased linearly for the large Ada projects (process exponent close to 1). For large non-Ada projects, effort increased more than linearly; the increase in effort was also greater than that predicted by the COCOMO model, which has a process exponent of 1.2 for embedded or very large systems (Boehm and Royce, 1988). The differences were clearest for system sizes greater than 100 KEDSI (which the MITRE study used as a definition of "large").
In a study of telecommunications applications, Jones (1994) compared the productivity of several 3GLs, using function points per staff-month as the metric. The results, presented in Table D.10, indicate that, in this domain, C++ developments had a higher productivity rate than those using Ada, while developments using C were less productive than those using Ada.
|Table D. 10 Productivity for Telecommunications Projects by Language (function points per staff month)|
|Assembly||C||CHILL||Pascal||Ada 83||Ada 9Xa||C++||Smalltalk|
aAda 9X figure based on simulation.
SOURCE: Data from Jones (1994).
|100||Ada and Beyond: Software Policies for the Department of Defense|
In summary, based on the results of currently available empirical data and feature analysis comparisons, a conclusion that Ada is superior, with respect to availability/reliability and a lower incidence of defects, appears warranted. The evidence is not strong enough to assert Ada's superiority in the cost area. However, there is some positive evidence in the cost area, and when it is combined with the anecdotal conclusions favoring Ada (described in "Anecdotal Experience from Projects" in Chapter 2) and the lack of solid evidence indicating less expensive custom software development in other languages, a case can be made that using Ada provides cost savings in building custom software, particularly for real-time, high-assurance warfighting applications.
Briefings and Position Papers Received by the Committee
Washington, D.C., April 10-12, 1996
|102||Ada and Beyond: Software Policies for the Department of Defense|
Washington, D.C., May 21-23, 1996