Object-Oriented Programming (Java)

Chapter 14
Security, Performance, Observability, and Technical Governance

Bachelors Program in IT
Object-Oriented Programming (Java)   •   Bachelor

Security, Performance, Observability, and Technical Governance

Introduction

A Java program is not complete when it merely produces the correct output. A professional system must also protect information, resist misuse, perform acceptably under realistic load, reveal its operational condition, and remain governable throughout its life cycle. These concerns are interconnected. Weak input validation can create security defects and excessive resource consumption; poor observability can delay detection of both attacks and performance failures; uncontrolled dependencies can introduce vulnerabilities and make maintenance expensive.

This chapter develops an engineering approach to four related responsibilities:

  • secure coding, validation, authentication, and authorization;
  • performance analysis, profiling, benchmarking, and capacity planning;
  • observability through logs, metrics, traces, and alerts;
  • technical governance, including dependency management and build-versus-buy decisions.

The central principle is evidence-based engineering. Developers should not rely on intuition alone when deciding whether code is secure, fast enough, maintainable, or economically justified. They should define requirements, collect appropriate evidence, evaluate risk, and document decisions.

Learning Objectives

By the end of this chapter, students should be able to:

  1. Apply secure coding principles and validate untrusted input in Java applications.
  2. Distinguish authentication from authorization and implement each appropriately.
  3. Explain common sources of performance problems and use profiling and benchmarking correctly.
  4. Select useful logs, metrics, traces, and service-level indicators.
  5. Estimate throughput, latency, utilization, and capacity using appropriate models.
  6. Govern third-party dependencies and evaluate supply-chain risk.
  7. Make reasoned build-versus-buy decisions using cost, risk, capability, and maintainability evidence.

1. Security as a Software Quality Attribute

Security is the protection of confidentiality, integrity, and availability, often abbreviated as the CIA triad.

  • Confidentiality means that information is disclosed only to authorized parties.
  • Integrity means that data and operations are not improperly altered.
  • Availability means that authorized users can access services when needed.

Security is not a single feature. It is a property of architecture, code, configuration, operations, and organizational process. A secure Java class can still be used insecurely if its API permits unauthorized access or if deployment exposes sensitive configuration.

1.1 Threat modeling

Threat modeling is a structured method for asking what can go wrong and how risk can be reduced. A practical process is:

  1. Identify assets, such as credentials, personal data, payment records, and service availability.
  2. Identify trust boundaries, where data or control moves between users, services, networks, or privilege levels.
  3. Identify threats, including impersonation, tampering, information disclosure, denial of service, and repudiation.
  4. Estimate likelihood and impact.
  5. Select controls and record residual risk.

Risk is often represented conceptually as:

Risk = Likelihood × Impact

Likelihood and impact are commonly ordinal ratings rather than physical measurements. Therefore, the expression is a prioritization aid, not a precise probability calculation. It is useful only when the rating scales are defined consistently.

1.2 Secure coding principles

Important principles include:

  • Least privilege: grant only the permissions required for a task.
  • Fail securely: when a security check fails or an unexpected error occurs, do not expose protected data or grant access.
  • Defense in depth: use several independent controls rather than relying on one.
  • Secure defaults: an object or service should be safe when no special configuration is supplied.
  • Complete mediation: check authorization whenever a protected operation is performed, not only when a user first logs in.
  • Separation of duties: avoid giving one component excessive control over an entire business process.
  • Economy of mechanism: simpler security mechanisms are easier to review and test.
  • Do not trust client controls: hidden fields, disabled buttons, and client-side validation do not enforce server-side security.

In Java, encapsulation supports security by restricting direct access to state. However, private fields alone do not make a class secure. Public methods must also validate arguments, enforce invariants, avoid leaking sensitive data, and maintain correct authorization boundaries.

2. Input Validation and Safe Data Handling

All external data should be considered untrusted. External data includes HTTP parameters, JSON payloads, files, environment variables, message queues, database results from untrusted sources, and user-controlled headers.

2.1 Validation strategies

Syntactic validation checks form: type, length, character set, and format. For example, a product quantity may need to be an integer between 1 and 1,000.

Semantic validation checks meaning in context. A valid date may still be invalid if it precedes an order date. A syntactically valid account identifier may still be unauthorized for the current user.

Prefer allowlists to denylists. An allowlist states what is permitted, such as a defined enumeration of sort fields. A denylist attempts to identify every dangerous possibility and is usually incomplete.

