코드 메트릭 - 순환 복잡성 - Visual Studio (Windows)

코드를 복잡하게 만들면 안될까?에 답을 해준 문서

목표 스프레드시트

Untitled


구현 방식에 따른 차이가 존재할 수 있다.

하지만 기존 방식에 비해 간결하게 서비스를 구현할 수 있고,

수정, 변경, 삭제, 삽입 시에 일어날 수 있는 코드 수정이 data Model에 한정된다.

기존 코드 (8점)

기존코드 복잡성.png

celper 사용 코드 (3점)

celper 사용 복잡도.png

package service;

import dto.Student;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 현재 서비스 부분에 POI 사용으로 인한 코드가 너무 많아짐
 *
 * 여기코드에서 추가해야하는 사항
 * 1. 스타일 설정 로직
 * 2. Cell에 대한 null 및 type 검증 로직
 * 3. 기본 값 설정 로직
 *
 * 즉, 하나의 내보내기 기능을 위해 아래의 로직들이 모두 필요함
 * 또한 컬럼의 순서가 변경 되거나 특정서비스 마다 제외해야하는 컬럼이 존재할 경우
 * 하드 코딩된 부분을 수정해야함
 */
public class OriginalExcelService {
    private String[] header = {"이름", "주소", "나이", "연락처",
                    "생년월일", "성별", "군필여부", "학적",
                    "국적", "전공", "학번", "학년", "학점",
                    "취업여부", "기숙사신청", "장애 학생", "val1",
                    "val2", "val3", "val4", "val5",
                    "val6", "val7", "val8", "val9",
                    "val10", "val11", "val12", "val13", "val14"};

