TIL - 0524
스프링부트
일급객체 사용하기 : @Embeddable, @Embeded
- 객체지향적으로 코드 변경하기 : 컬렉션을 그대로 사용하지않고, wrapper 클래스를 만들어 객체.메소드로 요청하게끔 코드 짜기
- 응집도가 높은 엔티티를 분리해서 각각 관리하면서(역할 분리 - 유지보수에 유리함) 쓸 때는 하나에서 쓸 수 있게
- 객체지향 생활체조 원칙
- 객체지향 언어를 쓰면서 객체지향 개발을 지양하는 개발자가 되지말자!
@Entity
public class Question {
.
.
.
@Embeded
private Answers answers;
.
.
.
}
@Embeddable
public class Answers {
@OneToMany(mappedBy = "question")
@Where(clause = "deleted = false")
@OrderBy("id ASC")
private List<Answer> answers;
public Answers() {
}
public void delete(Question question) {
answers.forEach(answer -> answer.delete(question));
}
public List<Answer> getAnswers() {
return answers;
}
public int getSize() {
return answers.size();
}
}
@Embeded
: 분리한 엔티티들을 붙여서 사용하는 총체 엔티티의 attribute(인스턴스변수)에 붙이는 어노테이션@Embeddable
: 응집도가 높은 엔티티를 분리하고, 분리한 엔티티에 붙이는 어노테이션
옵셔널 활용하기
- 옵셔널을 리턴하면 안전한 예외처리를 할 수 있음
- 깔끔한 코드를 만들 수 있는 것은 덤이다!
/* QuestionController.java */
@GetMapping("/{id}/edit")
public String edit(@PathVariable("id") Long id, Model model, HttpSession session) {
Optional<Question> maybeQuestion = questionRepo.findById(id);
Question question = maybeQuestion.filter(q -> q.isMatch(HttpSessionUtils.getUserFromSession(session)))
.orElseThrow(() -> new UnAuthorizedException("user.mismatch.sessionuser"));
model.addAttribute("question", question);
return "/question/edit";
}
- try ~ catch 문으로 예외처리를 하지않고 함수로 예외처리 가능함 : API 제공(orElseThrow 등)
- if문을 사용하지않고도 분기처리 가능함 : 코드가 깔끔해짐
- 그러나 너무 남발해서 쓰면 오히려 코드 가독성을 해치는 측면이 있음
네트워크
HTTP 리퀘스트 메세지는 그냥 전달되는 것일까?
- HTTP 리퀘스트 메세지를 그대로 보내지않고, 패킷을 나눠서 전송을 한다 : 데이터가 클 때(예를 들어 게시판 글)는 패킷 분할해서 보냄
- 웹브라우저는 통신기능이 없기때문에 OS의 프로토콜 스택에 리퀘스트 메세지를 전달함
- 프로토콜 스택은 일정 기준에 맞게 패킷으로 쪼개어 보냄
- 일정 기준 : 패킷의 사이즈 - MTU(Max Transmission Unit - TCP 헤더까지 포함한 크기), MSS(Max Segment Size) / 대기타임
- MTU, MSS: 최대 크기까지 기다리는 이유는 잘개 쪼개어진 패킷을 자주 전송하는 것은 네트워크 이용 효율을 저하시키는 것
- 대기타임 : 일정 시간(ms 단위)까지 버퍼에 쌓이지않으면 곧바로 패킷을 만들어 전송함
- 어플리케이션(웹브라우저)으로부터 데이터를 받아 송신버퍼에 저장해두었다가 패킷으로 만듦
- 즉시 전송이 필요할 경우 어플리케이션에서 설정할 수 있음
- 패킷 구성 : 수신측에 전달하는 데이터 총체
- 이더넷이나 IP의 제어정보 : IP 제어정보일 경우 송수신측 IP 번호
- TCP 헤더 : TCP가 헤더를 부가함, TCP 제어정보(송수신측 포트, 컨트롤비트 - 제어 상태값, 시퀀스번호, ACK 번호 - 수신데이터 일련번호 등)
- 데이터 : 쪼개어진 데이터를 넣음
패킷 전송 후 수신 - 누락확인을 한다
- 프로토콜 스택의 임무는 패킷 전송을 하는 것에서 끝나는 것이 아니라 확인, 수신 측으로부터의 데이터 수신까지임
- 전송한 패킷 수신 확인은 어떻게 할까?
- 패킷을 전송할 때 패킷에 시퀀스 번호를 매기고, 해당 패킷의 크기를 기록함
- 수신 측에서는 해당 패킷의 시퀀스 번호 + 전송받은 크기를 더해서 TCP 헤더에 기록(ACK 번호)해서 다시 클라이언트에 보냄
- 클라이언트에서는 ACK 번호를 가지고 어느 패킷이 누락되었는지 체크를 할 수 있음 : 몇 바이트 받았는지
- 수신 확인이 오지 않을 경우
- 여러 경우가 있음 : 네트워크 연결이 불안정하거나 끊겼거나
- 여러번 전송하면 그것 또한 낭비이기때문에 기준이 존재함
- 통신 타임아웃값(기준)이 설정되는데, 타임아웃값은 패킷 통신을 하면서 수신측에서 보낸 ACK 번호의 수신 시간에 따라 타임아웃 시간이 동적으로 변함
- 누락되었을 경우에는 프로토콜 스택에 할당된 송신버퍼에서 다시 꺼내어 다시 전송함
- 클라이언트 - 서버 양방향 통신 : 송수신을 각각 할 수 있는데 각각 다른 방법으로 송수신하는게 아니라 방법은 똑같음
패킷 전송 수신확인까지 기다리지않고 전송하기
- 패킷 전송 수신확인(ACK 번호)까지 기다린다면 그만큼 시간낭비를 하는 것
- 비동기 방식으로 제어를 하는 방법이 있는데 윈도우 제어 방식이라고 함
- 패킷을 전송하고, 전송하는 방식
- 알고 있어야할 부분 : 수신하는 측에서 수신버퍼를 두고 패킷을 수신하는데, 저장용량 초과가 나면 어떡하지?
- 수신버퍼가 초과하지않도록 수신 측에서 TCP 헤더에 수신할 수 있는 데이터양에 대해 알림
- 수신버퍼는 다차면 수신 처리를 하는게 아니라 수신이 왔을 때 즉시 처리함 : 빈 공간만큼 받을 수 있는 공간이 늘어남
- 그렇다면 매번 수산할 수 있는 데이터양(윈도우 사이즈)에 대해 알릴 것인가?
- 매번 알린다면 이 또한 잘개 여러번 패킷을 보내는 것이므로 네트워크 이용 효율이 떨어지는 행위
- 수신확인(ACK 번호)과 윈도우사이즈를 하나의 패킷으로 묶어서 보냄