TIL - 2024/04/08

박상우·2024년 5월 3일
0

📝 TIL

목록 보기
16/45
post-thumbnail

FE Article

Link: https://yozm.wishket.com/magazine/detail/2483/

  • 제목 : 프론트엔드 개발자가 알아야할 ‘유닛 테스트’ 작성법

  • 내용

    테스트의 본질은 ‘검증하고 싶은 무언가를 검증하는 것’이다. 검증하는 것이 어떤 것이냐에 따라 목표나 이름이 달라진다.

    • 유닛 테스트 컴포넌트 테스트, 시각 테스트, 종단 간(End-to-End) 테스트 등이 있다. 유닛 테스트는 특정 모듈이 목표하는 기능을 올바르게 수행하고 있는지 검증하는 절차
      • 유닛 테스트 작성 전 알아야할 것
        • 코드를 분리해서 관리하는 이유 - 모든 로직이 하나의 파일, 모듈에 있으면 가독성 측면 뿐만아니라 디버깅에 어려움이 발생한다. 그래서 독립적인 기능을 기준으로 나누는 것이 바람직하다는 의견이 많아졌고, 이러한 내용은 테스트에도 영향을 미친다.
        • 그래서 개발자들은 주어진 요구사항을 만족하는 ‘순수한 함수’로 코드를 분리하는 것을 지향한다.
      • 순수한 코드는 무엇일까
        • 순수하다는 것은 잘 정제되고 다듬어진 코드를 말한다. 그리고 함수가 ‘순수’해지기 위해서 몇가지 조건이 필요하다.
          • 동일한 입력값에는 동일한 결과를 보장해야 한다.
          • 함수의 외부 스코프의 값을 변경하지 않아야 한다.
          • 함수 외부 스코프의 값을 참조하지 않아야 한다.
          • 함수 내부에서 함수의 결과 값에 영향을 주는 예측 불가능한 임의의 값을 사용하지 않는다.
    • 유닛 테스트 연습
      • Given - When - Then 기법을 통해 테스트 케이스 내부의 영역을 명시적으로 구분하여 가독성을 높일 수 있다.
    • 멱등성
      • 특정 기능을 반복해도 항상 같은 결과로 이어져야한다는 것을 말한다.
      • 순수 함수는 항상 멱등성을 띄지만 멱등성을 띈다고 순수함수는 아니다.
  • Opinion

    테스트 코드 관련해서는 여러번 시도해본적이 있지만 실제 프로젝트에 적용해본적은 아직 없다. 필요성에 아직 공감을 깊게 못해고 있다는 점이 큰 것 같다. 그래서 올해 중순에 있을 나만무 시즌에는 서비스 크기나 FE쪽 기술 난이도를 고려해서 테스트 코드 관련해서 적극 도입을 검토해볼 예정이다.


데이터 이동 인스트럭션

가장 많이 사용되는 인스트럭션은 데이터를 한 위치에서 다른 위치로 복사하는 명령이다.

오퍼레이션 표기 방식의 일반성으로 인해 데이터 이동과 관련된 기계어 인스트럭션의 간단해졌다.

데이터 이동 클래스 MOV는 4개의 인스트럭션을 구분되어 있다.: movb, movw, movl, movq . 이 네개의 인스트럭션은 모두 같은 동작을 하지만 인스트럭션의 마지막 글자에 따라 서로 다른 크기의 데이터를 다룬다는 점에서 차이가 있다.

소스 오퍼랜드는 상수, 레지스터 저장값, 메모리 저장 값을 표시한다.

목적 오퍼랜드는 메모리 또는 레지스터 주소의 위치를 지정한다.

x86-64는 데이터 이동 인스트럭션에서는 소스 값을 레지스터에 적재하는 인스트럭션과 레지스터 값을 목적지에 쓰기위한 인스트럭션이 필요하다.

InstructionEffectsDescription
MOV S, DD ←SMove
movbMove Byte
movwMove word
movlMove double word
movqMove quad word
movabsq I , RR ←IMove absolute quad word

movabsq의 경우 64비트 상수를 다루기 위한 것이다. movq의 경우 32비트 2의 보수 숫자로 나타낼 수 있는 상수 소스 오퍼레이션만 가지며 이후 부호 확장 되어 목적지를 위해서 64비트를 생산하게 된다. movabsq의 경우 임으로 64비트 상수 값을 소스 오퍼레이션으로 가질 수 있고, 목적지를 레지스터만으로 설정 가능하다.

