New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: 지역 검색 기능을 추가한다 #836
feat: 지역 검색 기능을 추가한다 #836
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
작성하신 코드 잘 봤습니다 전반적으로 잘 작성해주셔서 몇가지 코멘트만 남겼습니다
어제 얘기했을 때는 json으로 관리하여 요청하는 이유가 city에 대해 추가,수정,삭제 이런 것들을 관리하기 편해서라고 말씀해주셨는데 작성해주신 코드를 보면 이미 저장되어 있다면 작업을 수행하지 않기 때문에 굳이 json으로 관리하는 이유를 잘 모르겠습니다!
오히려 이렇게 된다면 json도 관리해줘야하고 db의 데이터도 관리해줘야 될 것 같아보여서요 혹시 제이의 다른 의견이 있으신가요?
} | ||
|
||
@Override | ||
public boolean isExistAlready() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is exists 로 메서드명을 바꾸는 건 어떤가요? already는 결국 과거형이라 뭔가 어색한 느낌인것 같아요
@Override | ||
public boolean isExistAlready() { | ||
String sql = "SELECT EXISTS (SELECT 1 FROM city)"; | ||
Integer result = namedParameterJdbcTemplate.queryForObject(sql, Map.of(), Integer.class); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아무 변수를 바인딩할 필요가 없다면 namedparameter jdbc말고 그냥 jdbctemplate을 사용하는 것이 가독성이 좋을 것 같아요!
.where(city.name.contains(query)) | ||
.limit(LIMIT_SIZE_OF_CITY) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
orderby 하지 않아도 매번 같은 결과가 보장되나요? 정렬을 하지 않으면 왠지 같은 단어를 검색해도 결과가 다를 수도 있을 것 같아서요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
먼저 찾는 순서대로 나와서 결과는 같습니다! 그래도 OrderBy 해주는 것이 보는 사람 입장에서는 편할 것 같네요~ 수정하겠습니다
@RequiredArgsConstructor | ||
@Slf4j | ||
@Service | ||
public class CityRequestService { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
해당 객체에 많은 책임이 있는 것 같은데 분리하는 것은 어떤가요?
예를 들어 요청을 보내는 클래스, 그걸 변환을 해주는 부분, 저장을 하는 부분
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
분리는 하는게 저도 좋다고 생각합니다!
다만, 위에 리뷰와 더불어서 어떻게 할지 한 번 생각을 들어보고 진행하고 싶어서 이번에는 코멘트만 남겨봅니다!
- JSON으로 데이터를 받는 것에 대하여
- 이 부분은 처음에
cityCustomRepository.isExist()
를 통해서데이터가 없다면
city 데이터를 로드하여 저장합니다.
다만 만약 새로운 데이터가 추가된다면 저장하지 못하는 문제가 발생할 수 있다고 생각합니다.
--> 이를 개선하기 위해서 해당 if문을 지워도 될 것 같다고 생각합니다. 현재 batch insert 부분에서 INSERT IGNORE~
쿼리로 작동하기 때문입니다
- 현재 City 데이터가 약 2만6천개 정도 되고 있습니다.
이를 저도 페이징 처리해서 1000개씩 저장하면 좋다고 생각하지만, 이 API에서 페이징할 수가 없습니다 ㅠㅠ 이를 어떻게 나눠서 저장하면 좋을까요?
물론 처음에만 저장하면 그 후부터는 중복되는 건 스킵하기 때문에 큰 문제는 없을 것 같지만 첫 저장에서 오래 걸릴까봐 걱정이 되긴하네요 ㅎㅎ 의견 주시면 좋을 것 같습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 지금 로직에서 insert ignore로 저장하게 된다면 똑같은 데이터가 또 저장될 것 같습니다. insert ignore은 id가 같은 부분에 대해서 insert 시 에러를 무시하도록 하는 함수인데, 현재는 insert 시에 id를 auto increment로 증가시켜주고 있기 때문에 id가 무조건 중복되지 않아 그냥 insert가 될 것 같아요 , 그리고 json에 데이터가 추가된다면 insert로 추가하는 부분은 쉬울 것 같은데, 만약 json에서 해당 주소명이 변경되거나, 위도 경도가 변경된다면 대응하기가 힘들 것 같은데 이 부분에 대해서는 어떻게 생각하시나요?
- 페이징 처리를 하지 않더라도 트랜잭션은 분리하면 좋을 것 같아요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- RequestService의 트랜잭션 분리 및 현재 다른 작업처럼 첫 실행에서 실행되고 나머지는 off로 실행되지 않도록 변경
- 가끔 추가되는 지역 데이터 및 수정되는 정보는 관리자 페이지로 작업하도록 변경
슬랙으로 대화 나눈 것처럼 API 호출하는 작업은 비싼 작업이니 관리자 페이지에서 관리하도록 변경하겠습니다.
자주 바뀌는 데이터가 아니다보니 관리자 페이지로 진행해도 될 것 같습니다!
좋은 리뷰 감사합니다 !
@Transactional | ||
public void requestCity() { | ||
while (true) { | ||
try { | ||
if (cityCustomRepository.isExistAlready()) { | ||
log.info("지역 정보가 이미 존재합니다"); | ||
return; | ||
} | ||
saveCities(); | ||
log.info("지역 정보 저장 완료"); | ||
return; | ||
} catch (Exception e) { | ||
log.error("지역 정보 저장 실패"); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
해당 메서드에 transactional이 붙어있으면 요청을 보내서 응답을 받아오는 시간 + 객체를 매핑하는 시간 + 저장하는 시간 때문에 트랜잭션을 오래 잡고 있을 것 같은데 문제 없을까요..?
Assertions.assertDoesNotThrow(() -> | ||
cityCustomRepository.saveAll(cities) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does not throw로 저장이 되었다고 검증을 할 수 있을까요? 차라리 아래의 테스트로 퉁치는 것이 어떨까요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
그러네요 밑에는 어차피 저장을 해야하니 퉁칠 수 있겠네요
사실 두 가지를 검증하니 좋은 테스트는 아니라고 생각하지만 테스트를 위한 불필요한 메서드보다는 나은 것 같아요 감사합니다
softly.assertThat(result.get(0)).usingRecursiveComparison() | ||
.isEqualTo(new CitySearchResponse("서울특별시", Latitude.from("37.5666103").getValue(), Longitude.from("126.9783882").getValue())); | ||
softly.assertThat(result.get(1)).usingRecursiveComparison() | ||
.isEqualTo(new CitySearchResponse("서울특별시 송파구 잠실동", Latitude.from("37.5666103").getValue(), Longitude.from("126.9783882").getValue())); | ||
softly.assertThat(result.get(2)).usingRecursiveComparison() | ||
.isEqualTo(new CitySearchResponse("서울특별시 송파구 신천동", Latitude.from("37.5666103").getValue(), Longitude.from("126.9783882").getValue())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using recursive comparison을 사용하면 굳이 list.get을 하지 않고도 테스트 할 수 있어요 그렇게 수정하는 것이 가독성이 좋을 것 같아요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수고하셨어요 제이! 테스트 관련해서 의견 하나 남겼습니다~
public interface CityCustomRepository { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
왜 Custom이라는 키워드가 들어갔는지 궁금해요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
기존에 주기적인 업데이트 하는 부분도 Custom이라고 이미 네이밍 되어 있어서 통일하려고 맞췄습니다!
@Test | ||
void 지역을_최대_3개_불러온다() { | ||
// given | ||
cityCustomRepository.saveAll(List.of( | ||
서울특별시_정보, | ||
서울특별시_송파구_잠실동_정보, | ||
서울특별시_송파구_신천동_정보 | ||
)); | ||
|
||
// when | ||
List<CitySearchResponse> result = cityQueryRepository.findSearchResult("서울"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저희 검색조건이 %지역%과 최대3개라면
-서울 송파 잠실
-서울 송파 신천
-경기 송파라솔 어쩌구
-경기 송파란색 저쩌구
저장해서 쿼리를 "송파"로 하고 송파라는 단어가 들어있는 것들 중 3개를 잘 갖고오는지 확인하는 테스트도 있었으면 좋겠어요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
그러네요~ 수정했습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제이 작성해주신 코드 잘 봤습니다
트랜잭션 분리하신 것도 확인했습니다
마지막으로 city패키지가 station에 있는게 어색한데 어떻게 생각하시나요?
private final CityCustomRepository cityCustomRepository; | ||
|
||
public void requestCity() { | ||
while (true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
while true로 메서드를 호출하면 문제가 없을까요?
제 생각에는 네트워크 환경이 안좋다던가 혹은 주소가 잘못되거나 이럴 때도 계속 호출하게 될 것 같은데요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
그럴 수 있을 것 같아요
커넥션이나 네트워크나 여러 문제가 생기는 경우 호출을 계속할 가능성이 있네요
MAX_TRY_COUNT를 두어서 실행에 제한을 두도록 변경하겠습니다
private final AdminCityService adminCityService; | ||
|
||
@GetMapping | ||
public ResponseEntity<CustomPage<CityResponse>> findAllCities(@AuthMember Long memberId, Pageable pageable) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
custom page 좋아요
|
||
@RequiredArgsConstructor | ||
@Component | ||
public class CityCustomRepositoryImpl implements CityCustomRepository { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
jdbc template을 사용하는 클래스가 domain에 있는게 어색해요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
맞네요 라이브러리이니 infrastructure로 이동시켰습니다.
@RequiredArgsConstructor | ||
@Slf4j | ||
@Component | ||
public class RestTemplateCityRequester { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
해당 클래스도 인터페이스를 통해 의존성을 관리하는 것이 어떠신가요? 만약 rest template을 사용하다 web client라는 클래스를 사용하게 된다면 클래스 이름도 바뀌어야할 거고 내부 구현도 바뀌어야하는데 이걸 사용하는 서비스 클래스에서도 변경에 의한 영향이 있을 것 같아서요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
정말 갓스터네요 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수고하셨습니다
📄 Summary
충전소 검색시
%검색어%
방식으로 지역을 검색합니다.🕰️ Actual Time of Completion
🙋🏻 More
close #833