Validation should occur at trust boundaries and again where context changes. For example, a web controller may validate JSON structure, while a domain service verifies business rules. Validation is not a substitute for output encoding or parameterized database queries.

Example:

public record TransferRequest(String destination, long cents) {
    public TransferRequest {
        if (destination == null || !destination.matches("[A-Z0-9]{8,20}")) {
            throw new IllegalArgumentException("Invalid destination");
        }
        if (cents <= 0 || cents > 1_000_000_00L) {
            throw new IllegalArgumentException("Invalid amount");
        }
    }
}

The example rejects invalid structure and range. A real system must additionally verify that the destination exists, that the user may transfer funds, and that the transaction satisfies business and regulatory controls.

2.2 Injection prevention

Injection occurs when data is interpreted as executable syntax. SQL injection is prevented by parameterized statements, not by manually escaping strings.

String sql = "SELECT id, name FROM users WHERE email = ?";
try (PreparedStatement ps = connection.prepareStatement(sql)) {
    ps.setString(1, email);
    try (ResultSet rs = ps.executeQuery()) {
        // Process results
    }
}

The same principle applies to command execution, HTML, XML, LDAP, and expression languages. Use APIs that separate data from instructions, and encode output for its destination. Input validation and output encoding address different risks.

2.3 Sensitive information

Passwords should never be stored as plaintext or with reversible encryption. Password verification should use a modern adaptive password-hashing algorithm such as Argon2id, bcrypt, or scrypt, with a unique salt per password. Application logs should not contain passwords, session tokens, authorization headers, full payment-card numbers, or unnecessary personal data.

Java exception messages and stack traces may reveal file paths, SQL statements, class names, or configuration details. Detailed diagnostic information belongs in controlled logs, while external responses should be safe and appropriately general.

3. Authentication and Authorization

Authentication answers, “Who are you?” Authorization answers, “What are you allowed to do?” Authentication without authorization is insufficient: a correctly identified user may still be prohibited from viewing another customer’s records.

3.1 Authentication

Authentication factors commonly include:

  • something the user knows, such as a password;
  • something the user has, such as a hardware security key;
  • something the user is, such as a biometric characteristic.

Multi-factor authentication combines independent factor categories. Two passwords are not two independent factors.

Session identifiers must be unpredictable, transmitted only over protected channels, and invalidated on logout or expiration. Session cookies should normally use Secure, HttpOnly, and an appropriate SameSite attribute. Token-based systems require careful validation of issuer, audience, signature, algorithm, expiry, and intended use. A token’s presence is not proof that it is valid.

3.2 Authorization models

Common models include:

  • Role-based access control (RBAC): permissions are assigned to roles such as clerk or administrator.
  • Attribute-based access control (ABAC): decisions use attributes of the subject, resource, action, and environment.
  • Discretionary access control: resource owners may delegate access.
  • Mandatory access control: policy authorities define classifications and permitted flows.

RBAC is understandable and effective for stable organizational responsibilities, but can produce role explosion when rules depend on many contextual attributes. ABAC expresses richer policies but requires disciplined policy management and testing.

Authorization should be enforced close to the protected resource. A controller check such as if (user.isAdmin()) is not enough if a service method can be called through another route. Object-level authorization is especially important: the user must be allowed to access the specific record identified by an ID.

4. Dependency and Supply-Chain Governance

Modern Java systems depend on libraries, plugins, container images, build tools, and transitive dependencies. A vulnerability may enter through a component the development team did not explicitly select.

Effective governance includes:

  1. Maintain a declared dependency manifest and lock or otherwise control versions.
  2. Review licenses and compatibility with organizational policy.
  3. Scan dependencies for known vulnerabilities using a maintained vulnerability database.
  4. Generate a software bill of materials (SBOM) describing components and versions.
  5. Verify artifact provenance and, where available, signatures or checksums.
  6. Remove unused dependencies and avoid unnecessary transitive complexity.
  7. Patch according to risk, exploitability, exposure, and business criticality.
  8. Test upgrades in continuous integration before production release.

A vulnerability score is not a complete risk decision. A high-severity issue in an unreachable development-only component may require less urgent action than a moderate issue in an internet-facing authentication service. Governance should combine technical facts with deployment context.