작은 소스 값을 큰 목적지로 복사하기 위한 MOVZ 클래스와, MOVS 클래스가 있다. 이 인스트럭션들은 레지스터나 메모리에 있는 소스로 부터 레지스터 목적지로 복사한다. 두 클래스 인스트럭션의 마지막 두 개의 문자는 각각 소스의 크기와 목적지의 크기를 나타낸다.

  • MOVZ 클래스 → 목적지의 남은 바이트를 모두 0으로 채워준다.
    InstructionEffectsDescription
    MOVZ S, RR ←ZeroExtend(S)Move with zero extension
    movzbwMove zero-extended byte to word
    movzblMove zero-extended byte to double word
    movzwlMove zero-extended word to double word
    movzbqMove zero-extended byte to quad word
    movzwqMove zero-extended word to quad word
    movzlq 인스트럭션은 없다. 해당 데이터 이동은 movl로 구현 가능하다.


  • MOVS 클래스 → 소스 오퍼랜드의 가장 중요한 비트를 반복해서 복사한다.
    InstructionEffectsDescription
    MOVS S, RR ←SignExtend(S)Move with sign extension
    movsbwMove sign-extended byte to word
    movsblMove zero-extended byte to double word
    movswlMove sign-extended word to double word
    movsbqMove sign-extended byte to quad word
    movswqR ←IMove zero-extended word to quad word
    movslqR ←IMove sign-extended double word to quad word
    cltq%rax ← SignExtend(%eax)Sign-extend %eax to %rax
    cltq 인스트럭션의 경우 레지스터 %eax%rax 만을 대상으로 한다.

스택 데이터의 저장과 이동 push, pop

x86-64에서 프로그램 스택은 특정 영역에 위치의 주소를 갖는 형태로 아래로 성장하는 특징이 있다.

popq 인스트럭션은 데이터를 추출하고 pushq 인스트럭션은 데이터를 스택에 추가하는 기능을 제공한다.

  • stack에 추가
    subq $8, %rsp  -> Derement stack pointer
    movq %rbp, (%rsp) -> Store %rbp on stack
  • stack에서 빼기
    movq (%rsp), %rax -> Read %rax from stack
    addq $8, %rsp  -> Derement stack pointer

3.7 프로시저

프로지서 호출은 소프트웨어에서의 주요 추상화이다. 지정된 인자들과 리턴 값으로 특정 기능을 구현하는 코드를 감싸주는 방법을 제공한다.

프로시저를 통해 프로그램 상태에 무슨 효과를 갖는지 간결한 인터페이스를 제공하며, 동시에 구체적인 구현을 감춰주는 추상화 매커니즘으로서 이용한다.

프로시저가 기계어 지원을 제공할 때 아래와 같은 메커니즘과 연관된다.

  • 제어권 전달: 프로그램 카운터는 프로시저 Q에 대한 시작 주소로 설정되고 리턴할때 프로시저 P에서 Q를 호출하는 인스트럭션 다음의 인스트럭션으로 설정되어야 한다.
  • 데이터 전달: 프로시저 P는 하나 이상의 매개변수 Q를 제공할 수 있어야 하며, Q는 다시 하나의 프로시저 P로 하나의 값을 리턴할 수 있어야 한다.
  • 메모리 할당과 반납: 프로시저 Q는 시작할 때 지역 변수들을 위한 공간으로 할당할 수 있고, 리턴할 때 이 저장소를 반납할 수 있다.

3.7.1 런타임 스택

대부분의 언어에서 프로시저 호출 동작 방식을 스택 자료구조의 후입선출 방식을 가지고 있다. 프로시저 가 다른 프로시저를 호출하는 경우 호출한 프로시저가 일시 중지되고 이후 호출된 프로시저가 리턴했을 때 자신이 할당된 위치로 반납될 수 있다. 따라서 스택을 통해 프로시저들이 요구하는 저장 장소로 활용될 수 있으며, 여기서 스택과 프로그램 레지스터들이 제어와 데이터를 전송하기 위해, 메모리를 할당하기 위해 필요한 정보를 저장한다.

프로시저가 레지스터에 저장할 수 있는 개수 이상의 저장 공간을 필요로 할때 스택에 할당한다. 이때 사용되는 영역을 스택 프레임이라고 한다.

일반적인 스택과 달리 stack Top 부분이 바닥을 향해 있으며, 실행중인 프로시저에 대한 프레임은 항상 스택의 시작 부분, 맨 위에 위치한다. 프로시저(P)가 다른 프로시저(Q)를 부를 때 다시 프로그램이 재실행되는 위치에 대한 리턴 주소를 보관하게 된다. 이때 피호출 프로시저(Q)가 아닌 호출 프로시저(P)와 관련있는 정보기 때문에 호출 프로시저(P)의 스택 프레임에 속한다.

profile
나도 잘하고 싶다..!

0개의 댓글