    public Workbook load(List<Student> model) {
        Workbook workbook = new XSSFWorkbook();
        // 엑셀 오브젝트 내에 시트 생성
        Sheet sheet = workbook.createSheet();
        setStudentSheetStyle(sheet);
        CellStyle studentDefaultCellStyle = createStudentDefaultCellStyle(workbook);

        // 헤더에 삽입
        int rowIndex = 0;
        Row headerRow = sheet.createRow(rowIndex++);
        for (int i = 0; i < header.length; i++) {
            Cell cell = headerRow.createCell(i);
            setHeaderStyle(workbook, studentDefaultCellStyle, cell, header[i]);
            cell.setCellValue(header[i]);
        }

        // 바디에 데이터 삽입
        for (Student student : model) {
            Row bodyRow = sheet.createRow(rowIndex++);
            for (int i = 0; i < header.length; i++) {
                setDataStyle(workbook, studentDefaultCellStyle, bodyRow.createCell(i), header[i]);
            }
            setValues(bodyRow, student);
        }
        return workbook;
    }
    // 값 세팅 및 스타일 세팅
    void setValues(Row row, Student student){
        row.getCell(0).setCellValue(student.getName());
        row.getCell(1).setCellValue(student.getAddress());
        row.getCell(2).setCellValue(student.getAge());
        row.getCell(3).setCellValue(student.getPhoneNumber());
        row.getCell(4).setCellValue(student.getDateBirth());
        row.getCell(5).setCellValue(student.getGender().toString());

        // 기본값 설정
        row.getCell(6).setCellValue(student.getMilitaryServiceStatus() == null ? "N" : student.getMilitaryServiceStatus());

        row.getCell(7).setCellValue(student.getSchoolRecordStatus().toString());
        row.getCell(8).setCellValue(student.getNationality());
        row.getCell(9).setCellValue(student.getMajor().toString());
        row.getCell(10).setCellValue(student.getStudentID());
        row.getCell(11).setCellValue(student.getSchoolYear());
        row.getCell(12).setCellValue(student.getGrade());
        row.getCell(13).setCellValue(student.getEmploymentStatus().toString());
        row.getCell(14).setCellValue(student.isDormitory());
        row.getCell(15).setCellValue(student.isStudentsDisabilities());
        row.getCell(16).setCellValue(student.getVal1());
        row.getCell(17).setCellValue(student.getVal2());
        row.getCell(18).setCellValue(student.getVal3());
        row.getCell(19).setCellValue(student.getVal4());
        row.getCell(20).setCellValue(student.getVal5());
        row.getCell(21).setCellValue(student.getVal6());
        row.getCell(22).setCellValue(student.getVal7());
        row.getCell(23).setCellValue(student.getVal8());
        row.getCell(24).setCellValue(student.getVal9());
        row.getCell(25).setCellValue(student.getVal10());
        row.getCell(26).setCellValue(student.getVal11());
        row.getCell(27).setCellValue(student.getVal12());
        row.getCell(28).setCellValue(student.getVal13());
        row.getCell(29).setCellValue(student.getVal14());
    }
    void setHeaderStyle(Workbook workbook, CellStyle defaultStyle, Cell cell, String curHeader){
        switch (curHeader){
            case "이름":
            case "국적":
                setEmphasizeCellStyle(workbook, defaultStyle, cell,createCellFormat(workbook,""));
                break;
            default:
                cell.setCellStyle(defaultStyle);
        }
    }
    void setDataStyle(Workbook workbook, CellStyle defaultStyle, Cell cell, String curHeader){
        Map<String, Short> cellFormatMap = createCellFormatMap(workbook);
        switch (curHeader){
            case "이름":
            case "학년":
                setEmphasizeCellStyle(workbook, defaultStyle, cell, cellFormatMap.get(curHeader) == null ? 0 : cellFormatMap.get(curHeader));
                break;
            default:
                CellStyle cellStyle = workbook.createCellStyle();
                cellStyle.cloneStyleFrom(defaultStyle);
                cellStyle.setDataFormat(cellFormatMap.get(curHeader) == null ? 0 : cellFormatMap.get(curHeader));
                cell.setCellStyle(cellStyle);
        }

    }
    // 스타일 만드는 부분
    void setStudentSheetStyle(Sheet sheet){
        sheet.setVerticallyCenter(true);
        sheet.setFitToPage(true);
        sheet.setDefaultRowHeight((short) 300);
        sheet.setDefaultColumnWidth(20);
    }
    CellStyle createStudentDefaultCellStyle(Workbook workbook){
        CellStyle defaultCellStyle = workbook.createCellStyle();
        
        Font defaultFont = workbook.createFont();
        defaultFont.setFontName("명조");
        defaultCellStyle.setFont(defaultFont);

        defaultCellStyle.setBorderTop(BorderStyle.THIN);
        defaultCellStyle.setBorderBottom(BorderStyle.THIN);
        defaultCellStyle.setBorderLeft(BorderStyle.THIN);
        defaultCellStyle.setBorderRight(BorderStyle.THIN);
        return defaultCellStyle;
    }
    void setEmphasizeCellStyle(Workbook workbook, CellStyle defaultCellStyle, Cell cell, short format){
        Font font = workbook.createFont();
        CellStyle cellStyle = workbook.createCellStyle();

        cellStyle.cloneStyleFrom(defaultCellStyle);

        cellStyle.setBorderTop(BorderStyle.DOUBLE);
        cellStyle.setBorderBottom(BorderStyle.DOUBLE);
        cellStyle.setBorderLeft(BorderStyle.DOUBLE);
        cellStyle.setBorderRight(BorderStyle.DOUBLE);

        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        cellStyle.setFillBackgroundColor(IndexedColors.YELLOW.getIndex());

        font.setFontName("굴림");
        font.setBold(true);

        cellStyle.setFont(font);
        cellStyle.setDataFormat(format);

        cell.setCellStyle(cellStyle);
    }
    Map<String, Short> createCellFormatMap(Workbook workbook){
        Map<String, Short> map = new HashMap<>();
        map.put("이름", createCellFormat(workbook, "@ 학생"));
        map.put("주소", createCellFormat(workbook, "@ (행정코드)"));
        map.put("나이", createCellFormat(workbook, "# 세 (만)"));
        map.put("연락처", createCellFormat(workbook, "@ - @ - @"));
        map.put("국적", createCellFormat(workbook, "# - 국가 코드"));
        return map;
    }
    short createCellFormat(Workbook workbook, String format){
        DataFormat dataFormat = workbook.createDataFormat();
        return dataFormat.getFormat(format);
    }
}
package dto;

