6. Software Deployment and Software Maintenance

1. Deployment Strategies and Maintenance Techniques

The Project Review Scheduler implementation incorporated several deployment strategies and maintenance techniques to ensure reliable delivery and ongoing support of the system. These approaches were selected based on the specific needs of the project and aligned with industry best practices in software engineering.

Deployment Strategies

Phased Deployment

The system was developed with both a command-line interface (in scheduler.py) and a web-based interface using Streamlit (in streamlit_app.py). As Sumo Logic (n.d.) notes, phased deployment “implements system in stages” which offers “reduced risk” and “allows for learning” during implementation. This dual-interface approach facilitated incremental adoption, allowing users to choose their preferred method of interaction while minimizing disruption to existing workflows.

The phased approach is evident in the code structure, where core functionality is implemented in modular components that can be accessed through either interface:

def calculate_due_dates(projects_df):
    # Functionality available to both CLI and web interface
    projects_df['Start_Date'] = pd.to_datetime(projects_df['Start_Date'], errors='coerce')
    # ... implementation details ...
    return projects_df

Safe Deployment with Backups

Before making any changes to data files, the system implements an automatic backup system that creates timestamped backup files. Sumo Logic (n.d.) describes this as the “preparation” phase of deployment, where protecting existing resources is necessary.

def backup_file(file_path):
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    backup_path = f"{file_path}.{timestamp}.bak"
    with open(file_path, 'r') as src, open(backup_path, 'w') as dst:
        dst.write(src.read())
    print(f" Backed up {file_path} → {backup_path}")