Dependency pinning improves reproducibility, but it can also prevent security updates if performed without a maintenance process. Automated update tools are valuable when combined with tests, review, and controlled release.

5. Understanding Performance

Performance is multidimensional. Relevant properties include response time, throughput, resource utilization, scalability, efficiency, and predictability.

  • Latency is the time required to complete one operation.
  • Throughput is the number of completed operations per unit time.
  • Utilization is the fraction of a resource’s capacity being used.
  • Scalability describes how performance changes as demand or resources change.

Averages can conceal poor user experiences. Percentiles are often more informative. The 95th percentile latency, written p95, is the value below which 95% of observed requests fall. It does not mean that every request is at most that value; the slowest 5% are higher.

5.1 A simple capacity model

For a single bottleneck with sustainable service rate μ requests per second and incoming rate λ requests per second, utilization is:

ρ = λ ÷ μ

Here λ and μ must use the same units, such as requests/second. The model assumes a stable workload and a defined bottleneck. When ρ approaches 1, queues and latency can increase sharply; real systems therefore require headroom. This is not a universal latency formula and should not be used to predict a complex distributed system without measurement.

For a system with N identical instances, each sustaining μ requests per second under a defined workload, an idealized capacity estimate is:

Capacity ≈ N × μ

This assumes near-equivalent instances, balanced traffic, no shared bottleneck, and negligible coordination overhead. These assumptions frequently fail when databases, network links, locks, or rate limits are shared.

5.2 Little’s Law

For a stable system, Little’s Law relates average number of items in a system, arrival rate, and average time in the system:

L = λ × W

L is the average number of items in the system, λ is the average arrival rate, and W is the average time an item spends in the system. Units must be consistent: requests/second multiplied by seconds/request gives requests. The law applies to a stable system over a meaningful observation interval; it does not by itself explain causes or guarantee a particular percentile latency.

If a service handles 40 requests per second and average end-to-end latency is 0.25 seconds, the average number of in-flight requests is:

L = 40 × 0.25 = 10 requests

This helps reason about concurrency, but it does not imply that every request takes 0.25 seconds.

5.3 Performance engineering process

A disciplined process is:

  1. Define a service-level objective, workload, hardware, software version, and measurement method.
  2. Establish a baseline.
  3. Form a hypothesis, such as excessive database round trips or allocation pressure.
  4. Measure using profiling or tracing.
  5. Change one significant factor at a time where practical.
  6. Repeat the test and compare confidence intervals or suitable variation measures.
  7. Record the result and monitor for regression.

Common causes of poor Java performance include inefficient algorithms, excessive object allocation, garbage-collection pressure, lock contention, blocking I/O, database queries without appropriate indexes, network round trips, oversized payloads, and unbounded caches.

6. Profiling and Benchmarking Java Applications

A profiler observes program behavior. CPU sampling can show where threads spend time; allocation profiling can identify object-creation hot spots; lock profiling can reveal contention; and memory analysis can identify retained objects and leaks.

A hot method consumes substantial execution time, but optimizing it is useful only if the change reduces an actual bottleneck without unacceptable complexity. Profiling in a representative environment is important because development machines and small test datasets can hide production behavior.

Microbenchmarks are appropriate for narrow questions, such as comparing two parsing methods. They are not reliable substitutes for end-to-end tests. Java benchmarking must account for just-in-time compilation, warm-up, dead-code elimination, constant folding, garbage collection, and environmental noise. The Java Microbenchmark Harness (JMH) is designed for this purpose.

A sound benchmark specifies:

  • operation and input distribution;
  • Java version, compiler, hardware, and configuration;
  • warm-up and measurement iterations;
  • forks or independent process runs;
  • result statistic, such as average time or percentile;
  • error or variability information.

A benchmark result without workload and environment information is weak evidence.

7. Observability: Logs, Metrics, and Traces

Monitoring reports selected conditions; observability is the broader ability to infer internal system state from externally visible outputs.

7.1 Logs

Logs provide event detail. Structured logs should include a timestamp, severity, service, environment, correlation or trace identifier, event name, and relevant non-sensitive context. Log levels should be meaningful:

  • DEBUG: detailed diagnostic information, normally disabled or restricted in production;
  • INFO: significant normal events;
  • WARN: unusual conditions that may require attention;
  • ERROR: failed operations or conditions requiring investigation.

