728x90
반응형
SonarLint라는 툴이 권장하는 방향으로 코드 리팩토링을 하면서 리팩토링 규칙들을 기록하는 글입니다! 중복되는 규칙들은 한 번만 작성하였습니다.
💡 BuildingCustomRepositoryImpl
- 반복되는 문자열 리터럴을 상수로 정의하라
- private static final 키워드로 상수를 정의하여 코드에 반영했습니다.
- final vs static final
- final만 사용하면 해당 필드는 변경이 불가능하지만 클래스의 각 인스턴스마다 그 필드의 복사본이 생성됩니다. 이는 필요 이상으로 메모리를 사용하게 되므로, 특히 그 필드의 값이 모든 인스턴스에서 동일할 경우, 비효율적일 수 있습니다.
- static final을 사용하면 해당 필드는 클래스 레벨에서 한번만 초기화되며 모든 인스턴스에서 공유하게 됩니다. 따라서 메모리 사용량이 줄어들고 효율성이 향상됩니다.
// Noncompliant Code
if (!isEmpty(pageable.getSort())) {
for (Sort.Order order : pageable.getSort()) {
Order direction = order.getDirection().isAscending() ? Order.ASC : Order.DESC;
switch (order.getProperty()) {
case "id":
OrderSpecifier<?> orderId = QueryDslUtil.getSortedColumn(direction, building, "id");
ORDERS.add(orderId);
break;
case "reviewCnt":
OrderSpecifier<?> orderReviewCnt = QueryDslUtil.getSortedColumn(direction, building.buildingSummary, "reviewCnt");
ORDERS.add(orderReviewCnt);
break;
case "avgScore":
OrderSpecifier<?> orderScore = QueryDslUtil.getSortedColumn(direction, building.buildingSummary, "avgScore");
ORDERS.add(orderScore);
break;
default:
break;
}
}
} else {
OrderSpecifier<?> orderId = QueryDslUtil.getSortedColumn(Order.DESC, building, "id");
ORDERS.add(orderId);
}
// Compliant Solution
// 상수 정의
private static final String ID = "id";
private static final String REVIEW_CNT = "reviewCnt";
private static final String AVG_SCORE = "avgScore";
// 메소드내에 있는 로직 변경
if (!isEmpty(pageable.getSort())) {
for (Sort.Order order : pageable.getSort()) {
Order direction = order.getDirection().isAscending() ? Order.ASC : Order.DESC;
switch (order.getProperty()) {
case ID:
OrderSpecifier<?> orderId = QueryDslUtil.getSortedColumn(direction, building, ID);
ORDERS.add(orderId);
break;
case REVIEW_CNT:
OrderSpecifier<?> orderReviewCnt = QueryDslUtil.getSortedColumn(direction, building.buildingSummary, REVIEW_CNT);
ORDERS.add(orderReviewCnt);
break;
case AVG_SCORE:
OrderSpecifier<?> orderScore = QueryDslUtil.getSortedColumn(direction, building.buildingSummary, AVG_SCORE);
ORDERS.add(orderScore);
break;
default:
break;
}
}
} else {
OrderSpecifier<?> orderId = QueryDslUtil.getSortedColumn(Order.DESC, building, ID);
ORDERS.add(orderId);
}
- 제네릭을 사용할 때는 타입 매개변수를 명시적으로 제공하여라
- 로직에 의해 여러 타입이 들어갈 수 있어서 와일드카드를 써주었습니다.
- 설명
- 제네릭 타입을 사용하면 타입의 안전성을 컴파일 타임에 보장할 수 있습니다.
- 예를 들어, List과 같은 경우, 컴파일러는 이 리스트에 문자열만 추가할 수 있도록 검사합니다.
- 그러나 제네릭을 원시 타입으로 사용하면, 이런 타입 검사를 받지 않고 런타임에 오류가 발생할 수 있습니다.
// Noncompliant Code
public List<OrderSpecifier> getAllOrderSpecifiers(Pageable pageable) {
List<OrderSpecifier> ORDERS = new ArrayList<>();
...
return ORDERS;
}
// Compliant Solution
public List<OrderSpecifier<?>> getAllOrderSpecifiers(Pageable pageable) {
List<OrderSpecifier<?>> ORDERS = new ArrayList<>();
...
return ORDERS;
}
- 산술 피연산자는 변수에 할당전에 타입을 캐스트 해라
- 피연산자 1을 1L로 변경해주었습니다.
- 설명
- 예를 들어, 기본적으로, 정수 연산의 결과는 항상 정수입니다. 즉, 정수 간의 나눗셈을 수행하면, 그 결과는 소수점 이하를 버린 정수가 됩니다.
- 이를 float나 double에 할당하면, 이 정수 값이 float나 double로 자동 타입 변환이 이루어지지만, 소수점 이하의 정보는 이미 연산 과정에서 손실된 상태입니다.
- 이러한 문제를 해결하려면, 연산을 수행하기 전에 적어도 한 쪽 피연산자를 최종 결과 타입으로 캐스트(형변환)해야 합니다.
// Noncompliant Code
@Override
public List<Building> searchBuildings(String params, List<Double> cursorIds, Pageable pageable) {
return searchBuildingsQuery(cursorIds, pageable).andThen(customOrderBy(pageable)).apply(params)
.limit(pageable.getPageSize() + 1)
.fetch();
}
// Compliant Solution
@Override
public List<Building> searchBuildings(String params, List<Double> cursorIds, Pageable pageable) {
return searchBuildingsQuery(cursorIds, pageable).andThen(customOrderBy(pageable)).apply(params)
.limit(pageable.getPageSize() + 1L)
.fetch();
}
- 지역 변수와 메소드 파라미터 명은 ^[a-z][a-zA-Z0-9]*$ 정규식에 맞게 지어라
- 대문자로 되어있던 지역변수를 소문자로 변경했습니다.
// Noncompliant Code
List<OrderSpecifier<?>> ORDERS = new ArrayList<>();
// Compliant Solution
List<OrderSpecifier<?>> orders = new ArrayList<>();
💡 ReviewCustomRepositoryImpl
- switch 문에 default 절을 추가하라.
- default 절에서는 id에 대해 내림차순 정렬하도록 추가했습니다.
// Noncompliant Code
switch (order.getProperty()) {
case "id":
OrderSpecifier<?> orderId = QueryDslUtil.getSortedColumn(direction, review, "id");
ORDERS.add(orderId);
break;
case "likeCnt":
OrderSpecifier<?> orderLikeCnt = QueryDslUtil.getSortedColumn(direction, review.reviewSummary, "likeCnt");
ORDERS.add(orderLikeCnt);
break;
case "score":
OrderSpecifier<?> orderReviewCnt = QueryDslUtil.getSortedColumn(direction, review.reviewToReviewCategoryList, "score");
ORDERS.add(orderReviewCnt);
}
// Compliant Solution
switch (order.getProperty()) {
case "id":
OrderSpecifier<?> orderId = QueryDslUtil.getSortedColumn(direction, review, "id");
ORDERS.add(orderId);
break;
case "likeCnt":
OrderSpecifier<?> orderLikeCnt = QueryDslUtil.getSortedColumn(direction, review.reviewSummary, "likeCnt");
ORDERS.add(orderLikeCnt);
break;
case "score":
OrderSpecifier<?> orderReviewCnt = QueryDslUtil.getSortedColumn(direction, review.reviewToReviewCategoryList, "score");
ORDERS.add(orderReviewCnt);
}
728x90
반응형
'💻 Service > E-ROOM' 카테고리의 다른 글
Refactoring with SonarLint - Service (0) | 2023.07.10 |
---|---|
Refactoring with SonarLint - Controller (0) | 2023.07.07 |