실무에서 알게 된 Java 프로그래밍 모범 사례 및 패턴 규칙 내용을 별도로 정리 해야겠다는 생각이 들어 글을 작성 하게 되었다.
1. 데이터를 조회하고 꺼내오는 Java 함수명 네이밍 규칙, getUserInfo VS findUserInfo
get prefix는 주로 cache, 인메모리에 저장되어 있는 데이터 등 코드 레벨과 아주 가깝고 밀접한 레벨에서의 데이터를 꺼내오거나 조회 할 때 사용하고, find 의 경우 Database, 외부 api 등을 통해 데이터를 꺼내오거나 조회 할때 prefix 로 사용 한다. get과 find 가 프로젝트에서 혼용되는 케이스가 다분한데 실제 데이터를 꺼내올때의 level 로 구분을 지어두고 사용하면 함수 prefix 네이밍만으로도 최적화 되어 있는 함수인지, 아닌지를 쉽게 구분 할 수 있다.
2. 함수명에 Valid 단어가 포함 되어 있다면, 내부 로직에 실제로 valid 처리가 되는 코드가 있어야 한다.
// X
public boolean findValidUserListByUserIds(List<String> userIds){
// 단순 외부 api 호출만 있고, 내부적으로 valid 를 해주는 로직이 없다면 함수명에 valid 단어를 제거 해야한다.
UserInfoListResp resp = userApiQueryRepo.findUserInfoList(userIds);
return resp.getUserInfoList();
}
// O
public boolean findUserListByUserIds(List<String> userIds){
UserInfoListResp resp = userApiQueryRepo.findUserInfoList(userIds);
return resp.getUserInfoList();
}
호출 하는 외부 API 서버 내부 로직에 valid 해주는 로직과 기능이 있다 해도 실제 작성자가 작성한 함수 내부에 Validation 로직이 위치하는 것이 아니기 때문에 코드가 담고 있는 의미의 함수명으로 정의 하는 것이 올바르다.
3. 객체를 생성할때에 무분별하게 또는 의미 없이 .set() 을 남발 하지 말자.
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String userName;
private String country;
private Integer age;
}
// O
public void createUser(String userName, String country, int age){
User user = new User(userName, country, age);
userRepository.insert();
}
// X
public void createUser(String userName, String country, int age){
User user = new User();
user.setUserName(userName);
user.setCountry(country);
user.setAge(age);
userRepository.insert();
}
생성자를 통해 충분히 객체를 구성하는데 어려움이 없어보이고, 오히려 코드의 양과 가독성 측면에서 불완전해보이는 구조로 보여질 확율이 높아 생성자 Level 에서 객체를 구성하는 방식이 보기가 좋고 완전해 보인다. 추가로 생성자를 통한 객체 생성이 부담스러운 상황이 있다면 객체 내부에 static 함수 builder() 또는 of() 와 같은 함수를 활용하여 static 함수 내부에서 객체를 생성하여 사용 하는 것도 일반 적이다.
4. Response를 해줄때 단일 List<>에 여러개의 타입이 들어가야할 경우 List<Map<String, Object>>사용을 지양해라.
// Object = Student || Teacher
public List<Map<String, Object>> findStudentOrTeacherList(){
// do somthing
};
Java 프로그래밍에서 단일 List 내부에 2개 이상의 객체 타입이 return 또는 response 되어야 할때 흔히 Map 타입을 사용하여 dynamic 한 타입의 객체를 표현 해주고자 하는 경우가 많은데, 이는 내부 로직을 확인 하지 않으면 실제로 어떤 타입으로 return 이 될지 알 수 없는 블랙박스 영역이 생기게 되기 마련이다.
public class StudentOrTeacher {
private String name;
private Integer age;
private String className;
...
private String ...;
}
public List<StudentOrTeacher> findStudentOrTeacherList(){
// do somthing
};
위 코드와 같이 Student 및 Teacher 의 데이터 모두 컨트롤 할 수 있는 융합 객체를 구성하여 사용하는 것이 바람직하다. 이때 합쳐진 객체의 이름은 식별하기 쉽거나 또는 여러 데이터의 조합으로 이루어진 객체라는 것을 의미 하는 네이밍으로 가져가는 것이 좋다.
5. put 은 실제 데이터를 입력하는 의미로 간주 될 수 있으니 List 내부에 데이터를 추가하는 작업이라는 의미의 사용을 지양해야한다.
putToUserListByStudentList(); // X
makeToUserListByStudentList(); // O
특정 리스트에 또는 실질적인 IO 작업이 일어나는 것이 아니라면 put 이라는 키워드 사용을 지양하는 것이 좋다. 현재 몸담고 있는 업계에서의 put 은 실제 데이터를 넣어주는 작업으로 이해하고 있는 사람들이 대부분이다. 보다 가벼운 워딩인 make 를 주로 사용 하도록 하자.
Self Working Level Effective Java | 실무에서 사용하는 Java 프로그래밍 1~5번 마무리를 하며
실무에서 사용하고 있는 Java 프로그래밍 패턴과 규칙 5가지를 기록 해보았다. 정말 사소한 부분이지만 약속이 되지 않은 상태로 프로젝트 개발이 진행 될 경우 용어의 오해가 충분히 일어 날 수 있는 부분들로 보여진다.
업계마다 작게는 프로젝트 마다 정의하고 약속한 내용들이 다르겠지만 큰 규모의 프로젝트를 진행하기 전 미리 합을 맞춰 놓으면 보다 일관된 코드를 작성하게 됨으로 여러 작업자들 간에 이해가 좀 더 깊어 질 수 있다.