import domain.*;
import java.time.LocalDate;

@lombok.Builder
@lombok.NoArgsConstructor
@lombok.AllArgsConstructor
@lombok.Getter
public class Student {
    private String name;
    private String address;
    private int age;
    private String phoneNumber;
    private LocalDate dateBirth;
    private Gender gender;
    private String militaryServiceStatus;
    private ClassificationSchoolRecord schoolRecordStatus;
    private int nationality;
    private Major major;
    private String studentID;
    private int schoolYear;
    private double grade;
    private EmploymentStatus employmentStatus;
    private boolean isDormitory;
    private boolean isStudentsDisabilities;

    // 필드 생성을 위해서
    private int val1;
    private int val2;
    private int val3;
    private int val4;
    private int val5;
    private int val6;
    private int val7;
    private int val8;
    private int val9;
    private int val10;
    private int val11;
    private int val12;
    private int val13;
    private int val14;
}
package service;

import dto.Student;
import org.celper.core.ExcelWorkBook;
import org.celper.type.WorkBookType;

import java.util.List;

public class ExcelService {

    public ExcelWorkBook load(List<Student> model){
        ExcelWorkBook excelWorkBook = new ExcelWorkBook(WorkBookType.XSSF);
        excelWorkBook.createSheet().modelToSheet(model);
        return excelWorkBook;
    }

}
package dto;

import domain.*;

import org.celper.annotations.*;
import org.celper.type.BuiltinCellFormatType;
import style.EmphasizeCellStyle;
import style.StudentSheetStyle;

import java.time.LocalDate;

@lombok.Builder
@lombok.NoArgsConstructor
@lombok.AllArgsConstructor
@lombok.Getter
@SheetStyle(StudentSheetStyle.class)
public class Student {

    @Column("이름")
    @CellFormat(customFormat = "@ 학생")
    @ColumnStyle(dataAreaStyle = EmphasizeCellStyle.class, headerAreaStyle = EmphasizeCellStyle.class)
    private String name;

    @Column("주소")
    @CellFormat(customFormat = "@ (행정코드)")
    private String address;

    @Column("나이")
    @CellFormat(customFormat = "# 세 (만)")
    private int age;

    @Column("연락처")
    @CellFormat(customFormat = "@ - @ - @")
    private String phoneNumber;

    @Column("생년월일")
    @CellFormat(builtinFormat = BuiltinCellFormatType.SIMPLE_DATE)
    private LocalDate dateBirth;

    @Column("성별")
    private Gender gender;

    @Column("군필여부")
    @DefaultValue("N")
    private String militaryServiceStatus;

    @Column("학적")
    private ClassificationSchoolRecord schoolRecordStatus;

    @Column("국적")
    @CellFormat(customFormat = "# - 국가 코드")
    @ColumnStyle(headerAreaStyle = EmphasizeCellStyle.class)
    private int nationality;

    @Column("전공")
    private Major major;

    @Column("학번")
    private String studentID;

    @Column("학년")
    @ColumnStyle(dataAreaStyle = EmphasizeCellStyle.class)
    private int schoolYear;

    @Column("학점")
    private double grade;

    @Column("취업여부")
    private EmploymentStatus employmentStatus;

    @Column("기숙사신청")
    private boolean isDormitory;

    @Column("장애 학생")
    private boolean isStudentsDisabilities;

    // 필드 생성을 위해서
    @Column("val1")
    private int val1;
    @Column("val2")
    private int val2;
    @Column("val3")
    private int val3;
    @Column("val4")
    private int val4;
    @Column("val5")
    private int val5;
    @Column("val6")
    private int val6;
    @Column("val7")
    private int val7;
    @Column("val8")
    private int val8;
    @Column("val9")
    private int val9;
    @Column("val10")
    private int val10;
    @Column("val11")
    private int val11;
    @Column("val12")
    private int val12;
    @Column("val13")
    private int val13;
    @Column("val14")
    private int val14;
}