Do not log secrets. Protect logs from unauthorized access and tampering, define retention periods, and consider privacy requirements. Excessive logging can increase cost, expose data, and degrade performance.

7.2 Metrics

Metrics are numerical time-series measurements. Useful categories include:

  • request rate;
  • error rate;
  • latency percentiles;
  • CPU, memory, disk, and network utilization;
  • queue depth;
  • database connection-pool usage;
  • cache hit ratio;
  • business outcomes such as completed orders.

Labels must have controlled cardinality. A metric label containing an unrestricted user ID or request ID can create millions of time series and cause a monitoring failure. High-cardinality identifiers belong in traces or logs, not usually metric labels.

A common error-rate expression is:

Error rate = Failed requests ÷ Total requests

Both quantities must refer to the same time interval and request population. If 120 of 10,000 requests fail, the error rate is 0.012, or 1.2%.

7.3 Distributed tracing

A trace follows a request across services. Spans represent operations such as an HTTP call, database query, or message publication. Trace context propagation allows engineers to connect a slow user request with a slow downstream dependency.

Logs, metrics, and traces answer different questions:

SignalMain questionTypical strength
LogsWhat event occurred?Detailed context
MetricsHow often or how much?Trends and alerting
TracesWhere did time or failure propagate?Request path analysis

7.4 Service-level objectives

A service-level indicator (SLI) is a measured quantity, such as successful requests divided by valid requests. A service-level objective (SLO) is a target, such as 99.9% successful requests over a month. An error budget is the permitted unreliability implied by the SLO.

For a 99.9% monthly availability objective, the permitted unavailability is 0.1% of the measurement window. If a 30-day month is approximated as 30 × 24 × 60 = 43,200 minutes, the budget is:

43,200 × 0.001 = 43.2 minutes

This is an approximation because calendar months differ and availability definitions vary. The SLO must specify exclusions, measurement points, and treatment of planned maintenance.

8. Technical Governance and Decision Quality

Technical governance establishes how engineering decisions are made, reviewed, measured, and revisited. It should enable responsible delivery rather than impose paperwork without value.

Useful governance artifacts include architecture decision records, threat models, dependency manifests, SBOMs, benchmark reports, operational runbooks, data-classification policies, and incident postmortems.

8.1 Build-versus-buy analysis

A build-versus-buy decision should evaluate:

  • functional fit and customization;
  • security and regulatory suitability;
  • integration complexity;
  • reliability and vendor resilience;
  • total cost of ownership;
  • internal skills and opportunity cost;
  • portability and exit strategy;
  • long-term maintainability.

A simplified total-cost model is:

TCO = Acquisition cost + Operating cost + Integration cost + Transition cost − Residual value

Each term should be defined over the same time horizon and currency. Operating cost may include licenses, cloud consumption, support, upgrades, training, and security assessment. Residual value may represent reusable assets or avoided transition cost. This model is an estimate, not an accounting standard; assumptions and uncertainty should be documented.

A weighted decision matrix can make trade-offs visible. For each criterion i, assign a weight wᵢ and score sᵢ, where weights sum to 1 and scores use a defined scale:

Total score = ∑(wᵢ × sᵢ)

The result is decision support, not objective truth. A severe legal or security disqualifier should not be hidden by strong scores in less important categories.

9. Illustrative Case: Secure and Observable Order Service

Background

Consider an illustrative online retailer whose Java order service accepts requests from a web application and calls inventory, payment, and shipping services. Customers report occasional slow checkouts, while a security review finds that users can request order records by changing an order ID in the URL.

Problem

The service has three immediate weaknesses:

  1. Object-level authorization is missing.
  2. Latency is measured only as an average, hiding slow requests.
  3. Dependencies are updated manually without a reliable inventory.

Analysis

A review identifies the order ID as untrusted input. The service authenticates the user but retrieves an order without verifying ownership. This is an authorization failure, not an authentication failure.

Operational data shows 80 requests per second and average latency of 0.30 seconds. Little’s Law estimates:

L = 80 × 0.30 = 24 in-flight requests

However, p95 latency is 2.4 seconds. Traces show that slow requests wait for an exhausted database connection pool and make repeated inventory calls.

Approach and solution

