1. 긴 함수 개념 정의
1-1) 짧은 함수 vs 긴 함수
1-2) 사용할 수 있는 리팩토링 기술
99%는 “함수 추출하기"로 해결할 수 있다.
함수로 분리하면서 해당 함수로 전달해야 할 매개변수가 많아진다면 다음과 같은 리팩토링을 고려함.
조건문 분해하기(Decompose Conditional)를 사용해 조건문을 분리할 수 있다.
같은 조건으로 여러개의 Swtich문이 있다면
“조건문을 다형성으로 바꾸기(Replace Conditional with Polymorphism)”를 사용할 수 있다.
반목문 안에서 여러 작업을 하고 있어 하나의 메소드로 추출하기 어렵다면
“반복문 쪼개기(Split Loop)”를 적용할 수 있다.
2. 임시 변수를 질의 함수로 바꾸기
2-1) 개념
변수를 사용하면 반복해서 동일한 식을 계산하는 것을 피할 수 있고,
이름을 사용해 의미를 표현할 수도 있다.
긴 함수를 리팩토링할 때 그러한 임시 변수를 함수로 추출해 분리한다면
빼낸 함수로 전달해야 할 매개변수를 줄일 수 있다.
해결 방법
2-2) 리팩토링 전
2-2)-1. class StudyDashboard
public class StudyDashboard {
public static void main(String[] args) throws IOException,
InterruptedException {
StudyDashboard studyDashboard = new StudyDashboard();
studyDashboard.print();
}
private void print() throws IOException, InterruptedException {
GitHub gitHub = GitHub.connect();
GHRepository repository = gitHub
.getRepository("whiteship/live-study");
List<Participant> participants = new CopyOnWriteArrayList<>();
int totalNumberOfEvents = 15;
ExecutorService service = Executors.newFixedThreadPool(8);
CountDownLatch latch = new CountDownLatch(totalNumberOfEvents);
for (int index = 1 ; index <= totalNumberOfEvents ; index++) {
int eventId = index;
service.execute(new Runnable() {
@Override
public void run() {
try {
GHIssue issue = repository.getIssue(eventId);
List<GHIssueComment> comments = issue.getComments();
for (GHIssueComment comment : comments) {
String username = comment.getUserName();
boolean isNewUser = participants.stream().noneMatch(
p -> p.username().equals(username)
);
Participant participant = null;
if (isNewUser) {
participant = new Participant(username);
participants.add(participant);
} else {
participant = participants.stream()
.filter(
p -> p.username().equals(username)
).findFirst().orElseThrow();
}
participant.setHomeworkDone(eventId);
}
latch.countDown();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
});
}
latch.await();
service.shutdown();
// markdownprint(마트다운으로 출력하는 부분)
try (FileWriter fileWriter = new FileWriter("participants.md");
PrintWriter writer = new PrintWriter(fileWriter)) {
participants.sort(Comparator.comparing(Participant::username));
writer.print(header(totalNumberOfEvents, participants.size()));
participants.forEach(p -> {
// RateCount(참여율 계산식)
long count = p.homework().values().stream()
.filter(v -> v == true)
.count();
// Rete(참여율)
double rate = count * 100 / totalNumberOfEvents;
// Markdown
String markdownForHomework =
String.format("| %s %s | %.2f%% |\\n", p.username(),
checkMark(p, totalNumberOfEvents), rate);
writer.print(markdownForHomework);
});
}
}
}
2-2)-2. private void print()
이미지
2-3) 리팩토링 후
2-3)-1. class StudyDashboard
public class StudyDashboard {
public static void main(String[] args) throws IOException,
InterruptedException {
StudyDashboard studyDashboard = new StudyDashboard();
studyDashboard.print();
}
private void print() throws IOException, InterruptedException {
GitHub gitHub = GitHub.connect();
GHRepository repository = gitHub
.getRepository("whiteship/live-study");
List<Participant> participants = new CopyOnWriteArrayList<>();
int totalNumberOfEvents = 15;
ExecutorService service = Executors.newFixedThreadPool(8);
CountDownLatch latch = new CountDownLatch(totalNumberOfEvents);
for (int index = 1 ; index <= totalNumberOfEvents ; index++) {
int eventId = index;
service.execute(new Runnable() {
@Override
public void run() {
try {
GHIssue issue = repository.getIssue(eventId);
List<GHIssueComment> comments = issue.getComments();
for (GHIssueComment comment : comments) {
String username = comment.getUserName();
boolean isNewUser = participants.stream().noneMatch(
p -> p.username().equals(username)
);
Participant participant = null;
if (isNewUser) {
participant = new Participant(username);
participants.add(participant);
} else {
participant = participants.stream()
.filter(
p -> p.username().equals(username)
).findFirst().orElseThrow();
}
participant.setHomeworkDone(eventId);
}
latch.countDown();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
});
}
latch.await();
service.shutdown();
try (FileWriter fileWriter = new FileWriter("participants.md");
PrintWriter writer = new PrintWriter(fileWriter)) {
participants.sort(Comparator.comparing(Participant::username));
writer.print(header(totalNumberOfEvents, participants.size()));
participants.forEach(p -> {
double rate = getRate(totalNumberOfEvents, p);
String markdownForHomework =
getMarkdownForParticipant(totalNumberOfEvents, p, rate);
writer.print(markdownForHomework);
});
}
}
// Query Function
private double getRate(int totalNumberOfEvents, Participant p) {
// RateCount
long count = p.homework().values().stream()
.filter(v -> v == true)
.count();
// Rate
double rate = count * 100 / totalNumberOfEvents;
return rate;
}
// ParticipantMarkdown
private String getMarkdownForParticipant(int totalNumberOfEvents,
Participant p, double rate) {
String markdownForHomework =
String.format("| %s %s | %.2f%% |\\n", p.username(),
checkMark(p, totalNumberOfEvents), rate);
return markdownForHomework;
}
}
2-3)-2. private void print()
이미지-1
여기서 한 가지 문제가 생김. 빨간 BOX에 있는 MarkdownForParticipant
메소드의 3개 파라미터 중 rate를 없애 리팩토링하고 싶을 때
getRate(totalNumberOfEvents, p)를 MarkdownForParticipant 메소드의
파라미터로 받는 걸로 해결하기
이미지-2
QueryFunction으로 빼냈을 때 파라티머를 줄일 수 있는 장점이 있음.
코드
public class StudyDashboard {
public static void main(String[] args) throws IOException,
InterruptedException {
StudyDashboard studyDashboard = new StudyDashboard();
studyDashboard.print();
}
private void print() throws IOException, InterruptedException {
GitHub gitHub = GitHub.connect();
GHRepository repository = gitHub
.getRepository("whiteship/live-study");
List<Participant> participants = new CopyOnWriteArrayList<>();
int totalNumberOfEvents = 15;
ExecutorService service = Executors.newFixedThreadPool(8);
CountDownLatch latch = new CountDownLatch(totalNumberOfEvents);
for (int index = 1 ; index <= totalNumberOfEvents ; index++) {
int eventId = index;
service.execute(new Runnable() {
@Override
public void run() {
try {
GHIssue issue = repository.getIssue(eventId);
List<GHIssueComment> comments = issue.getComments();
for (GHIssueComment comment : comments) {
String username = comment.getUserName();
boolean isNewUser = participants.stream().noneMatch(
p -> p.username().equals(username)
);
Participant participant = null;
if (isNewUser) {
participant = new Participant(username);
participants.add(participant);
} else {
participant = participants.stream()
.filter(
p -> p.username().equals(username)
).findFirst().orElseThrow();
}
participant.setHomeworkDone(eventId);
}
latch.countDown();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
});
}
latch.await();
service.shutdown();
try (FileWriter fileWriter = new FileWriter("participants.md");
PrintWriter writer = new PrintWriter(fileWriter)) {
participants.sort(Comparator.comparing(Participant::username));
writer.print(header(totalNumberOfEvents, participants.size()));
participants.forEach(p -> {
String markdownForHomework =
getMarkdownForParticipant(totalNumberOfEvents, p);
writer.print(markdownForHomework);
});
}
}
// Query Function(계산식이 있는 함수)
private double getRate(int totalNumberOfEvents, Participant p) {
// RateCount
long count = p.homework().values().stream()
.filter(v -> v == true)
.count();
// Rate
double rate = count * 100 / totalNumberOfEvents;
return rate;
}
// MarkdownForParticipant
private String getMarkdownForParticipant(int totalNumberOfEvents,
Participant p) {
return String.format("| %s %s | %.2f%% |\\n", p.username(),
checkMark(p, totalNumberOfEvents),
getRate(totalNumberOfEvents, p));
}
}
3. 매개변수 객체 만들기
3-1) 개념
3-2) 리팩토링 전
3-2)-1. private void print()
public class StudyDashboard {
public static void main(String[] args) throws IOException,
InterruptedException {
StudyDashboard studyDashboard = new StudyDashboard();
studyDashboard.print();
}
private void print() throws IOException, InterruptedException {
GitHub gitHub = GitHub.connect();
GHRepository repository = gitHub
.getRepository("whiteship/live-study");
List<Participant> participants = new CopyOnWriteArrayList<>();
int totalNumberOfEvents = 15;
ExecutorService service = Executors.newFixedThreadPool(8);
CountDownLatch latch = new CountDownLatch(totalNumberOfEvents);
for (int index = 1 ; index <= totalNumberOfEvents ; index++) {
int eventId = index;
service.execute(new Runnable() {
@Override
public void run() {
try {
GHIssue issue = repository.getIssue(eventId);
List<GHIssueComment> comments = issue.getComments();
for (GHIssueComment comment : comments) {
String username = comment.getUserName();
boolean isNewUser = participants.stream()
.noneMatch(
p -> p.username().equals(username)
);
Participant participant = null;
if (isNewUser) {
participant = new Participant(username);
participants.add(participant);
} else {
participant = participants.stream()
.filter(
p -> p.username().equals(username)
).findFirst().orElseThrow();
}
participant.setHomeworkDone(eventId);
}
latch.countDown();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
});
}
latch.await();
service.shutdown();
try (FileWriter fileWriter = new FileWriter("participants.md");
PrintWriter writer = new PrintWriter(fileWriter)) {
participants.sort(Comparator.comparing(Participant::username));
writer.print(header(totalNumberOfEvents, participants.size()));
participants.forEach(p -> {
String markdownForHomework =
getMarkdownForParticipant(totalNumberOfEvents, p);
writer.print(markdownForHomework);
});
}
}
private double getRate(int totalNumberOfEvents, Participant p) {
long count = p.homework().values().stream()
.filter(v -> v == true)
.count();
double rate = count * 100 / totalNumberOfEvents;
return rate;
}
private String getMarkdownForParticipant(int totalNumberOfEvents,
Participant p) {
return String.format(
"| %s %s | %.2f%% |\\n", p.username(),
checkMark(p, totalNumberOfEvents),
getRate(totalNumberOfEvents, p)
);
}
}
이미지
하는 방법
3-3) 리팩토링 후
public class StudyDashboard {
public static void main(String[] args) throws IOException,
InterruptedException {
StudyDashboard studyDashboard = new StudyDashboard();
studyDashboard.print();
}
private void print() throws IOException, InterruptedException {
GitHub gitHub = GitHub.connect();
GHRepository repository = gitHub
.getRepository("whiteship/live-study");
List<Participant> participants = new CopyOnWriteArrayList<>();
int totalNumberOfEvents = 15;
ExecutorService service = Executors.newFixedThreadPool(8);
CountDownLatch latch = new CountDownLatch(totalNumberOfEvents);
for (int index = 1 ; index <= totalNumberOfEvents ; index++) {
int eventId = index;
service.execute(new Runnable() {
@Override
public void run() {
try {
GHIssue issue = repository.getIssue(eventId);
List<GHIssueComment> comments = issue.getComments();
for (GHIssueComment comment : comments) {
String username = comment.getUserName();
boolean isNewUser = participants.stream()
.noneMatch(
p -> p.username().equals(username)
);
Participant participant = null;
if (isNewUser) {
participant = new Participant(username);
participants.add(participant);
} else {
participant = participants.stream()
.filter(
p -> p.username().equals(username)
).findFirst().orElseThrow();
}
participant.setHomeworkDone(eventId);
}
latch.countDown();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
});
}
latch.await();
service.shutdown();
try (FileWriter fileWriter = new FileWriter("participants.md");
PrintWriter writer = new PrintWriter(fileWriter)) {
participants.sort(Comparator.comparing(Participant::username));
writer.print(header(totalNumberOfEvents, participants.size()));
participants.forEach(p -> {
String markdownForHomework =
getMarkdownForParticipant(totalNumberOfEvents, p);
writer.print(markdownForHomework);
});
}
}
private double getRate(int totalNumberOfEvents, Participant p) {
long count = p.homework().values().stream()
.filter(v -> v == true)
.count();
double rate = count * 100 / totalNumberOfEvents;
return rate;
}
// Introduce Parameter Object
private double getRate(ParticipantPrinter participantPrinter) {
long count = participantPrinter.getP().homework().values().stream()
.filter(v -> v == true)
.count();
double rate = count * 100 / participantPrinter
.getTotalNumberOfEvents();
return rate;
}
private String getMarkdownForParticipant(int totalNumberOfEvents,
Participant p) {
return String.format(
"| %s %s | %.2f%% |\\n", p.username(),
checkMark(p, totalNumberOfEvents),
getRate(totalNumberOfEvents, p)
);
}
}
이미지
4. 필드 변수로 빼서 하는 방법
5. 객체 통째로 넘기기