SDLC models, requirement analysis, testing strategy and engineering process fundamentals.
The Software Development Life Cycle (SDLC) is a framework that defines the process used by organizations to build an application. Each model has distinct phases, trade-offs, and suitability for different project types. Understanding these models is critical for placement interviews.
| Model | Phases | Risk Handling | Best For | Flexibility |
|---|---|---|---|---|
| Waterfall | Linear sequential: Req, Design, Impl, Test, Deploy, Maintain | High risk (late testing) | Well-understood, stable requirements | Very Low |
| Iterative | Repeat small cycles of design, impl, test | Moderate (early feedback) | Large systems with evolving needs | Moderate |
| Spiral | Planning, Risk Analysis, Engineering, Evaluation (per spiral) | Low (explicit risk analysis) | High-risk, mission-critical projects | High |
| V-Model | Verification & Validation: each dev phase has a test phase | Moderate (parallel testing) | Safety-critical, regulated systems | Low |
| Agile | Iterative sprints, continuous delivery, adaptive planning | Low (incremental delivery) | Changing requirements, fast time-to-market | Very High |
| RAD | Rapid prototyping, iterative delivery, user feedback loops | Low (early user validation) | GUI-heavy, time-constrained projects | High |
The oldest and most straightforward SDLC model. Each phase must be completed before the next begins. Originated in manufacturing and construction industries.
An iterative approach where requirements evolve through collaboration. Delivers working software in small increments (sprints). Based on the Agile Manifesto (2001).
Proposed by Barry Boehm (1988). Combines iterative development with systematic risk assessment. Each spiral (cycle) goes through four quadrants.
Extension of Waterfall where each development phase has a corresponding testing phase. The left side is verification (are we building the right product?), the right side is validation (are we building the product right?).
SDLC Model Selection Decision Guide
════════════════════════════════════════════════════════════
Q1: Are requirements well-understood and stable?
YES → Q2: Is the project safety-critical or regulated?
YES → V-Model (verification & validation)
NO → Waterfall (simple, predictable)
NO → Q3: Is the project high-risk and large-budget?
YES → Spiral (explicit risk analysis)
NO → Q4: Is time-to-market the top priority?
YES → RAD (rapid prototyping)
NO → Agile (flexible, iterative)
Key Interview Points:
• Waterfall = predictable but inflexible
• Agile = flexible but less predictable
• Spiral = risk-focused but expensive
• V-Model = quality-focused but rigid
• RAD = fast but less scalable
• Iterative = balanced but moderate overheadRequirements Engineering is the systematic process of eliciting, documenting, validating, and managing requirements. Errors here are the most expensive to fix later — a defect in requirements costs 100x more to fix in maintenance than in the requirements phase.
| Type | Category | Examples | Measured By |
|---|---|---|---|
| Functional | What the system MUST do | Login, search, checkout, generate report, send notifications | Test cases, acceptance criteria |
| Non-Functional | How the system SHOULD perform | Response time < 200ms, 99.9% uptime, OWASP compliance, 10K concurrent users | SLAs, benchmarks, audits |
| Performance | Non-functional: speed | Page load < 2s, API response < 500ms, throughput 1000 req/s | Load testing tools (JMeter, k6) |
| Security | Non-functional: protection | Encryption at rest & in transit, RBAC, input validation, audit logging | Penetration testing, OWASP ZAP |
| Usability | Non-functional: user experience | Responsive design, accessibility (WCAG 2.1 AA), intuitive navigation | User testing, heuristics |
| Reliability | Non-functional: dependability | 99.99% availability, fault tolerance, graceful degradation | Chaos testing, MTBF/MTTR |
| Scalability | Non-functional: growth | Horizontal scaling, auto-scaling, zero-downtime deployment | Stress testing, capacity planning |
| Section | Content | Interview Importance |
|---|---|---|
| 1. Introduction | Purpose, scope, definitions, references, overview | Shows you understand documentation standards |
| 2. Overall Description | Product perspective, user characteristics, constraints, assumptions | Critical for system context |
| 3. Specific Requirements | Functional requirements, external interfaces, performance, design constraints | Core of the document |
| 4. Supporting Info | Index, appendix, change history | Maintainability of the document |
| Technique | Description | Best For | Output |
|---|---|---|---|
| Interviews | One-on-one structured/unstructured interviews with stakeholders | Understanding deep needs, uncovering hidden requirements | Interview notes, requirement lists |
| Questionnaires | Distributed surveys with closed/open-ended questions | Large user bases, quantitative data collection | Statistical data, trend analysis |
| Observation | Watch users perform their tasks in real environment | Discovering implicit requirements users cannot articulate | Workflow diagrams, pain points |
| Workshops | Facilitated group sessions (JAD sessions) | Resolving conflicts, building consensus | Prioritized requirements, action items |
| Prototyping | Build a quick mockup or throwaway prototype | Clarifying ambiguous requirements, user validation | Refined requirements, user feedback |
| Document Analysis | Review existing docs: manuals, forms, reports | Understanding current system processes | Derived requirements, gaps identified |
| Brainstorming | Group ideation session for new features | Creative requirements, feature discovery | Feature lists, innovation ideas |
| Use Case Analysis | Define actors, use cases, and interactions | Functional requirements, system boundaries | Use case diagrams, scenarios |
Use Case Diagram — Online Shopping System
════════════════════════════════════════════════════════════
[Actor: Customer]
├── Browse Products
├── Search Products
├── Add to Cart
├── Remove from Cart
├── Checkout
├── Make Payment <<include>> → Validate Payment
├── View Order History
└── Track Order <<extend>> ← Track by SMS
[Actor: Admin]
├── Manage Products (CRUD)
├── Manage Users
├── View Analytics
└── Process Refunds
[Actor: Payment Gateway] (External System)
├── Validate Payment
└── Process Refund
Relationships:
• <<include>> — mandatory sub-flow (always executed)
• <<extend>> — optional/conditional flow (may or may not happen)
• Generalization — specialized use case inherits from parent| Feasibility Type | Assessment | Key Questions |
|---|---|---|
| Technical | Can we build it with current tech and expertise? | Do we have the technology? Is it proven? Are skills available? |
| Economic | Is it cost-effective? Will ROI justify the investment? | Cost-benefit analysis: development cost vs. expected revenue/savings? |
| Operational | Will it fit the organization and users? | Will users accept it? Does it align with business processes? |
| Schedule | Can it be delivered within the required timeline? | Are deadlines realistic? What are the critical path risks? |
| Legal | Are there regulatory or legal constraints? | Compliance with GDPR, HIPAA, licensing, intellectual property? |
Software Testing is the process of evaluating a system with the intent to find defects. It verifies that the system meets specified requirements and validates that it fulfills user expectations. Testing accounts for 30-50% of total project cost in large systems.
| Level | Scope | Who Performs | Focus | Tools |
|---|---|---|---|---|
| Unit Testing | Individual functions/methods/classes | Developers | Code correctness, logic | JUnit, pytest, Jest, Mocha |
| Integration Testing | Module interactions & interfaces | Developers / QA | Data flow between modules | Postman, Supertest, Spring Test |
| System Testing | Entire integrated system | QA Team | End-to-end functionality | Selenium, Cypress, Playwright |
| Acceptance Testing | Business requirements validation | Clients / End Users | User expectations met | Manual testing, UAT sign-off |
Testing without knowledge of internal code structure. Focuses on inputs and outputs.
Testing with knowledge of internal code structure. Focuses on code paths and logic coverage.
# ── White Box Coverage Example ──
def classify_age(age):
"""Classify a person by age group."""
if age < 0 or age > 150: # Branch 1: invalid
return "Invalid"
elif age < 13: # Branch 2: child
return "Child"
elif age < 20: # Branch 3: teenager
return "Teenager"
elif age < 65: # Branch 4: adult
return "Adult"
else: # Branch 5: senior
return "Senior"
# Statement Coverage: need test for every return statement
# Tests: -1 (Invalid), 5 (Child), 16 (Teenager), 30 (Adult), 80 (Senior)
# All 5 return statements executed → 100% statement coverage
# Branch Coverage: each if/elif evaluated to True AND False
# Branch 1: True (age=-1), False (age=5)
# Branch 2: True (age=5), False (age=16)
# Branch 3: True (age=16), False (age=30)
# Branch 4: True (age=30), False (age=80)
# Branch 5: always True when reached
# Tests: -1, 5, 16, 30, 80 → 100% branch coverage
# ── Black Box: Boundary Value Analysis ──
# Valid range: [0, 150]
# Test values: -1, 0, 1, 149, 150, 151 (6 values at boundaries)TEST CASE TEMPLATE
════════════════════════════════════════════════════════════
Test Case ID: TC-LOGIN-001
Title: Verify successful login with valid credentials
Pre-conditions: User account exists; browser is open
Priority: High
Module: Authentication
Steps:
1. Navigate to login page
2. Enter valid username "testuser@example.com"
3. Enter valid password "SecurePass123!"
4. Click "Sign In" button
Expected Result: User is redirected to dashboard; welcome message displayed
Actual Result: (filled during execution)
Status: PASS / FAIL / BLOCKED
Test Case ID: TC-LOGIN-002
Title: Verify login with invalid password
Steps: Same as TC-LOGIN-001 but with password "WrongPass"
Expected Result: Error message "Invalid credentials" displayed; no redirect| Aspect | Testing | Debugging |
|---|---|---|
| Purpose | Find defects (preventive) | Fix defects (corrective) |
| When | Before the system is deployed | After defects are found |
| Who | Testers (QA) and Developers | Developers only |
| Process | Systematic, planned, documented | Ad-hoc, unstructured |
| Goal | Improve quality by finding issues | Resolve the root cause of a specific issue |
| Verification vs Validation | Both verification & validation | Root cause analysis and correction |
| Automation | Highly automatable | Partially automatable (debuggers) |
Software Design is the process of defining the architecture, components, interfaces, and data for a system to satisfy specified requirements. Good design follows the principle of separation of concerns and modularity.
| Coupling Level | Type | Description | Example |
|---|---|---|---|
| Lowest | No Coupling | Modules are completely independent | Standalone utility functions |
| Very Low | Data Coupling | Modules share data through parameters only | function add(a, b) |
| Low | Stamp Coupling | Modules share a composite data structure (use only parts) | Passing a struct with extra fields |
| Medium | Control Coupling | One module passes control flags to another | function process(data, flag=true) |
| Medium-High | Common Coupling | Modules share global data | Global variables, shared databases |
| High | Content Coupling | One module directly accesses another's internals | Reaching into another module's private data |
Rule of thumb: Aim for data coupling (pass data as parameters). Avoid content coupling (one module directly modifying another's data). Lower coupling <> easier maintenance, testing, and reuse.
| Cohesion Level | Type | Description | Example |
|---|---|---|---|
| Lowest | Coincidental | Unrelated functions grouped together | A module with print, sort, and compute functions |
| Very Low | Logical | Functions related logically but do different things | All input functions (read keyboard, file, network) |
| Low | Temporal | Functions executed at the same time | Initialization code that sets up various systems |
| Medium | Procedural | Functions that always execute in sequence | Read input -> validate -> save |
| Medium-High | Communicational | Functions operate on the same data | Functions that all work on a "Customer" record |
| High | Sequential | Output of one feeds input of next | Parse token -> validate -> evaluate |
| Highest | Functional | One single well-defined purpose | A module that only computes square root |
Rule of thumb: Aim for functional cohesion (one clear purpose per module). High cohesion means related code is together, making it easier to understand, test, and maintain.
| Principle | Full Name | Description | Example |
|---|---|---|---|
| S | Single Responsibility | A class should have only one reason to change | Separate UserAuth and UserProfile classes instead of one God class |
| O | Open/Closed | Open for extension, closed for modification | Use interfaces/polymorphism to add behavior without changing existing code |
| L | Liskov Substitution | Subtypes must be substitutable for their base types | Square IS-NOT-A Rectangle if it violates setWidth/Height contract |
| I | Interface Segregation | Separate Printable and Savable interfaces instead of one large DocumentInterface | |
| D | Dependency Inversion | Depend on abstractions, not concretions | Use dependency injection; code to interfaces, not implementations |
UML Diagrams Overview (Unified Modeling Language)
════════════════════════════════════════════════════════════
STRUCTURAL DIAGRAMS (Static View):
┌──────────────────┬──────────────────────────────────────────┐
│ Class Diagram │ Classes, attributes, methods, relations │
│ │ + public, - private, # protected │
│ │ Inheritance (▲), Composition (◆), Agg(◇) │
├──────────────────┼──────────────────────────────────────────┤
│ Object Diagram │ Instance snapshot of class diagram │
├──────────────────┼──────────────────────────────────────────┤
│ Component Diagram│ Physical components and their interfaces │
│ │ Used in system architecture design │
├──────────────────┼──────────────────────────────────────────┤
│ Deployment Diagram│ Hardware nodes and software allocation │
│ │ Shows servers, containers, communication │
├──────────────────┼──────────────────────────────────────────┤
│ Package Diagram │ Organization of packages and dependencies│
└──────────────────┴──────────────────────────────────────────┘
BEHAVIORAL DIAGRAMS (Dynamic View):
┌──────────────────┬──────────────────────────────────────────┐
│ Sequence Diagram │ Object interactions in time order │
│ │ Shows messages between objects │
├──────────────────┼──────────────────────────────────────────┤
│ Activity Diagram │ Flow of activities/decisions (flowchart+) │
│ │ Parallel activities, swimlanes │
├──────────────────┼──────────────────────────────────────────┤
│ State Diagram │ States an object can be in and transitions│
│ │ Triggers, guards, actions │
├──────────────────┼──────────────────────────────────────────┤
│ Use Case Diagram │ Actors and their interactions with system │
├──────────────────┼──────────────────────────────────────────┤
│ Timing Diagram │ Interaction timing constraints │
├──────────────────┼──────────────────────────────────────────┤
│ Communication │ Object interactions (focus on links) │
└──────────────────┴──────────────────────────────────────────┘
Key Relationships in Class Diagrams:
• Inheritance (Generalization): "is-a" → Solid line with hollow triangle
• Implementation (Realization): "implements" → Dashed line with hollow triangle
• Association: "uses" → Solid line with arrow
• Aggregation: "has-a" (weak) → Solid line with hollow diamond
• Composition: "owns-a" (strong, lifecycle) → Solid line with filled diamond
• Dependency: "depends on" → Dashed line with arrowAgile is a set of values and principles for software development under which requirements and solutions evolve through collaborative effort. The Agile Manifesto (2001) values individuals and interactions over processes and tools, working software over comprehensive documentation, customer collaboration over contract negotiation, and responding to change over following a plan.
THE AGILE MANIFESTO (2001)
════════════════════════════════════════════════════════════
We are uncovering better ways of developing software by doing it
and helping others do it. Through this work we have come to value:
Individuals and interactions over Processes and tools
Working software over Comprehensive documentation
Customer collaboration over Contract negotiation
Responding to change over Following a plan
That is, while there is value in the items on the right,
we value the items on the left more.
12 PRINCIPLES BEHIND THE MANIFESTO:
1. Highest priority: satisfy the customer through early & continuous delivery
2. Welcome changing requirements, even late in development
3. Deliver working software frequently (weeks, not months)
4. Business and developers must work together daily
5. Build projects around motivated individuals; trust them
6. Face-to-face conversation is the most efficient communication
7. Working software is the primary measure of progress
8. Sustainable development — maintain a constant pace indefinitely
9. Continuous attention to technical excellence and good design
10. Simplicity — maximizing the amount of work not done
11. The best architectures, requirements, and designs emerge from self-organizing teams
12. Regularly reflect on how to become more effective, then adjust accordingly| Element | Role/Item | Description |
|---|---|---|
| Product Owner | Role | Represents stakeholders; owns the Product Backlog; prioritizes features based on business value; makes final decisions on scope |
| Scrum Master | Role | Facilitator and coach; removes impediments; shields team from distractions; ensures Scrum practices are followed |
| Development Team | Role | Self-organizing, cross-functional team (5-9 members); does the actual work; estimates tasks; commits to Sprint Goal |
| Product Backlog | Artifact | Ordered list of everything needed in the product; maintained by Product Owner; continuously refined and prioritized |
| Sprint Backlog | Artifact | Set of items selected for the sprint + plan for delivering them; owned by the Development Team |
| Increment | Artifact | Sum of all completed Product Backlog items at the end of a sprint; must be in potentially shippable condition |
| Sprint Planning | Ceremony | Start of sprint; team selects items from Product Backlog; creates Sprint Backlog; timeboxed to 8 hrs (1-month sprint) |
| Daily Standup | Ceremony | 15-min daily meeting; each member answers: What did I do? What will I do? Any blockers? |
| Sprint Review | Ceremony | End of sprint; demo working increment to stakeholders; gather feedback; timeboxed to 4 hrs |
| Sprint Retrospective | Ceremony | After review; team reflects on process; identifies improvements for next sprint; timeboxed to 3 hrs |
| Sprint | Event | Timeboxed iteration (1-4 weeks, typically 2); all other events are contained within a sprint |
A visual workflow management method that focuses on continuous delivery without overloading the team.
An Agile methodology that emphasizes engineering excellence and technical practices.
USER STORIES & ESTIMATION
════════════════════════════════════════════════════════════
USER STORY FORMAT (As a... I want to... So that...):
"As a registered user, I want to reset my password via email,
so that I can regain access to my account if I forget it."
USER STORY ANATOMY:
Title: Password Reset via Email
Description: As a <role>, I want <action>, so that <benefit>
Acceptance Criteria (Given-When-Then format):
Given: I am on the login page and I forgot my password
When: I enter my registered email and click "Reset"
Then: A password reset link is sent to my email within 2 minutes
And: The link expires after 24 hours
STORY POINTS (Fibonacci Sequence: 1, 2, 3, 5, 8, 13, 21):
1 = Trivial (few minutes, no risk)
2 = Simple (hours, well-understood)
3 = Moderate (half a day, some unknowns)
5 = Complex (1-2 days, needs discussion)
8 = Very Complex (3-5 days, high risk)
13 = Extremely Complex (needs to be broken down)
21 = Too big → MUST split into smaller stories
VELOCITY = Total story points completed in a sprint
Sprint 1: 5 + 3 + 8 + 2 + 5 = 23 points → Velocity = 23
Sprint 2: 8 + 3 + 5 + 8 = 24 points → Velocity = 24
Average velocity ≈ 23.5 points/sprint
Use velocity to predict: "We have 100 points remaining.
At 23.5 points/sprint, we need ~5 more sprints (10 weeks)."
PLANNING POKER (Estimation Technique):
1. Product Owner reads the user story
2. Team asks clarifying questions
3. Each member privately selects a card (1, 2, 3, 5, 8, 13...)
4. Cards revealed simultaneously
5. Highest and lowest explain their reasoning
6. Repeat until consensusDesign patterns are reusable solutions to commonly occurring problems in software design. They are categorized into three types: Creational (object creation), Structural (composition), and Behavioral (object interaction). GRASP patterns focus on assigning responsibilities to objects.
| Pattern | Principle | Guideline | Example |
|---|---|---|---|
| Information Expert | Assign responsibility to the class that has the information needed | Who has the data needed to fulfill the responsibility? | Order.calculateTotal() — Order has the line items, so it calculates the total |
| Creator | Who should create an object? | Assign to the class that closely uses, aggregates, or contains the new object | Customer creates Orders; a Customer "contains" Orders |
| Controller | Who handles system events? | Assign a non-UI class to handle system operation events | OrderController handles "place order" event; separate from UI and domain |
| Low Coupling | Reduce dependencies between classes | Assign responsibilities so coupling remains low | Use interfaces instead of concrete classes; pass data via parameters |
| High Cohesion | Keep related functionality together | Assign responsibilities so cohesion remains high | A User class handles user data only, not payment processing |
| Polymorphism | Handle variations based on type | Assign type-specific behavior using polymorphic operations | Shape interface with draw(); Circle and Rectangle implement differently |
| Pure Fabrication | Invent a class that does not represent a domain concept | When high cohesion/low coupling cannot be achieved with domain classes | TaxCalculator — not a real-world concept, but improves design |
| Indirection | Assign responsibility to an intermediary | Reduce coupling between two classes by using a mediator | Adapter between incompatible interfaces; Mediator for complex coordination |
| Protected Variations | Protect stable parts from variations | Identify points of likely change; create stable interfaces around them | Strategy pattern encapsulates algorithms; add new algorithms without changing clients |
| Pattern | Category | Intent | Use Case |
|---|---|---|---|
| Singleton | Creational | Ensure a class has only one instance with global access point | Database connection pool, logger, configuration manager, thread pool |
| Factory Method | Creational | Define an interface for creating objects; let subclasses decide which class to instantiate | Document creator (PDF/Word), cross-platform UI components, payment processor |
| Abstract Factory | Creational | Create families of related objects without specifying their concrete classes | UI toolkit for different OS (Windows/Mac/Linux), database driver families |
| Builder | Creational | Separate object construction from its representation; step-by-step construction | SQL query builder, HTTP request builder, complex object assembly |
| Prototype | Creational | Clone existing objects without coupling to their concrete classes | Copy-on-write patterns, configuration templates, deep-copying complex objects |
| Pattern | Category | Intent | Use Case |
|---|---|---|---|
| Adapter | Structural | Convert one interface into another that clients expect | Legacy system integration, third-party API wrappers, data format conversion |
| Decorator | Structural | Add responsibilities to objects dynamically without subclassing | Stream I/O (BufferedInputStream wrapping FileInputStream), UI component styling |
| Facade | Structural | Provide a simplified interface to a complex subsystem | API gateway, compilation pipeline, home theater system control |
| Observer | Behavioral | One-to-many dependency; when one changes, all dependents are notified | Event systems, pub/sub, MVC (model notifies view), stock price alerts |
| Strategy | Behavioral | Define a family of algorithms, encapsulate each, make them interchangeable | Sorting algorithms, payment methods, routing strategies, compression |
| Command | Behavioral | Encapsulate a request as an object | Undo/redo operations, job queues, macro recording, menu actions |
| Iterator | Behavioral | Access elements of an aggregate sequentially without exposing representation | Collection traversal, tree traversal, lazy evaluation |
| State | Behavioral | Allow an object to alter its behavior when its state changes | Vending machine, order lifecycle (pending/shipped/delivered), TCP connection states |
# ── Singleton Pattern ──
class DatabaseConnection:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._connection = "Connected to DB"
return cls._instance
db1 = DatabaseConnection() # Creates instance
db2 = DatabaseConnection() # Returns same instance
assert db1 is db2 # True — same object
# ── Observer Pattern ──
class EventManager:
def __init__(self):
self._listeners = {}
def subscribe(self, event_type, listener):
self._listeners.setdefault(event_type, []).append(listener)
def notify(self, event_type, data):
for listener in self._listeners.get(event_type, []):
listener(data)
em = EventManager()
em.subscribe("order_created", lambda data: print(f"Email: {data}"))
em.subscribe("order_created", lambda data: print(f"Log: {data}"))
em.notify("order_created", "Order #1234 created")
# Output: Email: Order #1234 created
# Log: Order #1234 created
# ── Strategy Pattern ──
class SortStrategy:
def sort(self, data): pass
class BubbleSort(SortStrategy):
def sort(self, data): return sorted(data) # simplified
class QuickSort(SortStrategy):
def sort(self, data): return sorted(data, reverse=True)
class Sorter:
def __init__(self, strategy):
self._strategy = strategy
def execute(self, data):
return self._strategy.sort(data)
sorter = Sorter(QuickSort())
sorter.execute([3, 1, 4, 1, 5]) # [5, 4, 3, 1, 1]
# ── Factory Method Pattern ──
class Notification:
def send(self, msg): pass
class EmailNotification(Notification):
def send(self, msg): print(f"Email: {msg}")
class SMSNotification(Notification):
def send(self, msg): print(f"SMS: {msg}")
class NotificationFactory:
@staticmethod
def create(channel):
if channel == "email": return EmailNotification()
if channel == "sms": return SMSNotification()
raise ValueError(f"Unknown channel: {channel}")
factory = NotificationFactory()
factory.create("email").send("Hello!") # Email: Hello!Software maintenance consumes 60-80% of total software lifecycle cost. It includes modifying a system after delivery to correct faults, improve performance, adapt to a changed environment, or prevent future problems.
| Type | Purpose | Example | Cost Share |
|---|---|---|---|
| Corrective | Fix bugs and defects discovered after delivery | Fix a crash when user clicks "Export" with empty data | ~20% |
| Adaptive | Modify software to work in a new or changed environment | Migrate from MySQL to PostgreSQL; upgrade from Java 8 to 17 | ~25% |
| Perfective | Improve existing functionality, add new features, enhance performance | Add dark mode; optimize query from 5s to 200ms; add search filters | ~50% |
| Preventive | Prevent future problems through restructuring and documentation | Refactor legacy code; add monitoring; update dependencies to prevent vulnerabilities | ~5% |
| Metric | Type | Description | Formula / Value |
|---|---|---|---|
| LOC (Lines of Code) | Size | Total lines of source code (excluding blanks/comments) | Count of executable statements |
| Cyclomatic Complexity (V(G)) | Complexity | Number of linearly independent paths through code | V(G) = E - N + 2 (E=edges, N=nodes in CFG) |
| Function Points | Size | Measures functionality based on inputs, outputs, inquiries, files | UFP * VAF (Value Adjustment Factor) |
| Cohesion Metrics (LCOM) | Quality | Lack of Cohesion of Methods — measures how focused a class is | LCOM = 1 - (sum(m_i)/m*a) where m_i = methods accessing attr i |
| Coupling Metrics (CBO) | Quality | Coupling Between Objects — classes a class depends on | CBO = number of other classes it couples to |
| Maintainability Index | Quality | Overall maintainability (higher is better) | MI = 171 - 5.2*ln(V) - 0.23*G - 16.2*ln(LOC) |
| Defect Density | Quality | Defects per unit size (KLOC) | DD = Total Defects / KLOC |
| Code Churn | Process | Rate of code change over time | Lines added + deleted / time period |
| Technical Debt Ratio | Quality | Ratio of remediation cost to development cost | TD = Remediation Cost / Total Development Cost |
| Code Coverage | Testing | Percentage of code exercised by tests | Statement/Branch/Path coverage % |
# ── Cyclomatic Complexity Calculation ──
# V(G) = Decision Points + 1
# Decision points: if, elif, for, while, and, or, case, catch
# Example 1: Simple (V(G) = 1)
def add(a, b):
return a + b # No decisions → V(G) = 1
# Example 2: One decision (V(G) = 2)
def is_adult(age):
if age >= 18: # +1 decision
return True
return False # V(G) = 1 + 1 = 2
# Example 3: Multiple decisions (V(G) = 4)
def classify(age, income):
if age < 18: # +1
return "Minor"
elif income < 30000: # +1
return "Low Income Adult"
elif income < 75000: # +1
return "Middle Income Adult"
return "High Income Adult" # V(G) = 3 + 1 = 4
# Example 4: Nested (V(G) = 3)
def process(data):
if data is not None: # +1
for item in data: # +1
if item > 0: # +1
process(item)
# V(G) = 3 + 1 = 4
# Complexity Thresholds:
# 1-10: Low risk (simple, easy to test)
# 11-20: Moderate risk (manageable)
# 21-50: High risk (difficult to test, refactor recommended)
# 50+: Very high risk (untestable, MUST refactor)CODE REFACTORING TECHNIQUES
════════════════════════════════════════════════════════════
COMPOSING METHODS (Simplifying Code):
• Extract Method — Take a code fragment, make it a separate function
• Inline Method — Remove a method body and put it where it was called
• Replace Temp with Query — Replace a temporary variable with a query method
• Introduce Explaining Variable — Break complex expressions into named variables
• Decompose Conditional — Extract if/else branches into separate methods
ORGANIZING DATA:
• Encapsulate Field — Make fields private with getters/setters
• Replace Magic Number — Replace literal numbers with named constants
• Replace Type Code with Class — Use classes/polymorphism instead of type flags
• Replace Array with Object — Replace array of data with a proper data class
SIMPLIFYING CONDITIONALS:
• Decompose Conditional — Extract condition logic into named methods
• Consolidate Conditional Expression — Combine conditions with same result
• Replace Conditional with Polymorphism — Use Strategy/State pattern
• Introduce Null Object — Instead of null checks, use a null object
MOVING FEATURES:
• Move Method — Move method to the class that uses it most
• Move Field — Move field to the class that uses it most
• Extract Class — Split a large class into two smaller ones
• Hide Delegate — Hide the intermediate object from the client
GENERALIZATION:
• Pull Up Field/Method — Move common fields/methods to a base class
• Push Down Field/Method — Move specific fields/methods to subclasses
• Extract Interface — Create an interface from common methods
• Replace Inheritance with Delegation — Prefer composition over inheritance
REFACTORING GOLDEN RULES:
1. Refactor ONLY when you have passing tests
2. Make small, incremental changes
3. Run tests after each refactoring step
4. Use meaningful names
5. Don't add functionality while refactoring (separate the concerns)| Concept | Description | Command |
|---|---|---|
| Repository | Database storing all files, their full history, and metadata | git init, git clone |
| Commit | Snapshot of project at a point in time | git commit -m "message" |
| Branch | Independent line of development | git branch, git checkout -b feature |
| Merge | Combine changes from one branch into another | git merge feature |
| Rebase | Move/reapply commits on top of another base | git rebase main |
| Pull Request | Request to merge a branch; enables code review | GitHub/GitLab PR/ MR |
| Conflict | When changes in two branches modify the same lines | Manually resolve, then commit |
| Revert | Create a new commit that undoes a previous commit | git revert {commitHash} |
| Cherry-pick | Apply a specific commit from another branch | git cherry-pick {commitHash} |
| Tag | Named reference to a specific commit (e.g., v1.0.0) | git tag -a v1.0.0 -m "Release" |
| Stash | Temporarily store uncommitted changes | git stash, git stash pop |
| Submodule | Git repository embedded inside another repository | git submodule add {url} |
Frequently asked software engineering interview questions with structured answers. Master these for campus placements, technical interviews, and competitive exams like GATE.
Waterfall is a linear, sequential model where each phase (requirements, design, implementation, testing, deployment) must be completed before the next begins. The customer sees the product only at the end. It is best for projects with stable, well-understood requirements (e.g., construction, embedded systems).
Agile is an iterative model that delivers working software in small increments called sprints (1-4 weeks). It embraces changing requirements, continuous customer feedback, and adaptive planning. It is best for projects with evolving requirements and fast time-to-market needs (e.g., web apps, SaaS products).
Key differences:Waterfall is plan-driven (predictive), Agile is value-driven (adaptive). Waterfall has one big release, Agile has incremental releases. Waterfall measures success by "on time, on budget," Agile measures success by "customer satisfaction and working software." Waterfall documentation is extensive; Agile favors working software over comprehensive documentation.
Black Box Testing tests the software without knowledge of internal code structure. The tester only knows the inputs and expected outputs. Techniques include Equivalence Partitioning (dividing inputs into valid/invalid classes), Boundary Value Analysis (testing at edges), Decision Table Testing, and State Transition Testing. Example: testing a login form by entering various username/password combinations without reading the source code.
White Box Testing (also called structural or glass box testing) tests the internal logic, structure, and code paths. The tester has access to source code and examines code coverage. Techniques include Statement Coverage (every line executed), Branch Coverage (every if/else branch taken), Path Coverage (every execution path through code), and Loop Testing.
Key difference:Black Box is done by testers (and sometimes users), focuses on "what" the system does. White Box is done by developers, focuses on "how" the system works internally. In practice, both are needed: White Box catches logic errors, Black Box catches requirement gaps.
Coupling measures how much two modules depend on each other. Low coupling is desirable — changes in one module should not require changes in another.
Cohesion measures how closely related the responsibilities of a single module are.High cohesion is desirable — a module should do one thing well.
Example — Low Coupling: A UserService calls EmailService.send()by passing email address and message as parameters (data coupling). Changes to EmailService's internal implementation won't affect UserService.
Example — High Cohesion: A Calculator class contains onlyadd(), subtract(), multiply(), and divide() methods — all related to mathematical operations.
Example — Low Cohesion (bad): A Utility class containingsendEmail(), calculateTax(), parseJSON(), and drawChart() — completely unrelated functions grouped together.
Example — High Coupling (bad): ModuleA directly reads and modifiesModuleB's internal variables (content coupling). Changing ModuleB's variable names will break ModuleA.
S — Single Responsibility Principle: A class should have one reason to change. Example: Separate Invoice (calculates amounts) from InvoicePrinter(formats and prints). If printing format changes, only InvoicePrinter is affected.
O — Open/Closed Principle: Open for extension, closed for modification. Example: A NotificationService with an INotification interface. To add SMS notifications, create a new SMSNotification class — no need to modify existing EmailNotification or the service itself.
L — Liskov Substitution Principle: Subtypes must be substitutable for their base types. Example: If Penguin extends Bird and Bird hasfly(), then Penguin.fly() must work — but penguins cannot fly! Fix: Introduce FlyingBird and FlightlessBird subclasses.
I — Interface Segregation Principle: Many specific interfaces are better than one general interface. Example: Instead of one IMachine with print(), scan(), fax(), staple() — split intoIPrinter, IScanner, IFaxMachine. A simple printer only implements IPrinter.
D — Dependency Inversion Principle: Depend on abstractions, not concretions. Example: A OrderService should depend on IPaymentGateway(interface), not StripePaymentGateway (concrete). This allows switching payment providers by injecting different implementations.
Requirements: A parking lot has multiple levels, each with compact and motorcycle spots. Vehicles (car, motorcycle, bus) can park. A bus occupies 5 consecutive compact spots. The system must track availability, handle entry/exit, and calculate fees.
Classes: ParkingLot (has levels), Level (has rows of spots),ParkingSpot (type, vehicle, isFree), Vehicle (base) ->Car, Motorcycle, Bus (overrides spots needed),Ticket (entry time, vehicle, spot), ParkingFeeCalculator.
Key Design Decisions:
1. Encapsulation: Each level manages its own spots (high cohesion). The ParkingLot delegates to levels (low coupling).
2. Polymorphism: Vehicle is abstract; each subclass overrides getSpotsNeeded()(Car=1, Motorcycle=1, Bus=5). ParkingSpot checks if vehicle fits.
3. OCP/SRP: To add electric vehicle charging, add ChargingSpot andElectricVehicle — no modification to existing classes.
4. Fee Strategy: Use Strategy pattern for fee calculation (hourly, daily, flat rate). DIP: ParkingLot depends on IFeeStrategy.