The team:

  • enforces ownership or staff permission in the domain service before returning an order;
  • uses parameterized queries and validates order identifiers as positive bounded values;
  • adds structured audit events for denied access without logging sensitive payment data;
  • instruments request rate, error rate, p50 and p95 latency, connection-pool usage, and downstream spans;
  • removes repeated inventory calls by using a bounded cache with explicit freshness rules;
  • reviews connection-pool sizing using load tests rather than increasing it blindly;
  • generates an SBOM and adds dependency scanning to continuous integration;
  • establishes an SLO for successful checkout requests and an incident runbook.

Outcome

Subsequent tests show lower p95 latency and fewer database wait events. Security tests confirm that one customer cannot retrieve another customer’s order. The team also discovers that a transitive logging library requires an update and can remediate it before deployment.

Learning points

The case demonstrates that security and performance are not isolated activities. Authorization belongs at the business operation boundary; observability must expose both technical and user outcomes; and governance turns one-time fixes into repeatable controls. The evidence also prevents an attractive but unsafe response—simply increasing the connection pool without understanding the database bottleneck.

10. Challenges, Ethics, and Contemporary Practice

Security and observability involve ethical responsibilities. Collecting more data may improve diagnosis but increase privacy risk. Teams should practice data minimization, define retention, restrict access, and document legitimate purposes. Automated anomaly detection should be evaluated for false positives, discriminatory effects, and inappropriate use of personal data.

AI-assisted coding can suggest validation, queries, and tests, but generated code may contain insecure assumptions, license concerns, hallucinated APIs, or data-leakage risks. Human review, testing, static analysis, and approved data-handling policies remain necessary. AI tools should not receive secrets or confidential source code unless organizational controls permit it.

Contemporary engineering increasingly uses software composition analysis, infrastructure-as-code scanning, runtime application self-protection, OpenTelemetry-compatible telemetry, confidential computing, passkeys, and automated policy enforcement. These tools improve consistency but do not replace threat modeling, architectural reasoning, or accountability.

Best-Practice Checklist

Before releasing a Java service, confirm that:

  • trust boundaries and protected assets have been identified;
  • external input is validated for syntax, semantics, size, and context;
  • database and command interfaces separate data from instructions;
  • authentication, session management, and authorization are independently tested;
  • secrets are managed outside source code and logs;
  • dependencies, licenses, versions, and vulnerabilities are governed;
  • performance objectives and representative workloads are defined;
  • profiling distinguishes measured bottlenecks from assumptions;
  • dashboards show traffic, errors, latency, saturation, and business outcomes;
  • logs are structured, useful, privacy-aware, and access-controlled;
  • traces connect important distributed operations;
  • capacity assumptions and headroom are documented;
  • architecture and build-versus-buy decisions record alternatives, risks, costs, and review dates.

Chapter Summary

Secure Java engineering combines threat modeling, least privilege, safe defaults, validation, parameterized interfaces, protected secrets, and explicit authorization. Authentication identifies a principal; authorization determines whether that principal may perform a specific operation on a specific resource.

Performance work requires defined workloads, baselines, profiling, careful benchmarking, and awareness of bottlenecks. Utilization, Little’s Law, throughput, latency, and capacity estimates are useful when their assumptions and units are made explicit. Observability combines structured logs, metrics, and distributed traces. SLIs and SLOs translate operational expectations into measurable objectives.

Technical governance controls dependencies, software supply-chain risk, architectural decisions, and trade-offs. SBOMs, vulnerability scanning, reproducible builds, and documented decision records improve accountability. Build-versus-buy analysis should consider total cost, risk, capability, maintainability, integration, and exit options rather than acquisition price alone. Across all topics, evidence and explicit assumptions produce better decisions than intuition or isolated tooling.

Key Terms

Authentication: Verification of a user or system identity.

Authorization: Determination of whether an authenticated principal may perform an action.

Allowlist: A defined set of permitted values or behaviors.

Threat modeling: Structured identification and treatment of security threats.

Least privilege: Granting only the permissions required for a task.

Injection: Treating untrusted data as executable syntax.

RBAC: Role-based access control in which permissions are assigned to roles.

ABAC: Attribute-based access control using subject, resource, action, and environmental attributes.

Dependency governance: Management of component versions, vulnerabilities, licenses, provenance, and updates.

SBOM: Software bill of materials listing software components and versions.

Latency: Time required to complete an operation.

Throughput: Completed operations per unit time.

Utilization: Fraction of a resource’s capacity currently being used.

Profiling: Measuring program behavior to locate resource consumption or bottlenecks.

