블로그
전체 112025. 03. 16.
0
[워밍업 클럽 3기 - CS 전공 지식] - 2주차 발자국
✍ 학습 내용 복습Q. 공유 자원(Shared Resource)이란?A. 공유 자원은 여러 프로세스나 스레드가 동시에 사용하거나 접근할 수 있는 자원을 의미한다. 프로세스 또는 스레드 간에 공통으로 사용되기 때문에, 자원에 대한 접근을 관리하는 것이 중요한다.Q. 임계 구역(Critical Section)이란?A. 공유 자원에 동시에 접근이 가능한 구간.(보통 코드 구간을 의미)Q. 상호 배제(Mutual Exclusion)이란?A. 공유 자원에 대해 한 번에 하나의 프로세스나 스레드만 접근할 수 있도록 보장하는 것.Q. 교착 상태(Deadlock)이란?A. 여러 개의 프로세스나 스레드가 서로 자원을 기다리며 무한히 대기하는 상태. 교착 상태가 발생하기 위해서는 다음의 4가지 조건이 필요하다. 상호 배제, 비선점, 점유와 대기, 원형 대기. 하나라도 만족하지 못한다면 교착상태에 빠지지 않는다
워밍업클럽3기
・
CS
・
발자국
2025. 03. 16.
0
[워밍업 클럽 3기 - CS 전공 지식] - Day 9 미션 2
운영체제FIFO 스케줄링의 장단점이 뭔가요?장점단순하고 이해하기 쉽다단점실행 시간(burst time)이 짧은 프로세스는 실행 시간이 길더라도 일찍 도착한 프로세스의 완료를 기다려야한다 SJF를 사용하기 여러운 이유가 뭔가요?A. 프로세스의 실행시간을 예측하기 어렵다. RR 스케줄링에서 타임 슬라이스가 아주 작으면 어떤 문제가 발생할까요?A. 컨텍스트 스위칭을 처리하는 비용이 증가한다. 운영체제가 MLFQ에서 CPU Bound Process와 I/O Bound Process를 어떻게 구분할까요?A. CPU 사용시간에 따라 우선순위 큐에 다르게 배치하면서 구분한다. 예를 들어, CPU 바운드 작업은 타임 슬라이스를 I/O 바운드 작업보다 오래 점유해서 사용하기 때문에, 우선순위가 낮은 큐에 배치시키고, 더 짧게 사용하는 I/O 바운드 프로세스는 우선순위가 더 높은 큐에 배치시킨다. (타임 슬라이스를 사용하는 시간과 요청 빈도에 의한 피드백) 공유자원이란 무엇인가요?A. 프로세스간 통신에서 공통으로 접근해서 이용하게 되는 데이터. 교착상태에 빠질 수 있는 조건은 어떤 것들을 충족해야할까요?상호 배제: 자원은 한번에 하나의 프로세스만 사용비선점: 이미 점유한 자원은 다른 프로세스가 뺏어갈 수 없다점유와 대기: 이미 자원을 점유한 프로세스가 추가적인 자원을 기다리는 상태원형 대기: 프로세스들이 서로가 가지고 있는 자원을 기다리며 대기하는 상태자료구조와 알고리즘재귀함수에서 기저조건을 만들지 않거나 잘못 설정했을 때 어떤 문제가 발생할 수 있나요?A. 함수에서 탈출하지 못하기 때문에 무한하게 재귀를 호출하게 되면서 스택 오버플로우(StackOverflow)가 발생한다.0부터 입력 n까지 홀수의 합을 더하는 재귀 함수를 만들어보세요.A.function sumOdd(n) { if (n 다음 코드는 매개변수로 주어진 파일 경로(.는 현재 디렉토리)에 있는 하위 모든 파일과 디렉토리를 출력하는 코드입니다. 다음 코드를 재귀 함수를 이용하는 코드로 변경해보세요.import fs from "fs"; import path from "path"; function traverseDirectory1(directory){ const stack = [directory]; // 순회해야 할 디렉토리를 저장할 스택 while (stack.length > 0) { // 스택이 빌 때까지 반복 const currentDir = stack.pop(); // 현재 디렉토리 const files = fs.readdirSync(currentDir); // 인자로 주어진 경로의 디렉토리에 있는 파일or디렉토리들 for (const file of files) { // 현재 디렉토리의 모든 파일or디렉토리 순회 const filePath = path.join(currentDir, file); //directory와 file을 하나의 경로로 합쳐줌 const fileStatus= fs.statSync(filePath); // 파일정보 얻기 if (fileStatus.isDirectory()) { // 해당 파일이 디렉토리라면 console.log('디렉토리:', filePath); stack.push(filePath); } else { // 해당 파일이 파일이라면 console.log('파일:', filePath); } } } } traverseDirectory1("."); // 현재 경로의 모든 하위 경로의 파일, 디렉토리 출력 console.log("------------------------"); function traverseDirectory2(directory){ const files = fs.readdirSync(directory); // 현재 디렉토리의 파일 목록 가져오기 for (const file of files) { const filePath = path.join(directory, file); // 파일 또는 디렉토리의 전체 경로 const fileStatus = fs.statSync(filePath); // 파일정보 얻기 if (fileStatus.isDirectory()) { // 해당 파일이 디렉토리라면 console.log('디렉토리:', filePath); traverseDirectory2(filePath); // 재귀 호출하여 내부 탐색 } else { // 파일인 경우 console.log('파일:', filePath); } } } traverseDirectory2("."); // 현재 경로의 모든 하위 경로의 파일, 디렉토리 출력
워밍업클럽3기
・
cs
・
미션
2025. 03. 09.
0
[워밍업 클럽 3기 - CS 전공 지식] - Day 5 미션 1
운영체제 1. while(true){ wait(1); // 1초 멈춤 bool isActivated = checkSkillActivated(); // 체크 } 위 코드는 1초 마다 플레이어가 스킬을 사용했는지 체크하는 코드입니다. 이 방식은 폴링방식입니다. 1초마다 체크하기 때문에 성능에 좋지 않습니다. 이를 해결하기 위한 방식으로 어떤 걸 이용해야 할까요? A. 인터럽트(Interrupt) 방식 프로그램과 프로세스가 어떻게 다른가요?A. 프로그램 자체는 명령어의 집합일 뿐이다. 반면에 프로세스는 해당 프로그램을 실행하여, 프로세스가 사용할 독립된 메모리 공간을 할당받는다. 멀티프로그래밍과 멀티프로세싱이 어떻게 다른가요? A. 멀티 프로그래밍은 메모리에 여러개의 프로세스를 올려서 처리하는 방식이다. CPU가 한 프로그램의 I/O 작업 등을 기다리는 동안 다른 프로그램을 실행할 수 있게한다. 멀티 프로세싱은 여러 CPU(또는 코어)를 사용하여 여러 프로세스를 실제로 동시에 처리하는 것을 말한다. 운영체제는 프로세스를 관리하기 위해서 어떤 것을 사용하나요? A. 프로세스를 관리하기 위한 주요 요소는 다음과 같다.프로세스의 정보를 담고있는 PCB(Process Control Block)를 사용생성, 준비, 대기, 실행, 완료로 프로세스 상태를 관리한다어떤 프로세스에 CPU 시간을 할당할지 결정하기 위해 CPU 스케쥴링(Scheduling)을 사용한다 컨텍스트 스위칭이란 뭔가요?A. 운영 체제가 CPU를 하나의 프로세스에서 다른 프로세스로 전환하는 과정. 과정을 대략적으로 설명하면 다음과 같다.인터럽트가 발생하면, 운영 체제는 현재 실행 중인 프로세스의 상태 정보를 PCB에 저장(스케줄러는 준비 상태 큐에 있는 프로세스 중에서 선택)선택된 프로세스의 PCB에서 상태 정보를 참조해서 상태를 복원 자료구조와 알고리즘 여러분은 교실의 학생 정보를 저장하고 열람할 수 있는 관리 프로그램을 개발하려고 합니다. 이 때 여러분이라면 학생의 정보를 저장하기 위한 자료구조를 어떤 걸 선택하실 건가요? 이유를 함께 적어주세요. A1. 단일 교실 규모라면 배열 또는 리스트를 사용한다이유: 학생에 대한 변경(추가/삭제)는 자주 일어나지 않는다. 순서를 보장할 수 있다. 교실 전체의 학생을 순회하여 조회하는 경우가 많다.A2. 학교 전체를 관리하는 경우 해시 맵을 사용한다이유: 읽기/쓰기/삭제 등의 작업에 O(1)의 성능을 보장하기 때문에 효율적이다. 현재 컴퓨터의 성능을 고려하면, 메모리 문제가 발생할 가능성은 낮다. 특정 정보를 키로 활용할 수 있다.(예시: 학번을 키로 사용) 여러분은 고객의 주문을 받는 프로그램을 개발하려고 합니다. 주문은 들어온 순서대로 처리됩니다. 이 때 여러분이라면 어떤 자료구조를 선택하실 건가요? 이유를 함께 적어주세요.A. 큐(Queue) 자료구조를 사용한다이유: 가장 먼저 들어온 데이터가 가장 먼저 나가는 구조이기 때문에, 주문이 들어온 순서대로 처리하기에 적합하다. 우리가 구현한 스택은 0번 인덱스, 즉 입구쪽으로 데이터가 삽입되고 나오는 구조입니다. 반대로 마지막 인덱스, 즉 출구쪽으로 데이터가 삽입되고 나오는 구조로 코드를 변경해주세요.A.push(data) { // 0번 인덱스 대신 마지막 인덱스에 삽입 this.list.insertLast(data); } pop() { try { // 0번 인덱스 대신 마지막 노드 삭제 및 반환 return this.list.deleteLast(); } catch(e) { return null; } } 해시테이블의 성능은 해시 함수에 따라 달라집니다. 수업 시간에 등번호를 이용해 간단한 해시 함수를 만들어봤습니다. 이번엔 등번호가 아닌 이름을 이용해 데이터를 골고루 분산시키는 코드로 수정해주세요. 힌트: charCodeAt() 함수를 이용 예시: name1 = "이운재"; name1.charCodeAt(0); // 51060 이운재의 0번 인덱스 ‘이’의 유니코드 출력 hashFunction(name) { let hashValue = 0; for (let i = 0; i
워밍업클럽3기
・
CS
・
미션
2025. 03. 09.
0
[워밍업 클럽 3기 - CS 전공 지식] - 1주차 발자국
✍ 학습 내용 복습Q. 배열(Array)의 특징은?A. 가장 기본적인 자료구조배열은 같은 종류의 데이터들이 순차적으로 저장되어 있다배열의 크배열은 메모리 주소가 연속될 것을 요구하기 때문에 배열의 크기를 늘리는 것은 불가능기에 상관 없이 인덱스를 알고 있으면 해당 원소로 접근하는데 걸리는 시간은 O(1)이다(참조의 성능이 좋다)배열의 크기를 늘릴 필요가 있다면 크기가 더 큰 새로운 배열을 생성하여 기존 배열의 내용을 복사하는 과정이 필요하다 Q. 연결 리스트(Linked List)의 특징은?A.연결 리스트는 낭비되는 메모리 없이 필요한 만큼만 메모리를 확보해서 사용하기 위해서 노드를 만들고 각 노드를 서로 연결해서 사용한다노드는 저장할 데이터와 다음 노드로 향하는 참조를 가지고 있다. 첫 노드(헤드 노드)의 주소만 알고 있으면, 다른 연결된 모든 노드에 접근할 수 있다초기에 크기를 정해야 하는 기존 배열의 단점을 해결할 수 있다 Q. 해시 테이블(Hash Table)의 특징은?A.키-값(Key-Value) 형태의 자료구조키를 알고 있다면, O(1)의 성능으로 값을 읽기/삽입/수정/삭제하는 것이 가능하다(해시 충돌이 없다는 가정)해시 함수(해시 알고리즘)를 사용한다. 해시 함수를 통해 값에 대한 해시값을 계산한다.해시 인덱스(hash index)는 데이터가 저장될 위치라고 생각하면 편한다해시 값에 대한 해시 인덱스를 구하는 과정을 해싱(hashing)이라고 한다해시 충돌(hash collision)은 이미 키에 값이 존재하는 경우에 값을 삽입되는 경우 발생한다. 이 경우 해당 키에서는 값들을 리스트로 저장해서 사용한다. Q. 프로세스(Process)란?A. 실행 중인 프로그램. 프로그램 자체는 명령어의 집합일 뿐이다. 반면에 프로세스는 해당 프로그램을 실행하여, 프로세스가 사용할 독립된 메모리 공간을 할당받는다. Q. 시분할 시스템(Time-Sharing System)이란?A. CPU가 여러 프로세스에게 짧은 시간 간격(시간 조각)을 할당하고, 각 프로세스는 이 시간 동안만 실행되는 방식의 시스템. 시간 간격이 매우 짧아서 여러 프로세스가 동시에 실행되는 것처럼 보이게 만들 수 있다. Q. 컨텍스트 스위치(Context-switch)란?A. 운영 체제가 CPU를 하나의 프로세스에서 다른 프로세스로 전환하는 과정. 과정을 대략적으로 설명하면 다음과 같다.인터럽트가 발생하면, 운영 체제는 현재 실행 중인 프로세스의 상태 정보를 PCB에 저장(스케줄러는 준비 상태 큐에 있는 프로세스 중에서 선택)선택된 프로세스의 PCB에서 상태 정보를 참조해서 상태를 복원CPU가 새 프로세스를 실행하기 시작 🤔 회고CS 지식을 복습할 수 있어서 너무 좋았다
시스템 · 운영체제
・
워밍업클럽3기
・
CS
・
운영체제
・
자료구조
2024. 10. 27.
0
[워밍업 클럽 2기 - Clean Code & Test Code] 4주차 발자국
워밍업 클럽 2기: Clean Code & Test Code의 4주차 발자국 작성입니다.3주차 발자국 보러가기 📝 학습 내용Presentation Layer 테스트 작성Mock더 나은 테스트를 작성하기 위한 여러 팁REST Docs ✍ 학습 내용 복습Q. Presentation Layer의 특징은?클라이언트로 부터 입력을 받아서 비즈니스 계층으로 해당 요청을 보내는 계층요청을 제일 먼저 받는 계층입력 데이터에 대한 기본적인 검증을 수행한다Presentation 계층에서의 검증과 Business 계층에서의 검증을 분리해서 생각해야 한다Presentation 계층에서는 보통 형식적인 검증을 한다예시: 필수 입력 값 검사, 데이터 타입 검사, null 검사, 빈 문자열 검사Business 계층에서는 비즈니스 로직에 따른 도메인 유효성 검사가 이루어진다Business 계층으로 부터 결과를 받아서 클라이언트로 반환한다컨트롤러에서 사용하는 요청 DTO가 서비스 계층으로 침투하지 못하도록 컨트롤러 계층에서 서비스 전용 DTO로 변환하는 것을 권장한다(상황에 따라 다를 수 있을것 같다. 만약 받는 포맷이 변할 가능성이 거의 없다면, 그냥 컨트롤러의 DTO를 쭉 사용해도 괜찮지 않을까 생각이 된다.)Q. Presentation Layer의 테스트 방법은?Business, Persistence 계층을 모킹해서 테스트한다MockMvc 같은 도구를 사용해서 HTTP요청과 응답을 시뮬레이션 한다모킹을 위해서 Mockito 같은 프레임워크를 사용할 수 있다 Q. Test Double의 종류를 정리해보자면?Dummy: 아루런 동작도 하지 않는 객체. 잘 사용되진 않지만, 보통 파라미터 전달용으로 사용된다.Fake: 실체 객체와 동일한 기능은 수행하지만, 프로덕션 용도로 사용하기에는 적합하지 않은 객체.예시: 인메모리로 맵을 사용해서 가짜 레포지토리를 구현하는 경우Stubs: 테스트에서의 요청에 대해 미리 준비된 결과를 제공하는 객체. 미리 반환할 데이터가 정의되어 있고, 호출하는 경우 해당 데이터를 반환한다. 미리 정의되어 있지 않은 것들은 응답하지 않는다.Spies: Stub이지만 정복 기록도 함께하는 객체. 호출 여부, 호출 횟수 등의 정보를 기록할 수 있다. 일부는 실제 객체 처럼 동작하고, 일부는 Stubbing할 수 있다.Mocks: 행위에 대한 기대를 명세하고, 그 명세에 따라 동작되도록 설계 된 객체. 그러니깐 개발자가 직접 그 객체의 행동을 관리하는 객체이다.Q. Stub과 Mock을 구분하는 기준은?Stub : 상태 검증(State Verification)Mock : 행동 검증(Behavior Verification) TIP. 테스트 작성을 위한 여러 팁을 정리해보면Mockito 프레임워크를 한번 래핑하는 BDD Mockito 프레임워크를 사용해서 조금 더 자연스러운 API 네이밍으로 프레임워크를 사용할 수 있다테스트 간의 독립성을 보장하자 테스트에서 전역 변수를 정의해서 사용하는 것은 권장하지 않는다@BeforeEach또는 @AfterEach 메서드를 사용한 레포지토리 클렌징@Transactional사용 Test Fixture용 클래스를 따로 분리해서 사용하는 것은 권장하지 않는다Test Fixture를 @BeforeEach를 사용한 셋업 메서드에서 사용하는 경우, 중복 제거보다 해당 테스트에 해당 내용을 알아야하는지 고려해보고 적용하자테스트 내용은 동일한데 입력값만 변경해보면서 테스트 해보고 싶으면 @ParameterizedTest 사용private메서드에 대한 테스트가 필요하다면 해당 메서드의 책임을 분리할지 고민해본다단순히 테스트하기 위해서 public으로 열어두는 것은 권장하지 않는다 Q. REST Docs vs Swagger의 차이는?REST Docs테스트를 통과해야 문서가 만들어지기 때문에 신뢰도가 높다프로덕션 코드에 비침투적이다코드의 양이 많고 설정이 상대적으로 어렵다Swagger적용이 쉽다문서에서 바로 API 호출이 가능하다애노테이션을 달아줘야 하기 때문에 프로덕션 코드에 침투적이다🤔 회고워밍업 클럽의 마지막 주차가 되었다. 강의 양이 많아도 내가 정말 필요한 내용을 담아서 만들어져있어서, 시간 가는 줄 모르고 시청했다.강의와 미션을 따라가면서 학습에 많은 도움을 받았다. 만약 워밍업 클럽 3기가 있다면 다시 참가할 예정이다.지금까지 학습 내용을 다시 복습해보고 더 나아가서 프로젝트에 적용하는 것이 목표이다. 🔍 참고Practical Testing: 실용적인 테스트 가이드
백엔드
・
테스트코드
・
워밍업클럽2기
・
백엔드
・
발자국
・
4주차
・
회고
2024. 10. 25.
0
[워밍업 클럽 2기] Day 18 - 모킹 애노테이션의 종류, 테스트 내용 배치
워밍업 클럽 2기: Clean Code & Test Code의 Day 18 미션입니다. 🎯 미션 11. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이를 한번 정리해 봅시다. @MockMockito의 기본 모킹 애너테이션Mock 객체를 만들어 해당 객체의 메서드 호출에 대해 미리 정의된 값을 반환하도록 설정 가능(stub)Mock 객체는 실제 메서드를 호출하지 않고 동작만 시뮬레이션 한다@MockBeanMock 객체를 빈으로 등록합니다. 이는 테스트 대상 클래스가 의존성 주입을 통해 해당 Mock 빈을 받을 수 있도록한다.보통 @SpringBootTest나 @WebMvcTest와 같은 Spring 컨텍스트와 함께 사용되는 경우에 적합하다 @SpyMockito에서 객체의 일부 메서드만 모킹하고 나머지는 실제 메서드를 호출할 수 있다객체의 일부 기능만 변경하여 테스트하고 싶은 경우 사용한다실제 객체가 만들어져서 사용된다doReturn().when.() 사용SpyBean부분 모킹을 위해 스프링 컨텍스트에 등록된 실제 빈을 Spy로 대체한다실제 빈의 일부 메서드만 모킹하고, 나머지는 실제 메서드를 호출하게 할 때 유용하다@InjectMocks테스트 클래스에 정의된 @Mock 또는 @Spy로 선언된 객체를 주입하여, 대상 클래스의 의존성을 자동으로 설정한다 🎯 미션 22. 아래 3개의 테스트가 있습니다. 내용을 살펴보고, 각 항목을 @BeforeEach, given절, when절에 배치한다면 어떻게 배치하고 싶으신가요? (@BeforeEach에 올라간 내용은 공통 항목으로 합칠 수 있습니다. ex. 1-1과 2-1을 하나로 합쳐서 @BeforeEach에 배치) As-Is@BeforeEach void setUp() { ❓ } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { 1-1. 사용자 생성에 필요한 내용 준비 1-2. 사용자 생성 1-3. 게시물 생성에 필요한 내용 준비 1-4. 게시물 생성 1-5. 댓글 생성에 필요한 내용 준비 1-6. 댓글 생성 // given ❓ // when // then - 검증 } @DisplayName(""사용자가 댓글을 수정할 수 있다."") @Test void updateComment() { 2-1. 사용자 생성에 필요한 내용 준비 2-2. 사용자 생성 2-3. 게시물 생성에 필요한 내용 준비 2-4. 게시물 생성 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 2-7. 댓글 수정 // given ❓ // when ❓ // then - 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { 3-1. 사용자1 생성에 필요한 내용 준비 3-2. 사용자1 생성 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 3-6. 사용자1의 게시물 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 3-9. 사용자2가 사용자1의 댓글 수정 시도 // given ❓ // when ❓ // then - 검증 } 다음은 미션을 수행한 To-Be 입니다.To-Be@BeforeEach void setUp() { 1-1. 사용자 생성에 필요한 내용 준비, 2-1. 사용자 생성에 필요한 내용 준비, 3-1. 사용자1 생성에 필요한 내용 준비 3-3. 사용자2 생성에 필요한 내용 준비 1-3. 게시물 생성에 필요한 내용 준비, 2-3. 게시물 생성에 필요한 내용 준비, 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-2. 사용자 생성 1-4. 게시물 생성 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then - 검증 } @DisplayName(""사용자가 댓글을 수정할 수 있다."") @Test void updateComment() { // given 2-2. 사용자 생성 2-4. 게시물 생성 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then - 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-2. 사용자1 생성 3-4. 사용자2 생성 3-6. 사용자1의 게시물 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then - 검증 }고려한 내용@BeforeEach()에는 각 테스트에서 반복되지만, 검증하는 대상과는 직접적인 관련이 없는 공통 준비 사항을 처리하려고 했다. 여기서 준비하는 내용은 없어도 각 테스트를 이해할 수 있어야 하고, 각 내용이 변경되어도 각 테스트는 정상적으로 수행될 수 있어야 한다.when에는 각 테스트에서 검증하는 행위만을 배치시켰다 🔍 참고Practical Testing: 실용적인 테스트 가이드
백엔드
・
워밍업클럽2기
・
테스트코드
・
Day18
・
모킹