Activity ‐ Writing SOLID Java Code - accentient/github-copilot-devs GitHub Wiki

Writing SOLID Java Code

Objective

This activity introduces Java developers to GitHub Copilot while building a simple Unit Converter application. The activity demonstrates how Copilot assists in generating code, providing suggestions, and reducing development time. By the end of the activity, students will:

  • Understand how to integrate and use GitHub Copilot in VS Code or IntelliJ
  • Experience generating Java code snippets with Copilot
  • Build and test a Unit Converter application using Copilot-generated code
  • Learn how to refine Copilot suggestions through comments and prompts

SOLID is a set of five principles for designing clean, maintainable, and scalable object-oriented software. They help developers write flexible and robust code that’s easier to extend and maintain.

  • S (Single Responsibility): A class should have one reason to change
  • O (Open/Closed): Code should be open for extension, closed for modification
  • L (Liskov Substitution): Subtypes must work seamlessly in place of their base types
  • I (Interface Segregation): Interfaces should have only necessary methods
  • D (Dependency Inversion): Depend on abstractions, not concrete implementations

Project

Use GitHub Copilot to identify potential violations of SOLID principles in Java code, analyze their impact on code quality and maintainability, and provide actionable suggestions to refactor the code for improved adherence to SOLID design principles.

Prerequisites

  • Java Development Kit (JDK) installed
  • VS Code or IntelliJ IDEA with GitHub Copilot enabled
  • Active GitHub Copilot subscription

Steps

Step 1: Project setup

  • Create a new Java project
  • Open or add Main.java and replace it with the following code
public class Main {
    public static void main(String[] args) {
        System.out.println("Demonstrating SOLID Principle Violations:");

        // SRP Violation
        SingleResponsibilityViolation employee = new SingleResponsibilityViolation();
        employee.generateReport();

        // OCP Violation
        OpenClosedViolation calculator = new OpenClosedViolation();
        System.out.println("Addition Result: " + calculator.calculate(2, 3, "add"));

        // LSP Violation
        LiskovSubstitutionViolation rectangle = new Square();
        rectangle.setHeight(5);
        rectangle.setWidth(10);
        System.out.println("LSP Violation Area: " + rectangle.getArea());

        // ISP Violation
        InterfaceSegregationViolation multifunctionDevice = new InterfaceSegregationViolation();
        multifunctionDevice.print();
        multifunctionDevice.scan();
        multifunctionDevice.fax();

        // DIP Violation
        DependencyInversionViolation violation = new DependencyInversionViolation();
        violation.startEngine();
    }

    // ----- SRP VIOLATION -----
    // Class does too many things: handles employee data and generates reports.
    private static class SingleResponsibilityViolation {
        private String name;
        private double salary;

        public void calculateSalary() {
            System.out.println("Calculating salary...");
        }

        public void generateReport() {
            System.out.println("Generating employee report...");
        }
    }

    // ----- OCP VIOLATION -----
    // Violates Open-Closed Principle because modifying logic requires changing the class.
    private static class OpenClosedViolation {
        public int calculate(int a, int b, String operation) {
            if (operation.equals("add")) {
                return a + b;
            } else if (operation.equals("subtract")) {
                return a - b;
            }
            throw new UnsupportedOperationException("Operation not supported");
        }
    }

    // ----- LSP VIOLATION -----
    // Square breaks the behavior expected from Rectangle.
    private static class LiskovSubstitutionViolation {
        protected int width;
        protected int height;

        public void setWidth(int width) {
            this.width = width;
        }

        public void setHeight(int height) {
            this.height = height;
        }

        public int getArea() {
            return width * height;
        }
    }

    private static class Square extends LiskovSubstitutionViolation {
        @Override
        public void setWidth(int width) {
            this.width = width;
            this.height = width;
        }

        @Override
        public void setHeight(int height) {
            this.height = height;
            this.width = height;
        }
    }

    // ----- ISP VIOLATION -----
    // Interface forces the class to implement unnecessary methods.
    private interface Machine {
        void print();

        void scan();

        void fax();
    }

    private static class InterfaceSegregationViolation implements Machine {
        public void print() {
            System.out.println("Printing...");
        }

        public void scan() {
            System.out.println("Scanning...");
        }

        public void fax() {
            System.out.println("Faxing...");
        }
    }

    // ----- DIP VIOLATION -----
    // High-level class directly depends on a low-level concrete class.
    private static class Engine {
        public void start() {
            System.out.println("Engine starting...");
        }
    }

    private static class DependencyInversionViolation {
        private Engine engine = new Engine();

        public void startEngine() {
            engine.start();
        }
    }
}
  • Build and run the app

Step 2: Ask GitHub Copilot's Opinion of This Code

  • Open the GitHub Copilot Chat
Is this code SOLID?
  • Review the responses for each of the principles

Step 3: Address the Single Responsibility Principle

  • Open the GitHub Copilot Chat
Make this code follow the Single Responsibility principle
  • Make the appropriate updates, ensuring the app still builds

Step 4: Address the remaining SOLID Principles

  • Open the GitHub Copilot Chat
Make this code SOLID
  • Make the appropriate updates, ensuring the app still builds

Step 5: Ask GitHub Copilot's Opinion of the New Code

  • Open the GitHub Copilot Chat
Is this code SOLID?
  • Review the responses, and make any improvements if you want

Summary

In this hands-on activity, participants built a unit converter application in Java using GitHub Copilot as an AI coding assistant. Through guided prompts, they learned to integrate Copilot into their development workflow, generated code for length, temperature, and weight conversions, wrote JUnit tests, and refined AI-generated suggestions, gaining practical experience in accelerating software development with AI tools.