오봉이와 함께하는 개발 블로그
CleanCode - 형식 맞추기 본문
형식 맞추기
코드 형식을 맞추는 행위는 중요하다. 코드 형식은 가독성을 높이는데 있어 매우 중요하다 생각한다. 우리는 대부분 팀으로 일하기 때문에 팀 내부에서 약속을 정하고 모두 그 규칙에 따르는 등 형식을 맞춰야 같이 일하는데 잡음이 발생할 확률이 적다.
형식을 맞추는 목적
구현한 코드의 가독성은 앞으로 바뀔 코드의 품질에 지대한 영향을 미친다.
오랜 시간이 지나 원래 코드의 흔적을 더 이상 찾아보기 어려울 정도로 코드가 바뀌어도 맨 처음 잡아놓은 구현 스타일과 가독성 수준은 유지보수 용이성과 확장성에 계속 영향을 미친다.
원래 코드는 사라질지라도 개발자의 스타일과 규율은 사라지지 않는다.
책에서 저자는 위와 같이 말한다. 내가 아무리 설명하는 것 보다 위 세 문장으로 정리하는 것이 더 효과적이라 판단하여 더 이상 설명하지 않겠다.
적절한 행 길이를 유지하라.
대규모 오픈소스 프로그램에서 .java 파일의 평균 길이는 200이다. 평균 200 라인으로 작성해도 대규모 오픈소스 프로그램을 충분히 작성할 수 있다.
엄격하게 지켜야 하는 규칙이라기보단, 가능하면 지킬 규칙으로 보라 한다.
내가 생각해도 긴 파일보단 짧은 파일이 실제로 더 읽기 편하고, 심적으로도 압박이 덜 할 거 같다.
개념은 빈 행으로 분리하라.
혹시 이 글을 읽는 사람 중 변수 선언, 생성자, 함수 등 한 클래스 파일 안에서 작성할 수 있는 행위에 빈 칸을 추가하지 않고 작성하는 사람이 있다면 반성하길 바란다.
public class UserService {
private final UserJpaRepository userJpaRepository;
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final AuthenticationManagerBuilder authenticationManagerBuilder;
private final TokenProvider tokenProvider;
public void join(UserDto.SignUpUserDto userDto) {
validateDuplicationId(userDto.getAccount());
userDto.setPassword(passwordEncoder.encode(userDto.getPassword()));
userRepository.save(User.signUpUser(userDto));
}
public TokenDto login(UserDto.LoginUserDto userDto) {
List<UserDto.LogonUserDto> findUsers = userJpaRepository.findByAccount(userDto.getAccount());
validateNotExistsUser(findUsers);
UserDto.LogonUserDto logonUserDto = findUsers.get(0);
validatePasswordMatch(userDto.getPassword(), logonUserDto.getPassword());
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
userDto.getAccount(), userDto.getPassword());
Authentication authentication = authenticationManagerBuilder.getObject()
.authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
return tokenProvider.createToken(authentication);
}
}
// ........................
public class UserService {
private final UserJpaRepository userJpaRepository;
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final AuthenticationManagerBuilder authenticationManagerBuilder;
private final TokenProvider tokenProvider;
public void join(UserDto.SignUpUserDto userDto) {
validateDuplicationId(userDto.getAccount());
userDto.setPassword(passwordEncoder.encode(userDto.getPassword()));
userRepository.save(User.signUpUser(userDto));
}
public TokenDto login(UserDto.LoginUserDto userDto) {
List<UserDto.LogonUserDto> findUsers = userJpaRepository.findByAccount(userDto.getAccount());
validateNotExistsUser(findUsers);
UserDto.LogonUserDto logonUserDto = findUsers.get(0);
validatePasswordMatch(userDto.getPassword(), logonUserDto.getPassword());
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
userDto.getAccount(), userDto.getPassword());
Authentication authentication = authenticationManagerBuilder.getObject()
.authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
return tokenProvider.createToken(authentication);
}
}
위와 아래 코드 중 어떤 것이 더 읽기 좋은가?
세로 밀집도
서로 연관된 개념끼리는 세로로 가까운 곳에 놓아야 가독성이 좋다
public class ReporterConfig {
/**
* 리포터 리스너의 클래스 이름
*/
private String m_className;
/**
* 리포터 리스너의 속성
*/
private List<Property> m_properties = new ArrayList<Property>();
public void addProperty(Property property) {
m_properties.add(property);
}
}
public class ReporterConfig {
private String m_className;
private List<Property> m_properties = new ArrayList<Property>();
public void addProperty(Property property) {
m_properties.add(property);
}
}
수직 거리
세로 밀집도와 유사하다.
함수 연관 관계와 동작 방식을 이해하기 위해 같은 파일 이곳 저곳 왔다갔다 뺑뺑이 돌면 상당히 힘든데, 다들 이런 경험이 있을 것으로 보인다.
서로 밀접한 개념은 가까이 두고 사용하자
책에서는 지역 변수 의 경우 사용하는 곳의 가장 가까운 곳에 선언하라 하는데, 개인적으로 맨 처음 선언하고 사용하는 것이 편해 이해되지 않지만, 이런 것은 개인적인 취향에 따라 정하면 좋을 거 같다.
인스턴스 변수 의 경우는 클래스의 최상단에 선언하는 것이 좋다고 하는데 나는 이에 동의한다.
종속 함수 의 경우 한 함수가 다른 함수를 호출한다면 특정 두 함수는 세로로 가까이 배치하는 것이 좋다. 또한 가능하면 호출하는 함수를 호출되는 함수보다 먼저 배치하라 하는데 이런 거 또한 따로 가르치지 않더라도 가독성을 높이는 방법을 생각해본 사람이라면 잘 하고 있다 생각한다. 나 또한 배우지 않아도 생각하다 보니 이런 방법을 적용하고 있었다.
개념적 유사성 개념적으로 유사한 함수(가령 유사한 동작을 하는 함수)면 서로 가까이 배치하라 한다.
가로 형식 맞추기
가로 형식도 중요하다. 코드를 읽다가 오른쪽으로 스크롤 하고 다시 돌아오기 위해 왼쪽으로 스크롤 하는 일이 자주 발생하는데 반복하면 매우 짜증이 난다. 책의 저자는 개인적으로 120자 정도를 추천한다.
내 개인적인 생각은 적당한 범위를 모르겠다. 당장 나만 해도 4k 모니터에 폰트를 작게 놓고 써서 어지간하면 한 눈에 들어온다.(실제로 다른 분들이 내 화면을 보면 이게 눈에 보이냐고 말씀하실 정도)
pycharm 같은 IDE를 사용하면 경고를 하기 때문에 적당한 값을 정해두고 플러그인을 설정하는 것이 좋아보인다.
들여쓰기 무시하기.
간단한 if, 짧은 while문 같은 경우에서 들여쓰기를 무시하고 싶은 유횩이 생길 수 있지만, 저자는 다시 초심으로 돌아가 들여쓰기를 작성한다 한다.
나 또한 절대 들여쓰기를 무시하지 않는다.
팀 규칙
개발자 개인마다 성향이 달라 선호하는 규칙이 있겠지만, 팀에 소속된 개발자라면 팀원 모두 합의한 규칙이 선호하는 규칙이 되어야 한다.
여러 규칙이 있겠지만, google 같은 곳에서 정한 컨벤션을 사용하는 것도 좋을 거 같다.
'이론' 카테고리의 다른 글
CleanCode - 오류 처리 (0) | 2024.01.03 |
---|---|
내 코드가 그렇게 이상한가요? - 컬렉션 : 중첩을 제거하는 구조화 테크닉 (0) | 2024.01.01 |
CleanCode - 주석 (1) | 2024.01.01 |
CleanCode - 함수 (1) | 2023.12.27 |
CleanCode - 의미있는 이름 (0) | 2023.12.26 |