[TIL] [2024.10.30] Clean Code
김동진
4 min read
💡
QUIZ 01.
// 본인이 가장 잘하는 언어로(JS, Python 등등) 더러운 코드를 깨끗한 코드로
// 리팩토링하는 예시를 만들어보세요. 현재 파일은 JS 로 되어있지만. 자유롭게 다른 언어로 변경해주세요.
// 원칙 1.
단일책임의 원칙
// Before 😣
public class DBConnectionManager {
private Queue<DBConnectionManager> connectionPool = new LinkedList<>();
private int MAX_POOL_SIZE;
private boolean connected = false;
public DBConnectionManager(int poolSize) {
this.MAX_POOL_SIZE = poolSize;
initializeConnections();
}
public PooledDataSource(int poolSize) {
this.MAX_POOL_SIZE = poolSize;
initialize();
}
private void initialize() {
for (int i = 0; i < MAX_POOL_SIZE; i++) {
connectionPool.offer(new BasicDBConnection());
}
}
public void connect(){
if(!connected){
connected = true;
}
}
public void disconnect() {
if (connected) {
connected = false;
}
}
public boolean isConnected() {
return connected;
}
public DBConnection getConnection() {
connect();
return connectionPool.poll();
}
public void releaseConnection(DBConnection connection) {
if (connection != null && connectionPool.size() < MAX_POOL_SIZE) {
connectionPool.offer(connection);
}
}
}
// 무엇을 고치려고 하는지, 고치려는 문제가 무엇인지 알려주세요.
커넥션 풀 관리와 개별 커넥션 관리를 DBConnectionManager 에서 모두 담당하고 있다.
// After 😎
// DBConnection.java
public interface DBConnection {
void connect();
void disconnect();
boolean isConnected();
}
public interface DataSource {
DBConnection getConnection();
void releaseConnection(DBConnection connection);
}
public class DefaultDBConnection implements DBConnection {
private boolean connected = false;
@Override
public void connect() {
if (!connected) {
System.out.println("Connecting to the database...");
connected = true;
}
}
@Override
public void disconnect() {
if (connected) {
System.out.println("Disconnecting from the database...");
connected = false;
}
}
@Override
public boolean isConnected() {
return connected;
}
}
public class PooledDataSource implements DataSource {
private final Queue<DBConnection> connectionPool = new LinkedList<>();
private final int MAX_POOL_SIZE;
public PooledDataSource(int poolSize) {
this.MAX_POOL_SIZE = poolSize;
initialize();
}
private void initialize() {
for (int i = 0; i < MAX_POOL_SIZE; i++) {
connectionPool.offer(new DefaultDBConnection());
}
}
@Override
public DBConnection getConnection() {
return connectionPool.poll();
}
@Override
public void releaseConnection(DBConnection connection) {
if (connection != null && connectionPool.size() < MAX_POOL_SIZE) {
connectionPool.offer(connection);
}
}
}
// 어떻게 고쳤는지, 사례에서 무엇을 배워야 하는지 설명해주세요.
개별 커넥션과 커넥션 풀 관리 기능을 분리하고
각각의 책임을 나누어 코드 수정 시 다른 기능에도 영향을 미치지 않도록 격리 함.
💡
QUIZ 02.
// 본인이 가장 잘하는 언어로(JS, Python 등등) 더러운 코드를 깨끗한 코드로
// 리팩토링하는 예시를 만들어보세요. 현재 파일은 JS 로 되어있지만. 자유롭게 다른 언어로 변경해주세요.
// 원칙 2.
예외를 사용하라
// Before 😣
public class UserService {
private Map<Integer, String> users = Map.of(
1, "Alice",
2, "Bob"
);
public String findUserById(int userId) {
return users.get(userId);
}
}
// 무엇을 고치려고 하는지, 고치려는 문제가 무엇인지 알려주세요.
예외가 발생할 수 있는 상황에서 아무런 조치 없이 값을 반환하고 있다.
// After 😎
public class ApplicationException extends RuntimeException {
public ApplicationException(String message) {
super(message);
}
public ApplicationException(String message, Throwable cause) {
super(message, cause);
}
}
public class UserService {
private Map<Integer, String> users = Map.of(
1, "Alice",
2, "Bob"
);
public String findUserById(int userId) {
if (!users.containsKey(userId)) {
throw new ApplicationException("해당 유저를 찾지 못했습니다: " + userId + "번 유저");
}
return users.get(userId);
}
}
// 어떻게 고쳤는지, 사례에서 무엇을 배워야 하는지 설명해주세요.
확장성을 고려하여 CustomException(사용자 정의 예외)를 사용하여 정의하고,
예외가 발생할 수 있는 상황을 고려하여 예외 처리하며 에러 메시지를 함께 던진다.
💡
QUIZ 03.
// 본인이 가장 잘하는 언어로(JS, Python 등등) 더러운 코드를 깨끗한 코드로
// 리팩토링하는 예시를 만들어보세요. 현재 파일은 JS 로 되어있지만. 자유롭게 다른 언어로 변경해주세요.
// 원칙 3.
디미터 법칙
// Before 😣
public class Customer {
private Address address;
public Customer(Address address) {
this.address = address;
}
public Address getAddress() {
return address;
}
}
public class Address {
private String city;
public Address(String city) {
this.city = city;
}
public String getCity() {
return city;
}
}
public class Order {
private Customer customer;
public Order(Customer customer) {
this.customer = customer;
}
public void printCustomerCity() {
System.out.println("Customer city: " + customer.getAddress().getCity());
}
}
// 무엇을 고치려고 하는지, 고치려는 문제가 무엇인지 알려주세요.
결합도가 높아 Customer의 구조가 변경되면 Order도 함께 변경되어야 하며,
Customer의 내부 구조가 노출되고 있다.
// After 😎
public class Customer {
private Address address;
public Customer(Address address) {
this.address = address;
}
public String getCity() {
return address.getCity();
}
}
public class Address {
private String city;
public Address(String city) {
this.city = city;
}
public String getCity() {
return city;
}
}
public class Order {
private Customer customer;
public Order(Customer customer) {
this.customer = customer;
}
public void printCustomerCity() {
System.out.println("Customer city: " + customer.getCity());
}
}
// 어떻게 고쳤는지, 사례에서 무엇을 배워야 하는지 설명해주세요.
디미터 법칙을 적용함으로써 Customer의 구조가 바뀌어도
Customer가 city를 제공하므로 Order가 변경될 필요가 없어
결합도가 낮아지고 유지보수성이 높아진다.
0
Subscribe to my newsletter
Read articles from 김동진 directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by