프로젝트의 규모가 커지면서 점점 파일이 쌓여가고 있다. 복잡한 디렉토리 구조가 거슬리때 쯤
https://cheese10yun.github.io/spring-guide-directory/ 이 글을 보게됐다.
src/
└── main/
└── java/
└── com/
└── example/
└── myapp/
├── config/
│ └── SecurityConfig.java
├── controller/
│ ├── MemberController.java
│ └── GameController.java
├── service/
│ ├── MemberService.java
│ └── GameService.java
├── repository/
│ ├── MemberRepository.java
│ └── GameRepository.java
├── model/
│ ├── Member.java
│ └── Game.java
├── dto/
│ ├── MemberDto.java
│ └── GameDto.java
└── Application.java
src/
└── main/
└── java/
└── com/
└── example/
└── reactmapping/
├── domain/
│ ├── member/
│ │ ├── controller/
│ │ │ └── MemberController.java
│ │ ├── service/
│ │ │ └── MemberService.java
│ │ ├── repository/
│ │ │ └── MemberRepository.java
│ │ └── dto/
│ │ └── MemberDto.java
│ ├── game/
│ │ ├── controller/
│ │ │ └── GameController.java
│ │ ├── service/
│ │ │ └── GameService.java
│ │ └── repository/
│ │ └── GameRepository.java
│ └── ...
├── config/
│ └── SecurityConfig.java
├── exception/
│ └── GlobalExceptionHandler.java
└── Application.java
현재 내 구조는 계층형이다.
이렇게 보면 별 문제 없어 보이는데
Service는 service대로 쭉 나열되어 있으니까 원하는 service에 찾아가는게 힘들다.
프로젝트 규모가 작을 때는 오히려 계층형이 더 편하다. 하지만 규모가 커질 수록 파일이 많아지는데 service에 접근했더니 20개의 service가 나열된다면 굉장히 보기 싫을 것이다.
훨씬 깔끔하다.
@Service
@Transactional
@RequiredArgsConstructor
public class ImageCreateService {
@Value("${cloud.aws.s3.bucket}")
private String bucket;
private final S3Config s3Config;
private static final String EMPTY_STRING = "";
public String createImg(MultipartFile file) throws IOException {
if (isFilenameEmpty(file)) {
return null;
}
String fileExtension = extractFileExtension(file.getOriginalFilename());
String uuid = generateUUID();
File localFile = createTemporaryFile(file, uuid, fileExtension);
uploadFileToS3(uuid, fileExtension, localFile);
return generateFileUrl(uuid, fileExtension);
}
private boolean isFilenameEmpty(MultipartFile file) {
return Objects.equals(file.getOriginalFilename(), EMPTY_STRING);
}
private String extractFileExtension(String filename) {
return filename.substring(filename.lastIndexOf("."));
}
private String generateUUID() {
return String.valueOf(UUID.randomUUID());
}
private File createTemporaryFile(MultipartFile file, String uuid, String fileExtension) throws IOException {
File localFile = File.createTempFile(uuid, fileExtension);
try (InputStream inputStream = file.getInputStream()) {
FileUtils.copyInputStreamToFile(inputStream, localFile);
}
return localFile;
}
private void uploadFileToS3(String uuid, String fileExtension, File file) {
s3Config.amazonS3Client().putObject(new PutObjectRequest(bucket, uuid + fileExtension, file)
.withCannedAcl(CannedAccessControlList.PublicRead));
}
private String generateFileUrl(String uuid, String fileExtension) {
return s3Config.amazonS3Client().getUrl(bucket, uuid + fileExtension).toString();
}
}
createImage() 하나의 메소드를 리펙토링 한건데 이렇게 많은 메서드들이 생겼다. image 관련 로직을 imageService에 모조리 담아 리펙토링 하면 몇 백줄로 늘어날 것이고, image 기능별로 service를 나누면 service 디렉토리에 무수히 많은 service들이 생길 것이다.
즉 도메인 형식으로 바꾸면
이렇게 마음놓고 늘릴 수 있다.