Overview of Pair Programming Session
This session focused on collaborative software development practices using Java. The primary objective was to implement two distinct modules involving file input/output operrations and arithmetic logic, while adhering to the Extreme Programming (XP) methodology of pair programming. The process involved mutual code review, collaborative coding, and role rotation between Driver and Navigator.
Phase 1: Mutual Code Review and Testing
Before collaborative coding began, each partner independently executed the other's initial implementation of the assigned modules. This peer review phase highlighted several areas for improvement:
- Module 1 (Data Management): The initial implementation met core requirements but lacked robustness in file parsing mechanisms. Specific edge cases regarding delimiter handling were identified and subsequently refined.
- Module 2 (Arithmetic Logic): Basic functionality was present, but floating-point precision was mishandled during division operations. The original logic relied on integer arithmetic for division, leading to accuracy isssues which were corrected to support real number calculations.
The review process proved beneficial for identifying blind spots in individual coding styles and improving overall code readability.
Phase 2: Collaborative Implementation - Data Management Module
The first collaborative task involved building a system to manage personal records stored in a text file. The system required features such as sorting, age-based queries, and location filtering.
Role Assignment: One partner acted as the Navigator, focusing on code review, unit test coverage, and refactoring opportunities. The other partner served as the Driver, handling the actual implementation and design documentation.
import java.io.*;
import java.util.*;
public class PersonDirectory {
private static List<PersonRecord> registry = new ArrayList<>();
public static void main(String[] args) {
loadDatabase("records.txt");
runMenu();
}
private static void loadDatabase(String filePath) {
File source = new File(filePath);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(source)))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.trim().split("\\s+");
if (parts.length >= 4) {
PersonRecord person = new PersonRecord();
person.setName(parts[0]);
person.setId(parts[1]);
person.setGender(parts[2]);
person.setAge(Integer.parseInt(parts[3]));
// Remaining parts assumed to be location data
StringBuilder location = new StringBuilder();
for (int i = 4; i < parts.length; i++) {
location.append(parts[i]).append(" ");
}
person.setLocation(location.toString().trim());
registry.add(person);
}
}
} catch (IOException e) {
System.err.println("Error loading database: " + e.getMessage());
}
}
private static void runMenu() {
Scanner scanner = new Scanner(System.in);
boolean active = true;
while (active) {
System.out.println("\n--- Directory Menu ---");
System.out.println("1. Sort by Name");
System.out.println("2. Find Oldest");
System.out.println("3. Find Youngest");
System.out.println("4. Find Peers by Age");
System.out.println("5. Search by Location");
System.out.println("6. Exit");
int choice = scanner.nextInt();
switch (choice) {
case 1:
registry.sort(Comparator.comparing(PersonRecord::getName));
System.out.println(registry);
break;
case 2:
Optional<PersonRecord> oldest = registry.stream()
.max(Comparator.comparingInt(PersonRecord::getAge));
oldest.ifPresent(p -> System.out.println("Oldest: " + p));
break;
case 3:
Optional<PersonRecord> youngest = registry.stream()
.min(Comparator.comparingInt(PersonRecord::getAge));
youngest.ifPresent(p -> System.out.println("Youngest: " + p));
break;
case 4:
System.out.print("Enter your age: ");
int inputAge = scanner.nextInt();
List<PersonRecord> peers = findClosestAge(inputAge);
peers.forEach(System.out::println);
break;
case 5:
System.out.print("Enter province: ");
String region = scanner.next();
for (PersonRecord p : registry) {
if (p.getLocation().contains(region)) {
System.out.println("Match found: " + p);
}
}
break;
case 6:
active = false;
System.out.println("Session terminated.");
break;
default:
System.out.println("Invalid selection.");
}
}
}
private static List<PersonRecord> findClosestAge(int targetAge) {
List<PersonRecord> result = new ArrayList<>();
int minDiff = Integer.MAX_VALUE;
for (PersonRecord p : registry) {
int diff = Math.abs(p.getAge() - targetAge);
if (diff < minDiff) {
minDiff = diff;
result.clear();
result.add(p);
} else if (diff == minDiff) {
result.add(p);
}
}
return result;
}
static class PersonRecord implements Comparable<PersonRecord> {
private String name;
private String id;
private String gender;
private int age;
private String location;
// Getters and Setters omitted for brevity
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getLocation() { return location; }
public void setLocation(String location) { this.location = location; }
@Override
public int compareTo(PersonRecord o) {
return this.name.compareTo(o.name);
}
@Override
public String toString() {
return String.format("%s (%s, Age: %d, Loc: %s)", name, id, age, location);
}
}
}
Phase 3: Collaborative Implementation - Arithmetic Quiz Module
The second task involved creating an automated arithmetic quiz that generates random problems, validates user input, and logs results to a file. Special attention was paid to handling floating-point precision correctly.
Role Assignment: Roles were swapped for this module. The previous Driver became the Navigator, overseeing logic flow and error handling, while the previous Navigator took over coding duties.
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Random;
import java.util.Scanner;
public class MathQuiz {
public static void main(String[] args) {
String logFile = "quiz_results.txt";
int score = 0;
int totalQuestions = 10;
try (PrintWriter logger = new PrintWriter(new FileOutputStream(logFile));
Scanner scanner = new Scanner(System.in)) {
System.out.println("Welcome to the Arithmetic Challenge");
System.out.println("Answers should be rounded to 2 decimal places.");
Random rand = new Random();
for (int i = 1; i <= totalQuestions; i++) {
int operand1 = rand.nextInt(101);
int operand2 = rand.nextInt(101);
int operation = rand.nextInt(4); // 0:+, 1:-, 2:*, 3:/
double correctAnswer = 0;
String operatorSymbol = "";
switch (operation) {
case 0:
correctAnswer = operand1 + operand2;
operatorSymbol = "+";
break;
case 1:
correctAnswer = operand1 - operand2;
operatorSymbol = "-";
break;
case 2:
correctAnswer = operand1 * operand2;
operatorSymbol = "*";
break;
case 3:
if (operand2 == 0) {
operand2 = 1; // Prevent division by zero
}
correctAnswer = (double) operand1 / operand2;
operatorSymbol = "/";
break;
}
System.out.printf("Question %d: %d %s %d = ", i, operand1, operatorSymbol, operand2);
double userAnswer = scanner.nextDouble();
// Format to 2 decimal places for comparison
BigDecimal correctBD = BigDecimal.valueOf(correctAnswer).setScale(2, RoundingMode.HALF_UP);
BigDecimal userBD = BigDecimal.valueOf(userAnswer).setScale(2, RoundingMode.HALF_UP);
if (userBD.compareTo(correctBD) == 0) {
score += 10;
System.out.println("Correct!");
} else {
System.out.println("Incorrect. Correct answer: " + correctBD);
}
logger.printf("Q%d: %d %s %d = %s (User: %s)%n",
i, operand1, operatorSymbol, operand2, correctBD, userBD);
}
System.out.println("Final Score: " + score);
logger.println("Final Score: " + score);
} catch (IOException e) {
System.err.println("Failed to write to log file.");
}
}
}
Reflections on Methodology
Throughout the development cycle, the separation of concerns between the Driver and Naviagtor provided distinct advantages. When acting as the Navigator, the ability to observe the code being written in real-time allowed for immediate identification of logical flaws and style inconsistencies without interrupting the flow excessively. This role facilitated deeper thinking about architectural decisions and test coverage.
Conversely, the Driver role benefited from the continuous feedback loop, reducing the time spent on debugging post-implementation. The collaborative environment encouraged knowledge transfer regarding specific Java APIs, such as BigDecimal for precision and streamlined file handling with try-with-resources. Disagreements on implementation details were resolved through discussion, leading to consensus on the most robust solutions.