Benchmarking: Controlled measurement used to compare performance under specified conditions.

Observability: Ability to infer internal system state from emitted telemetry.

SLI: Service-level indicator measuring a service property.

SLO: Service-level objective defining a target for an SLI.

Error budget: Permitted unreliability implied by an SLO.

Total cost of ownership: Acquisition, operation, integration, transition, and related costs over a defined period.

Review Questions

Short Answer Questions

  1. Distinguish authentication from authorization.
  2. Why are parameterized SQL statements safer than string concatenation?
  3. What is the purpose of an SBOM?
  4. Name the three principal observability signals discussed in this chapter.
  5. State one limitation of a simple capacity estimate based on identical instances.

Long Answer Questions

  1. Explain how threat modeling can guide secure design decisions in a Java service.
  2. Compare RBAC and ABAC, including a situation in which each is appropriate.
  3. Describe a disciplined process for profiling and benchmarking a Java application.
  4. Explain how logs, metrics, traces, SLIs, and SLOs work together during incident analysis.
  5. Discuss the technical and managerial factors that should be included in a build-versus-buy decision.

Analytical / Application Questions

  1. A service receives 60 requests per second and has an average latency of 0.4 seconds. Use Little’s Law to estimate the average number of in-flight requests, and explain what the result does not reveal.
  2. Design an authorization strategy for a multi-tenant order service. Identify the trust boundary, protected resources, required checks, and tests needed to prevent cross-tenant access.
  3. A proposed library has a low license cost but requires substantial integration, has a history of delayed security patches, and creates vendor lock-in. Compare it with an internal implementation using a documented decision matrix and recommend what additional evidence should be collected.

Multiple Choice Questions with Answers

Question 1

Which statement best distinguishes authentication from authorization?

A. Authentication determines permissions; authorization verifies identity.

B. Authentication verifies identity; authorization determines permitted actions.

C. Authentication encrypts data; authorization compresses data.

D. Authentication validates input; authorization formats output.

Correct Answer: B. Authentication verifies identity; authorization determines permitted actions.

Question 2

Which technique most directly prevents SQL injection in Java?

A. Concatenating only short strings

B. Hiding SQL errors from users

C. Using parameterized statements

D. Converting all input to uppercase

Correct Answer: C. Using parameterized statements

Question 3

A service receives 40 requests per second and has an average latency of 0.25 seconds. According to Little’s Law, what is the average number of in-flight requests?

A. 10 requests

B. 16 requests

C. 40 requests

D. 160 requests

Correct Answer: A. 10 requests

Question 4

Which observability signal is most suitable for following one request across several services?

A. A distributed trace

B. A static configuration file

C. A dependency manifest

D. A source-code comment

Correct Answer: A. A distributed trace

Question 5

Why should unrestricted user IDs generally not be used as metric labels?

A. They prevent metrics from being collected at all.

B. They can create excessive time-series cardinality.

C. They automatically encrypt the metric data.

D. They make CPU utilization equal to zero.

Correct Answer: B. They can create excessive time-series cardinality.

Question 6

For a 99.9% availability objective over an approximated 30-day month, what is the approximate error budget?

A. 4.32 minutes

B. 14.4 minutes

C. 43.2 minutes

D. 432 minutes

Correct Answer: C. 43.2 minutes

Question 7

Which principle requires checking permissions for the specific protected operation or resource?

A. Complete mediation

B. Data compression

C. Eventual consistency

D. Dead-code elimination

Correct Answer: A. Complete mediation

Question 8

Which statement about Java microbenchmarks is correct?

A. A single un-warmed run is always sufficient.

B. JIT compilation and dead-code elimination can affect results.

C. Hardware and Java version never matter.

D. Microbenchmarks replace all end-to-end performance tests.

Correct Answer: B. JIT compilation and dead-code elimination can affect results.

Question 9

What is a primary purpose of a software bill of materials?

A. To list software components and their versions

B. To replace all authorization checks

C. To guarantee zero production defects

D. To measure network latency directly

Correct Answer: A. To list software components and their versions

Question 10

Which factor should normally be included in build-versus-buy analysis?

A. Only the initial purchase price

B. Only the number of source-code lines

C. Integration, operating cost, risk, and exit options

D. The personal preference of the first developer consulted

Correct Answer: C. Integration, operating cost, risk, and exit options

Object-Oriented Programming (Java)
Chapter 14 of 15