프로젝트를 진행하는 중의 팀원들과의 소통입니다.
팀원들과 소통을 하면서도 막히는 부분들이 꽤 있었는데
같은 단어를 사용하면서도 다르게 이해를 하는 부분이 있었고
반대로 다른 단어를 사용하고 있었는데 알고 보니 같은 말을 하고 있는 경우도 있었습니다.
서로의 생각이 다르다보니
같은 생각을 같은 말로 하는 것이 중요하다는 것을 느꼈습니다.
회의를 진행할 때도, 무조건 모여서 진행을 하는 것보다는
각자가 조사할 주제를 정하고
그것에 대해서 모여서 의견을 나누는 방식이 더 좋았습니다.
서로 발언할 기회도 많아지고, 회의에 대한 이해도도 더욱 높아졌습니다.
ER Diagram 을 구성해봤습니다.
초반에는 기준을 명확히 잡지 못해서 많은 시행 착오가 있었습니다.
처음에 SR Requirement 를 작성할 때
페이지 기준으로 작성을 하면서 요구사항이 뒤죽박죽이 되었는데,
Schema 를 작성하면서, 어떤 점이 잘못되었는지 알게 되며
점점 DB의 구체적인 형태가 잡혀갔습니다.
'애플리케이션의 구체적인 기능'을 파악하지 못한 상태로 DB Schema 를 짠다는 것이
엄청 어려운 일이라는 것을 새삼 느꼈습니다.
프로젝트를 진행하면서, 정말 깊이 있게 아는 것들이 없다는 것을 느꼈습니다.
Schema 라는 것이 JDBC 에서만 사용하는 DB의 틀이라고 생각하고 있었는데
DB의 모든 것은 이쪽에서 나오는 것이라고 느꼈습니다.
Schema를 이용해서 DB의 틀을 만들고,
Flyway 를 이용하여 버전관리를 하면서 스키마를 다루는 방법을 새롭게 배웠습니다.
Spring Data JPA 를 이용하면서, 양방향 매핑의 중요성을 다시 한번 느꼈습니다.
class Studygroup extends Auditable {
...
/**
* <h2>양방향 매핑을 위한 메서드</h2>
* 기존 연결을 끊고, 새로 관계를 연결한다.<br>
* <font color="white"><b>양방향 매핑 시 순환참조 가능성이 있으므로,
* 반대쪽에서 사용하면 절대 안됨</b></color="white"><br>
* 참고: {@link Studygroup#setLeaderMemberOneWay(Member)}
* @param leaderMember 양방향 매핑을 위한 객체
*/
public void setLeaderMember(Member leaderMember) {
if (leaderMember == null) {
throw new IllegalArgumentException("Leader Member cannot be null");
}
if(this.leaderMember != null) {
this.leaderMember.getStudygroupsAsLeader().remove(this);
}
this.leaderMember = leaderMember;
this.leaderMember.getStudygroupsAsLeader().add(this);
}
/**
* <h2>양방향 매핑 중 순환 방지용으로 단방향으로만 추가하는 메서드</h2>
* @param leaderMember 관계를 끊는 경우 null 가능
*/
public void setLeaderMemberOneWay(Member leaderMember) {
this.leaderMember = leaderMember;
}
...
}
class Member extends Auditable {
...
@OneToMany(mappedBy = "leaderMember", cascade = {PERSIST, MERGE}, fetch = LAZY)
private List<Studygroup> studygroupsAsLeader = new ArrayList<>();
/**
* <h2>양방향 매핑을 위한 One To Many 쪽의 Setter 설정</h2>
* 기존에 연결되어있던 관계를 끊고, 양쪽 객체를 새로 연결해준다.
* @param studygroupsAsLeader 새로 매핑할 객체의 리스트( 시간표 )
*/
public void setStudygroupsAsLeader(List<Studygroup> studygroupsAsLeader) {
if (studygroupsAsLeader == null) {
throw new IllegalArgumentException("studygroup As Leader List cannot be null");
}
if (this.studygroupsAsLeader != null) {
for (Studygroup studygroup : this.studygroupsAsLeader) {
studygroup.setLeaderMemberOneWay(null);
}
}
this.studygroupsAsLeader = studygroupsAsLeader;
for (Studygroup studygroup : this.studygroupsAsLeader) {
studygroup.setLeaderMemberOneWay(this);
}
}
...
}
안전한 양방향 객체 매핑을 통해
서비스 로직에서는 반대쪽의 연결에 대해 신경을 쓰지 않아도 되었기에
서비스 로직에 집중할 수 있어서 좋았습니다.
인터페이스를 이용한 소통이라는 것도 배웠습니다.
지금까지는 인터페이스에 대해서
공통점을 묶어서 추상화를 한다는 개념으로 막연하게 알고 있었는데
실제로 인터페이스를 이용해서 소통을 하려고 구현을 해보니
전혀 다른 방법으로 이용할 수 있다는 것을 배웠습니다.
public interface SearchTagManager {
/**
* <h2>key(카테고리)를 받아 해당 key 에 대한 value(태그)의 리스트를 반환해준다</h2>
* <s><font color="white"><b> 403 forbidden </b></font> 로그인을 하지 않은 경우</s><br>
* <font color="white"><b> 404 not found </b></font> 해당 key 에 대한 값이 하나도 존재하지 않을 경우<br>
* @param studygroupId 검색에 사용할 스터디 그룹의 식별자
* @return
*/
List<SearchTag> getList(Long studygroupId);
/**
* <h2>key(카테고리)를 받아 해당 key 에 대한 value(태그)의 리스트를 반환해준다</h2>
* <s><font color="white"><b> 403 forbidden </b></font> 로그인을 하지 않은 경우</s><br>
* <font color="white"><b> 404 not found </b></font> 해당 key 에 대한 값이 하나도 존재하지 않을 경우<br>
* @param key 검색에 사용할 key(카테고리)
* @return key(카테고리)에 해당하는 value(태그)의 목록 전부
*/
List<SearchTag> getList(String key);
/**
* <h2>모든 key(카테고리)와 value(태그)의 쌍을 리스트로 반환해준다</h2>
* <s><font color="white"><b> 403 forbidden </b></font> 로그인을 하지 않은 경우</s><br>
* <font color="white"><b> 404 not found </b></font> 해당 key 에 대한 값이 하나도 존재하지 않을 경우<br>
* @return key(카테고리)에 해당하는 value(태그)의 목록 전부
*/
List<SearchTag> getAllList();
...
}
1. 인터페이스를 이용해서 내가 구현하고자 하는 기능에 대해 설명하며 틀을 잡고
2. 팀원과 인터페이스의 구현 내용에 대해서 리뷰
3. 전체적으로 틀이 잡혔다면 구현
이런 식으로 진행을 하니
그 전까지 입/출력을 위해 고민해왔던 것들이 너무나도 쉽게 풀렸습니다.
Github을 이용하여 프로젝트를 하는 다양한 방법도 경험해봤습니다.
Github 의 Discussion 도 이용을 해보려고 노력했습니다.
프로젝트 진행 중 질문 사항이 나오거나,
아이디어가 떠오르면 과감히 물어보거나 공유하고
작업 내용이 생기면 Discussion → Issue 생성을 이용하여 작업으로 바로 전환합니다.
하나의 Issue 가 너무 커지면 Discussion 으로 전환을 하여
다시 세부적인 사항으로 Issue 를 생성하며 작업을 진행하였습니다.
이로 인해 누락되는 작업이 없이 진행이 가능하게 되었습니다.
Github 의 Projects 도 프로젝트에 이용해봤습니다.
Projects 를 이용하여 일정을 나누고
각각의 작업에 대하여 세부 일정을 정할 수 있었습니다.
전체적인 작업 시간을 분배하며 관리할 수 있어서 매우 편했습니다.
Pull Request 시 팀원이 다 함께 코드 리뷰를 진행하며 서로가 궁금한 코드에 대해서 의견을 주고받았습니다.
서로 모르는 부분에 대해서 질문하고, 답변을 하며 이해를 하고
잘못된 부분이나 개선이 필요한 부분에 대해서 피드백을 진행했습니다.
이로 인해 코드는 따로 구현하지만,
함께 만들어간다는 감각을 더욱 잘 느끼며
애플리케이션의 질이 높아지는 것을 느꼈습니다.
Actions 의 CI 기능을 이용하여, Build가 되지 않는 PR 이 Merge 되는 것을 방지하였습니다.
PR 을 할 때, Conflict 해결 후에 코드가 동작을 하지 않게 되는 상황을 방지할 수 있었습니다.
Push 하기 전에 개별적으로 테스트는 하지만,
충돌 해결 과정에서 발생할 수 있을 휴먼에러를 방지하기 위함이었습니다.
패키지를 나누는 기준에 대해서 한번 더 생각을 해보게 되었습니다.
패키지 관리를 통해
전체적인 틀에 대한 기준을 잡기가 조금 더 수월했던 것 같습니다.
Postman API 문서화 입니다.
문서화를 하는데 걸리는 시간이 Restdoc을 작성하는 것보다 빠르고,
실패에 대한 코드도 포함할 수 있었고,
실시간으로 요청에 대한 응답을 그대로 받으며
데이터를 문서에 반영하는 것도 Save 로 가능했습니다.
이로 인해 API 문서 업데이트가 기존보다 빨랐던 것 같습니다.