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 번호)과 윈도우사이즈를 하나의 패킷으로 묶어서 보냄