The GitHub repository (https://github.com/cynthialmcginnis/ProjectReviewScheduler/tree/main) shows extensive evidence of this strategy’s implementation, with multiple backup files like “Projects.csv.20250515_202732.bak” demonstrating the system’s commit to data safety.

Adaptive File Creation

The system proactively manages file dependencies by checking for necessary files and creating them with appropriate headers if they don’t exist.

def create_csv_if_missing(file_path, schema=None):
    if os.path.exists(file_path):
        return False
    # Create appropriate schema based on filename
    # ...

This strategy supports Bennett’s (2024) concept of configuration identification, ensuring proper tracking and management of project assets throughout the deployment lifecycle.

Data Validation Before Deployment

Comprehensive validation ensures data integrity and prevents corrupted data from being deployed. Functions like validate_csv_data and validate_referential_integrity implement structured validation that checks data types, required fields, and relationships between entities.

def validate_csv_data(file_path, schema=None):
    # Validate the data in a CSV file against a schema
    # ...

This approach outlined by Sumo Logic (n.d.) emphasizes the importance of identifying issues before they reach production environments.

Maintenance Techniques

Comprehensive Documentation

The codebase includes detailed docstrings and comments that explain functionality and implementation. As Brown (2025) emphasizes, “Documentation is one of the most important parts of a software project,” providing a knowledge foundation that preserves institutional knowledge. Each function in the codebase includes purpose statements, parameter descriptions, and return value documentation:

def calculate_due_date(project_data, current_date=None):
    """
    Calculate the next review date based on the project's last review date and review frequency.
    
    Args:
        project_data (dict): Dictionary containing project information
        current_date (datetime or str, optional): Current date for comparison. Defaults to today.
    
    Returns:
        dict: Updated project data with Next_Review_Date and Status fields
    """

Modular Design

The codebase is organized into distinct functional modules:

  • Data Access Functions
  • Data Validation Functions
  • Due Date Calculator
  • Reviewer Assignment
  • Notification System
  • Reporting Module

This modular approach demonstrates the principles of technical documentation described by Brown (2025), making the software easier to maintain and update. Each module has a single responsibility, which reduces coupling between components and facilitates targeted maintenance activities.

Error Handling

The error handling implementation through try/except blocks represents an application of what Thales (n.d.) defines as “corrective software maintenance” - the systematic process of addressing faults and errors after they have been detected in operational software. According to Thales, corrective maintenance constitutes “the typical, classic form of maintenance” that becomes “necessary when something goes wrong in a piece of software including faults and errors.” Unlike other maintenance types that focus on enhancement or adaptation, corrective maintenance specifically targets existing defects that “can have a widespread impact on the functionality of the software in general and therefore must be addressed as quickly as possible.”

The Project Review Scheduler’s implementation of corrective maintenance principles manifests through exception-handling constructs that create fault isolation boundaries.

try:
    # Prepare and send email notification
    msg = EmailMessage()
    subject = f"Review Assignment: {row['Project_Name']}"
    msg['Subject'] = subject
    msg['From'] = sender_email
    msg['To'] = reviewer['Email']
    # Additional email preparation code...
    
    # Actual sending operation - highest risk of external failure
    with smtplib.SMTP(smtp_server, smtp_port) as server:
        server.starttls()
        if smtp_user and smtp_password:
            server.login(smtp_user, smtp_password)
        server.send_message(msg)
        
    # Record successful operation
    notification_log.append({
        'project_id': project['Project_ID'],
        'review_id': review['Review_ID'],
        'reviewer_email': reviewer['Email'],
        'status': 'Sent',
        'subject': subject
    })
    sent_count += 1
    
except Exception as e:
    # Structured error capture and logging
    notification_log.append({
        'project_id': project['Project_ID'],
        'review_id': review['Review_ID'],
        'status': 'Failed',
        'reason': str(e)
    })
    failed_count += 1

This implementation demonstrates several aspects of corrective maintenance that Thales (n.d.) emphasizes.

  1. It provides error containment by preventing exceptions from cascading through the system. When an email notification fails—perhaps due to network connectivity issues, authentication problems, or invalid recipient addresses—the exception is caught locally rather than propagating upward to crash the entire notification process. This directly addresses Thales’ observation that faults can have “widespread impact on the functionality” if not properly contained.

  2. It implements structured error documentation through the notification_log data structure. Rather than simply logging generic error messages, the system captures contextual information including project and review identifiers alongside the specific error message. This approach supports what Thales describes as the crucial ability to “recognize and take care of faults,” providing maintenance personnel with the information needed to diagnose and resolve issues systematically.

  3. The implementation demonstrates operational resilience by continuing processing after errors. The code increments failed_count but continues execution, allowing the system to process subsequent notifications even when some fail. Thales emphasizes addressing faults “as quickly as possible” by preventing individual failures from blocking overall system operation.

  4. The error handling mechanism creates feedback pathways that enable what Thales identifies as a competitive advantage: when “a company can recognize and take care of faults before users discover them.” The notification_log structure aggregates error data that can be analyzed to identify patterns requiring proactive corrective maintenance before they affect end users.

Most importantly, this implementation acknowledges the reality Thales describes—that software will inevitably experience faults—while minimizing the operational impact of those faults. The approach is the fundamental goal of corrective maintenance: to preserve system functionality in the face of unexpected errors while providing clear pathways for systematic fault resolution. By implementing these principles throughout critical system components, the Project Review Scheduler demonstrates an approach to error management that supports ongoing system reliability and maintainability.

Configuration Management

The Project Review Scheduler implements a configuration management approach through command-line argument parsing, representing effective software maintenance as described by Bennett (2024). This technique creates a separation between core logic and runtime parameters, enabling the system to adapt to diverse operational requirements without source code modifications. The implementation constructs a parameter dictionary at runtime through systematic parsing of command-line inputs, normalizing arguments by converting format variations (like hyphens to underscores), and handling both value parameters and flag parameters appropriately. This architectural decision is described by Bennett’s (2024) definition of configuration management as “a process to systematically manage, organize, and control changes” throughout the software lifecycle. By externalizing configuration choices, the system achieves several maintenance advantages:

  • it reduces the technical debt associated with environment-specific code branches
  • it simplifies deployment across development, testing, and production environments
  • it facilitates admin-level customization without developer intervention
  • it creates clear boundaries between stable core functionality and variable operational parameters.

The parameter parsing mechanism is a practical expression of Bennett’s (2024) configuration identification principle, establishing well-defined interfaces through which the system can be configured while maintaining internal coherence and stability across diverse deployment scenarios.

def parse_args(args):
    parsed = {}
    if not args:
        parsed["command"] = "help"
        return parsed
    parsed["command"] = args[0]
    for i in range(1, len(args)):
        if args[i].startswith("--"):
            key = args[i][2:].replace("-", "_")
            if i + 1 < len(args) and not args[i + 1].startswith("--"):
                parsed[key] = args[i + 1]
            else:
                parsed[key] = True
    return parsed

The command-line argument parsing mechanism is a critical aspect of software configuration management, allowing the system to adapt to different environments and requirements without modifying source code. Bennett describes SCM as “a process to systematically manage, organize, and control the changes in the documents, codes, and other entities during the Software Development Life Cycle,” with a primary goal of increasing productivity while minimizing mistakes. This fundamental principle manifests in the Project Review Scheduler through implementation strategies outlined in Bennett’s (2024) discussion of the Software Configuration Management Plan (SCMP), which “defines the types of documents to be managed and document naming.” The parsing function standardizes how configuration parameters are named, normalized (converting hyphens to underscores), and processed, creating a consistent interface between external commands and internal processing that conforms to formal configuration management practices.

Through this standardized approach, the Project Review Scheduler achieves flexibility that enables diverse deployment scenarios without requiring code modification. For instance, the same codebase can generate different report types (monthly, workload, overdue, or all) by simply changing command-line arguments. Similarly, notification behaviors can be filtered by status or directed to different SMTP servers without altering the core notification logic. These capabilities directly demonstrate what Bennett (2024) calls “accommodating changes in user requirement, policy, budget, schedule” - a primary reason for implementing SCM and a key benefit realized through the Project Review Scheduler’s command-line configuration system.

Referential Integrity Checks

The Project Review Scheduler incorporates multi-layered referential integrity validation that extends beyond simple data verification into relationship enforcement between interdependent entities. This validation framework implements what Bennett (2024) defines as “configuration audits and reviews,” which serve the dual purpose of verifying compliance with established configuration control standards and ensuring consistent traceability throughout the development process. The system’s validate_referential_integrity() function traverses the three primary CSV data stores—Projects, Users, and Reviews—to establish a verifiable web of cross-references that preserves data consistency. During validation, the function constructs fast-lookup hash sets of primary keys (project_ids and user_ids) and systematically verifies that every foreign key reference in the Reviews table points to an existing record, detecting orphaned references that could compromise system reliability:

def validate_referential_integrity():
    """
    Validate referential integrity between CSV files.
    
    Returns:
        dict: Validation result with 'valid' flag and list of 'errors'
    """
    projects = get_all_projects()
    users = get_all_users()
    reviews = get_all_reviews()
    
    errors = []
    
    # Create sets of IDs for faster lookup
    project_ids = {p.get('Project_ID') for p in projects}
    user_ids = {u.get('User_ID') for u in users}
    
    # Check Reviews reference valid Projects and Users
    for i, review in enumerate(reviews, start=2):  # Start from 2 to account for header row
        project_id = review.get('Project_ID')
        if project_id not in project_ids:
            errors.append({
                'row': i,
                'field': 'Project_ID',
                'message': f"Review references Project_ID: {project_id} which does not exist"
            })
        
        reviewer_id = review.get('Reviewer_ID')
        if reviewer_id not in user_ids:
            errors.append({
                'row': i,
                'field': 'Reviewer_ID',
                'message': f"Review references Reviewer_ID: {reviewer_id} which does not exist"
            })
    
    return {
        'valid': len(errors) == 0,
        'errors': errors
    }

The validation function employs several technical approaches to ensure data integrity.

  1. Set-based existence checking provides O(1) lookup complexity instead of O(n) iterative comparison for each reference validation, improving performance with larger datasets.
  2. Structured error objects preserve row context, field identification, and human-readable messaging, enabling precise identification and correction of integrity issues.
  3. The enumeration offset beginning at 2 accounts for CSV header rows when reporting error positions, providing accurate line references in error messages.

These design choices implement Bennett’s (2024) principle that “configuration status accounting tracks each release during the SCM process” by maintaining cross-entity consistency throughout data updates. The function’s composite result structure contains both a validity indicator and detailed error information, supporting both status checks and troubleshooting. Enforcing referential constraints prevents data corruption scenarios where orphaned records or invalid references might compromise reporting accuracy, reviewer assignment validity, or notification delivery—establishing data validation as an essential component of system reliability and maintainability.

The Project Review Scheduler balances practical constraints with established software engineering principles. By employing phased deployment with dual interfaces, the system’s gradual adoption minimizes user disruption while maximizing availability across different user preferences and technical capabilities. The automated backup system creates versioned data states that enable risk-free experimentation and immediate recovery from data corruption incidents (Bennett, 2024). These deployment strategies work in concert with file management and data validation to create a foundation for the system’s operation.

The maintenance techniques implemented in the Project Review Scheduler complement these deployment strategies by establishing sustainable patterns for long-term system evolution. The comprehensive documentation approach follows Brown’s (2025) assertion that documentation serves as “one of the most important parts of a software project,” creating both a knowledge repository and a framework for future development. Modular design principles facilitate targeted maintenance by isolating functional concerns into discrete components that can be independently maintained and tested. The structured error-handling methodology implements what Thales (n.d.) describes as corrective maintenance that “addresses faults and errors in a targeted manner to minimize disruption.”

Together, these deployment strategies and maintenance techniques form an integrated approach to software engineering that prioritizes reliability, maintainability, and adaptability. The configuration management methods and referential integrity validation establish boundaries and relationships between system components, reducing the likelihood of failures and enabling more efficient troubleshooting when issues arise. As Sumo Logic (n.d.) emphasizes, effective preparation and testing phases are necessary for the deployment process, and the Project Review Scheduler’s implementation exemplifies these principles through its systematic approach to deployment and ongoing maintenance.

2. Effectiveness of Strategies Used

Most Effective Deployment Strategy: Safe Deployment with Backups

The safe deployment with automated backups proved to be the most effective deployment strategy implemented in the Project Review Scheduler. This approach created a safety net that enabled development and experimentation while protecting against data loss. As Sumo Logic (n.d.) emphasizes, the preparation phase of deployment should include safeguarding resources before making changes, and this strategy directly implemented that principle.

The effectiveness of this strategy was demonstrated in several instances during development. When testing the reviewer assignment algorithm with real data, accidental corruption of the Projects.csv file occurred during a load balancing test. The repository contains multiple backup files (such as Projects.csv.20250515_202732.bak) that demonstrate this functionality in action. The backup system enabled immediate restoration to a previously known good state without permanent data loss, as implemented in the following function:

def backup_file(file_path):
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    backup_path = f"{file_path}.{timestamp}.bak"
    with open(file_path, 'r') as src, open(backup_path, 'w') as dst:
        dst.write(src.read())
    print(f" Backed up {file_path} → {backup_path}")

This function is a building block for the safe deployment strategy, creating timestamped backups that function as what Bennett (2024) describes as “formally accepted versions of software configuration items.” The timestamp-based naming convention creates a clear version history, supporting configuration accounting principles.

Modular design principles are implemented int the reporting module, where discrete functions handle specific report types with well-defined inputs and outputs. This architectural approach proved invaluable when requirements evolved during development as the system’s modular structure allowed for seamless addition of this feature without disrupting existing functionality. The new requirement was implemented as a standalone function:

def generate_department_statistics(output_file=None):
    """
    Generate a report showing statistics grouped by department.
    
    Args:
        output_file (str, optional): Path to output file. If None, uses default naming.
        
    Returns:
        dict: Report generation results
    """
    # Read data using existing functions
    projects = get_all_projects()
    reviews = get_all_reviews()
    
    # Group projects by department
    departments = {}
    for project in projects:
        dept = project.get('Department', 'Unknown')
        # ... processing logic ...

This new function integrated with the existing system without requiring modifications to other components, demonstrating what Thales (n.d.) refers to as “perfective software maintenance” that “adds new features without disrupting existing functionality.”

The modular design also helped resolve bugs. When an issue was discovered in the date calculation logic that affected review frequency interpretation, the fix could be isolated to the calculate_due_date function without risking modifications to other system components. This highlights what Thales (n.d.) terms “corrective software maintenance,” which addresses faults in a targeted manner.

Bennett (2024) emphasizes that configuration management helps “control the costs involved in making changes to a system,” and the modular design directly contributed to this goal by reducing the effort required for both enhancements and corrections. By clearly delineating component boundaries and responsibilities, the system maintained its overall integrity even as individual modules evolved, making it more resilient to the maintenance challenges that typically consume “60-80% of the total software lifecycle cost” (Thales, n.d.).

The deployment strategies and maintenance techniques implemented in the Project Review Scheduler demonstrate how thoughtful software engineering practices contribute to system reliability, adaptability, and longevity. Safe deployment with automated backups establishes a foundation of resilience that protects against data corruption and enables experimentation, while modular design creates clear boundaries between functional components that simplify both enhancement and correction activities. Together, these approaches form an integrated methodology that addresses both initial deployment concerns and long-term maintenance requirements.

Reflections on Software Deployment and Maintenance

Throughout this capstone project, I have unearthed that effective software deployment and maintenance embody a philosophy of sustainability that extends beyond individual code blocks or feature implementations. The strategies I employed while crafting the Project Review Scheduler have influenced and revolutionized my approach to software engineering.

The automated backup system I implemented represents a proactive approach to deployment safety, creating versioned data states that could protect against potential data corruption. While this capstone project did not encounter catastrophic failures requiring restoration, incorporating this safety mechanism aligns with Bennett’s (2024) emphasis on configuration management as a fundamental element of responsible software engineering.

Similarly, my modular architecture established clear functional boundaries between system components. This approach to organization creates theoretical benefits for future maintenance and enhancement, as changes can be isolated to specific modules without affecting the entire system. These principles of component isolation reflect industry best practices, even though the project’s limited scope and timeline did not require extensive system evolution.

The documentation was a learning exercise and a framework for code organization. As Brown (2025) notes, comprehensive documentation provides a knowledge foundation that supports both current development and future maintenance activities. This practice of explicit knowledge capture represents an essential skill applicable across all future development work.

The configuration management system implemented through command-line argument parsing demonstrates how external parameters can be separated from core logic. This practical application of Bennett’s (2024) principles enhances flexibility without compromising reliability, allowing systems to adapt to different environments without modifying source code.

These deployment and maintenance strategies have broader implications beyond this specific academic project. The balance between technical sophistication and practical maintainability is critical for all software development. By studying and implementing these principles, I have gained insight into architectural decisions that influence a system’s long-term sustainability.

In the larger context of software engineering, this project reinforces what Thales (n.d.) identifies as a fundamental reality: maintenance constitutes an essential lifecycle component that typically consumes “60-80% of total software lifecycle cost.” I have developed a more holistic understanding of sustainable software development by understanding how deployment safeguards and maintenance facilitators work in practice.

As software grows in complexity and importance, these thoughtful deployment and maintenance principles will become more critical. Through this capstone experience, I have gained technical implementation skills and a deeper appreciation for the architectural decisions that enable systems to remain adaptable in the face of changing requirements.

References

Bennett, L. (2024, August 13). Software Configuration Management in Software Engineering. Www.guru99.com. https://www.guru99.com/software-configuration-management-tutorial.html

Bierds, B., Gibson, J., Hasznos, S., Backman, D., Hungate, C., Ransom, M., Lawrence, C., Byers, R., Zuliani, F., & Brown, C. P. (2004). The Software Deployment Mystery - Solved. IBM.

Sumo Logic. (n.d.). Discover what software deployment is | definition and overview. Sumo Logic. https://www.sumologic.com/glossary/software-development

Thales. (n.d.). The 4 Types of Software Maintenance-What is Software Maintenance. Cpl.thalesgroup.com. https://cpl.thalesgroup.com/software-monetization/four-types-of-software-maintenance