-
Notifications
You must be signed in to change notification settings - Fork 0
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
대소문자를 구분하지 않는 Attributes #75
base: freddie-noel
Are you sure you want to change the base?
Conversation
삽입, 조회시 강제로 대문자로 수정해서, 대소문자를 구분하지 않는 로직을 구현했습니다.
#67 기존 들어온 헤더 필드를 강제로 대문자로 변경 후 저장하는 구조였는데, 기존 테스트 케이스가 깨지고, 예상값도 대문자로 해줘야 하는 불편함이 있었습니다. 따라서, Attribute의 맵에 값을 추가할 때 대소문자 관계없이 해당 원소가 존재하는지 맵을 순차적 O(n)으로 비교하고 없을 경우 추가하는 방식으로 로직을 수정했습니다.
return attributes.get(k); | ||
} | ||
} | ||
return null; |
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.
null이 조금 걸리네요..ㅎㅎ
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.
exception
null을 받아야할 이유가 있다면: optional
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.
getDefault가 있는데 굳이 null을 리턴해줄 필요는 없다고 보여집니다.
꼭 써야한다면 Optional로 제공해주는 것도 고려해볼 수 있을 것 같아요
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.
그리고 null을 명시적으로 리턴해준다면 get이 null인 케이스도 테스트에서 확인을 해봐야할 것 같습니다!
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.
고생 많으셨어요
생각하기 어려운 로직인데 잘 처리된 것 같네요
} | ||
|
||
public Attributes add(String key, String value) { | ||
for (String k : attributes.keySet()) { |
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.
직접 사용할 변수면 명시적으로 이름을 짓는 것도 좋아보여요
eachKey currentKey 같은거라도 좋을 것 같고
그게 힘들면 매개변수 이름을 targetKey 같은 걸로 나눠줘도 좋을 것 같습니다.
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.
앗.. 너무 막지었네요.
지적 감사합니다.
return attributes.get(k); | ||
} | ||
} | ||
return null; |
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.
getDefault가 있는데 굳이 null을 리턴해줄 필요는 없다고 보여집니다.
꼭 써야한다면 Optional로 제공해주는 것도 고려해볼 수 있을 것 같아요
for (String k : attributes.keySet()) { | ||
if (k.equalsIgnoreCase(key)) { | ||
return attributes.get(k); | ||
} | ||
} | ||
return defaultValue; |
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.
코드 중복이 되는데 get이나 getOrDefault 둘 중 하나를 기준으로 중복 제거를 해볼 수 있겠네요
Attributes statusLineAttributes = new Attributes(); | ||
|
||
statusLineAttributes.put(METHOD_KEY, statusLine.get(0)); | ||
statusLineAttributes.put(PATH_KEY, statusLine.get(1)); | ||
statusLineAttributes.put(PROTOCOL_VERSION_KEY, statusLine.get(2)); | ||
statusLineAttributes.add(METHOD_KEY, statusLine.get(0)); | ||
statusLineAttributes.add(PATH_KEY, statusLine.get(1)); | ||
statusLineAttributes.add(PROTOCOL_VERSION_KEY, statusLine.get(2)); |
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.
이 부분도 Attributes를 만들면서 자연스럽게 검증이 될 테니 Map으로 받아줘도 괜찮을 것 같아요
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.
그게 아니라 생성자로 Attributes를 넣어주는게 더 바람직하다고 생각하신거면 좋은 방법인 것 같습니다
만약 그렇다면 Map<String, String>을 받는 생성자를 완전히 대체해주는게 좋을 것 같습니다.
assertAll( | ||
() -> assertEquals("value", attributes.get("KEY")), | ||
() -> assertEquals("value", attributes.get("key")), | ||
() -> assertEquals("value", attributes.get("kEy")) | ||
); |
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.
혹시 매개변수화 시켜서 테스트를 하면 어떤 장점이 있는건가요??
아직 정확하게 와닿지 못해서 이런 방식으로 작성했습니다!
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.
기본적으로 저는 assertAll은 같은 테스트에 대한 그룹을 묶어주는 것이라 생각했습니다. 예를 들어 검증해야 될 객체에 여러개의 필드가 들어있고 각각 검증을 해야 하는 상황이라면 묶어주는게 의미가 있을거라 생각합니다.
하지만, assertAll로 여러개의 테스트 케이스를 묶어주면 여러개의 테스트가 하나의 테스트 안에 들어가있는 느낌이라 좋지 못하다고 생각한 것 같습니다. 기본적으로 하나의 테스트는 한 가지 테스트를 수행하는게 가장 좋다고 알고 있기 때문입니다.
마지막으로 가독성에 대한건 개인 취향이긴 한데, RequestHandlerTest에 있는 케이스들을 저런 식으로 처리한다면 가독성이 매우 떨어질 것 같습니다.
() -> assertEquals(expectedAttributes.get("key"), attributes.get("KEY")), | ||
() -> assertEquals(expectedAttributes.get("KEY"), attributes.get("kEY")), | ||
() -> assertEquals(expectedAttributes.get("kEy"), attributes.get("key")) |
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.
size같은걸로 검증해볼 수 있을 것 같네요
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.
예외상황 추가해주셔서 감사합니다!
return attributes.get(k); | ||
} | ||
} | ||
return null; |
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.
그리고 null을 명시적으로 리턴해준다면 get이 null인 케이스도 테스트에서 확인을 해봐야할 것 같습니다!
추가적으로 Attributes의 Map을 계속 탐색하는 대신에 Key를 타입으로 분리해볼 수 있을 것 같습니다. 이런식으로 분리하다보면 나중에 Value 파트도 스프링의 MultiValueMap처럼 리스트 타입으로 해야 하거나 하면 쉽게 분리할 수 있을 것 같아요 |
# Conflicts: # src/main/java/webserver/http/statusline/StatusLine.java
# Conflicts: # src/main/java/webserver/http/startline/RequestLine.java # src/test/java/webserver/http/header/RequestHeaderTest.java # src/test/java/webserver/http/header/ResponseHeaderTest.java # src/test/java/webserver/http/startline/RequestLineTest.java # src/test/java/webserver/http/startline/StatusLineTest.java
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.
고생하셨습니다
아쉬운 부분이 있어서요 한 번만 얘기 더 해봐요 ㅎㅎ
try { | ||
return get(targetKey); | ||
} catch (IllegalArgumentException e) { | ||
return defaultValue; | ||
} |
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.
try-catch를 안 쓰는 방법도 있지 않을까요??
for (String currentKey : attributes.keySet()) { | ||
if (currentKey.equalsIgnoreCase(targetKey)) { | ||
return attributes.get(currentKey); | ||
} | ||
} | ||
throw new IllegalArgumentException("일치하는 키가 없습니다."); |
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.
key에 해당하는 value가 null이라면 제대로 동작하지 않을 것 같아요
이런 경우를 막지 않아도 괜찮을까요?
그리고 예외를 발생시키면서까지 get을 사용해야할 경우가 있을까요?
getOrDefault로는 안되는 경우가 있는건지 궁금합니다
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.
key: "null",
value: null
인 상태에서 key값으로 "null"을 꺼내면 null을 반환 하는데
제대로 동작하지 않는다 게 어떤 부분인지 잘 모르겠습니다.
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.
f61aa7f 에서 try-catch를 제거하는 방식으로 수정했습니다.
혹시 생각하신 방식이랑 다르다면 말씀해주세요!
public Attributes add(String key, String value) { | ||
attributes.put(key, value); | ||
public Attributes add(String targetKey, String value) { | ||
for (String currentKey : attributes.keySet()) { |
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.
👍👍👍👍
()-> assertThat(attributes.get("null")).isNull(), | ||
()-> assertThat(attributes.get("null2")).isNull() |
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.
둘 다 null을 확인하는 별개의 테스트케이스 같은데, 따로 묶은 이유가 있으신가요?
attributes.add("null2", null); | ||
|
||
assertAll( | ||
()-> assertThat(attributes.size()).isEqualTo(2), |
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.
null을 확인하는 테스트 같은데 사이즈를 확인하는 이유가 어떤건가요?
close #67
대소문자를 구분하지 않는 Attributes 를 구현하기 위해
처음 시도했던 방법은 들어온 헤더 필드를 강제로 대문자로 변경 후 저장하는 구조였습니다.
다만, 기존 테스트 케이스가 깨지고, 예상값도 대문자로 해줘야 하는 불편함이 있어 개선이 필요했습니다.
따라서, Attribute의 맵에 값을 추가할 때
대소문자 관계없이 해당 원소가 존재하는지 맵을 순차적으로 비교하고
없을 경우 추가하는 방식으로 로직을 수정했습니다.