블로그

영후이

[인프런 워밍업 클럽 3기] 백엔드 발자국 2주차

📒 2주차에 배운 내용 📌 Controller, Service , Repository , DTO 개발과 테스팅, 그리고 Tymeleaf fragments 에 대해 학습하는 시간이였다.✏ 강의 중에 다뤘던 PresentationService 테스트 @DisplayName("활성화된 Introduction 만 조회하는데 성공한다. ") @Test fun testGetIntroductions() {/* given */ val introductions = mutableListOf<Introduction>() (1..DATA_SIZE).forEach { introductions.add(Introduction(content = "$it", isActive = it % 2 == 0)) } val activeIntroductions = introductions.filter { it.isActive } Mockito.`when`(presentationRepository.getActiveIntroductions()).thenReturn(activeIntroductions) /* when */ val introductionDTOs = presentationService.getIntroductions() /* then */ assertThat(introductionDTOs).hasSize(DATA_SIZE / 2) introductionDTOs.forEach { assertThat(it.content.toInt()).isEven() } } @DisplayName("활성화된 Link 만 조회하는데 성공한다. ") @Test fun testGetLinks() {/* given */ val links = mutableListOf<Link>() (1..DATA_SIZE).forEach { links.add(Link(name = "$it", content = "$it", isActive = it % 2 != 0)) } val activeLinks = links.filter { it.isActive } Mockito.`when`(presentationRepository.getActiveLinks()).thenReturn(activeLinks) /* when */ val linkDTOs = presentationService.getLinks() /* then */ var expectedSize = DATA_SIZE / 2 if (DATA_SIZE % 2 != 0) expectedSize += 1 assertThat(linkDTOs).hasSize(expectedSize) linkDTOs.forEach { assertThat(it.content.toInt()).isOdd() } } ✏ Repository 성능 개선 -> N + 1 해결하기 (fetch join)@Repository interface ProjectRepository: JpaRepository<Project, Long> { @Query("select distinct p from Project p left join fetch p.details where p.id = :id") override fun findById(id: Long): Optional<Project> }📌 JPQL fetch Joinspring: application: name: kotlin-portfolio jpa: database: h2 open-in-view: false show-sql: true hibernate: ddl-auto: create properties: hibernate: format_sql: true default_batch_fetch_size: 10 # batch size 조절 📌`application.yml` 에서 batch size 설정 ✏ Mocking 을 활용한 Controller 테스트val logger = KotlinLogging.logger {} @AutoConfigureMockMvc @SpringBootTest @DisplayName("[API 컨트롤러 테스트]") class PresentationApiControllerTest ( @Autowired private val mockMvc: MockMvc, ){ @DisplayName("Introductions 조회") @Test fun testGetIntroductions() { /* given */ val uri = "/api/v1/introductions" /* when */ val mvcResult = performGet(uri) val contentAsString = mvcResult.response.contentAsString val jsonArray = JSONArray(contentAsString) /* then */ assertThat(jsonArray.length()).isPositive() } @DisplayName("Links 조회") @Test fun testGetLinks() { /* given */ val uri = "/api/v1/links" /* when */ val mvcResult = performGet(uri) val contentAsString = mvcResult.response.contentAsString val jsonArray = JSONArray(contentAsString) /* then */ assertThat(jsonArray.length()).isPositive() } @DisplayName("Resume 조회") @Test fun testGetResume() { /* given */ val uri = "/api/v1/resume" /* when */ val mvcResult = performGet(uri) val contentAsString = mvcResult.response.contentAsString val jsonObject = JSONObject(contentAsString) /* then */ logger.info{jsonObject.optJSONObject("experiences")} assertThat(jsonObject.optJSONArray("experiences").length()).isPositive() assertThat(jsonObject.optJSONArray("achievements").length()).isPositive() assertThat(jsonObject.optJSONArray("skills").length()).isPositive() } private fun performGet(uri: String): MvcResult { return mockMvc .perform (MockMvcRequestBuilders.get(uri)) .andDo(MockMvcResultHandlers.print()) .andReturn() } }📌 2주차 미션 1 대 다 관계를 갖는 테이블 설계하기 ✔Rest API 를 설계하기✔

한선규

[인프런 워밍업 클럽 3기 - CS] 2주차 발자국

학습 내용 회고: 이번 2주차는 운영체제를 공부하며 정말 재미를 느꼈습니다. 평소에 윈도우 설정을 보면서 그냥 넘어갔던 용어들 ex.조각 모음 같은 용어의 뜻을 알게 되어 너무 재밌게 수강했습니다.   1강 프로세스 간 통신프로세스 간 통신(Inter-Process Communication, IPC)은 같은 컴퓨터 안에서 프로세스들끼리 데이터를 주고받거나, 네트워크로 연결된 다른 컴퓨터의 프로세스와 데이터를 주고받는 기술이다.한 컴퓨터 내에서의 통신 방법파일(File): 여러 프로세스가 하나의 파일을 읽고 쓰면서 데이터를 공유하는 방식.파이프(Pipe): 운영체제가 제공하는 파이프를 통해 데이터를 주고받는 방식.쓰레드(Thread): 같은 프로세스 내에서 공유하는 CODE, DATA, HEAP 영역 중 DATA와 HEAP을 이용해 통신하는 방식.네트워크를 이용한 통신 방법소켓(Socket) 통신: 네트워크를 통해 데이터를 주고받는 방식.원격 프로시저 호출(RPC, Remote Procedure Call): 네트워크를 통해 다른 컴퓨터의 함수를 호출하는 방식.2강 공유자원과 임계구역프로세스 간 통신을 할 때 여러 프로세스가 공동으로 사용하는 변수나 파일을 공유자원(Shared Resource)이라고 한다.문제점: 동기화(Synchronization) 문제공유자원에 여러 프로세스가 동시에 접근하면 실행 순서에 따라 결과가 달라질 수 있다.컨텍스트 스위칭(Context Switching)으로 인해 실행 순서를 예측하기 어렵다.→ 이를 해결하려면 임계구역(Critical Section) 개념이 필요하다.공유자원 사용 시 발생하는 문제경쟁조건(Race Condition): 여러 프로세스가 동시에 공유자원에 접근하면 충돌이 발생할 수 있음.임계구역 문제 해결을 위한 상호 배제(Mutual Exclusion) 메커니즘임계구역에는 동시에 하나의 프로세스만 접근 가능해야 한다.여러 프로세스가 접근을 요청해도 한 번에 하나만 들어갈 수 있어야 한다.임계구역에 들어간 프로세스는 최대한 빨리 나와야 한다.3강 세마포어(Semaphore)세마포어는 상호 배제(Mutual Exclusion) 메커니즘 중 하나로, 공유자원에 대한 접근을 조절하는 역할을 한다.세마포어 개념프린터 방 예시:공유자원: 프린터프로세스: A, B대기 장소: 대기 큐열쇠 관리자: 운영체제열쇠: 세마포어세마포어는 프로세스가 공유자원에 접근하기 전에 획득하고, 사용이 끝나면 해제하는 방식으로 동작한다.4강 모니터(Monitor)세마포어의 단점을 보완한 상호 배제 메커니즘으로, 운영체제가 아닌 프로그래밍 언어 차원에서 지원하는 동기화 기법이다.모니터의 특징세마포어처럼 wait(), signal()을 직접 호출할 필요 없이 언어 차원에서 동기화 기능을 제공한다.더 안전하고 직관적으로 동기화 코드를 작성할 수 있다.예시: Java에서 synchronized 키워드를 사용하면 동시에 여러 프로세스가 같은 메서드를 실행할 수 없다.예시위 코드에서 프로세스 A가 increase() 메서드를 실행 중이면, 프로세스 B는 decrease()를 실행할 수 없다.결론 모니터는 세마포어보다 더 직관적이고 안전한 동기화 메커니즘을 제공하여, 동기화 코드를 쉽게 작성할 수 있도록 해준다. 데드락(교착상태)여러 프로세스가 서로 다른 프로세스의 작업이 끝나길 기다리다 아무도 작업을 진행하지 못하는 상황을 교착상태라 한다.ex. 프로세스A: 프로세스B가 자원을 줘야 실행 됨 프로세스B: 프로세스C가 자원을 주길 기다리고 있음. 프로세스C: 프로세스 A가 자원 주면 지원해주겠음. 교착상태의 발생 원인은 공유자원 때문이다.교착상태의 필요조건 4가지(모두 충족해야함)상호배제(어떤 프로세스가 리소스를 점유했다면 그 리소스는 다른 프로세스에게 공유 되면 안된다.)비선점(프로세스 A가 리소스를 점유하고 있는데 프로세스 B가 리소스를 빼앗을 수 없어야함.)점유와 대기(어떤 프로세스가 리소스 A를 점유하고 있는 상태에서 리소스 B를 원하는 상태)(오른쪽 포크를 쥔 상태에서 왼쪽 포크를 원하는 상태)원형 대기(점유와 대기를 하는 프로세스들의 관계가 원형을 이루고 있어야한다.)(1번은 자원이 공유될 수 있는지, 2번은 점유된 리소스를 빼앗을 수 있는지)교착상태를 예방하는 방법은 너무 비효율적이었다.그래서 교착상태에 빠졌을 때 해결방법을 알아보겠다.교착상태 회피(Deadlock avoidance)운영체제가 프로세스들에게 자원을 할당할 때 어느정도 자원을 할당해야 교착상태에 이르는지 파악하고 발생하지 않는 수준의 자원을 할당한다.교착상태 회피는 할당된 자원의 수를 기준으로 안정 상태와 불안정 상태로 나뉜다.운영체제는 최대한 안정 상태를 유지하려고 자원할당을 한다.불안정상태여도 교착상태에 무조건 빠지는 것이 아닌 확률이 높아지는 것.(은행원 알고리즘)운영체제는 프로세스들에게 자원을 할당하기 전에 자원을 얼마나 가지고 있는지 즉 총 자원을 알고있다.프로세스들은 자기가 필요한 자원의 최대 숫자를 운영체제에게 알려줘야함. 이를 최대 요구 자원 이라 함.안정상태시스템의 총 자원=14 사용가능한 자원=2프로세스 최대 요구 자원 현재 할당된 자원 요청이 예상되는 자원 P1 9 5 4 P2 6 4 2 P3 4 3 1이 상황에서 P1이 4개를 요구하면 요구를 취소하고 P2에게 빌려줌.그 후 P2가 작업을 마치고 6개를 반납함 so P1, P3 요구 전부 가능.불안정상태시스템의 총 자원=14 사용가능한 자원=1프로세스 최대 요구 자원 현재 할당된 자원 요청이 예상되는 자원 P1 9 7 2 P2 6 4 2 P3 4 2 2P1, P2, P3 의 요청 전부 불가능함.지금처럼 불안정상태라해도 모든 프로세스가 최대 요구 자원을 요구하지 않는 이상 교착상태에 빠지진 않지만 요구한다면 교착상태에 빠진다.이는 비효율적이다.교착상태를 어떻게 검출해낼까?가벼운 교착 상태 검출(프로세스가 일정시간 작업을 진행하지 않는다면 교착상태가 발생했다 간주& 해결)(해결: 일정 시점마다 체크포인트를 만들어 작업을 저장하고 타임아웃으로 교착상태가 발생했다면 마지막으로 저장했던 체크포인트로 롤백하는 것)무거운 교착 상태 검출(자원할당 그래프를 이용함, 현재 운영체제에서 프로세스가 어떤 자원을 사용하는지 지켜보고 교착상태가 발생했다면 해결한다. 그래프를 보고 HOW? ,그래프를 보고 순환 구조를 파악한 뒤 교착상태를 발생시킨 프로세스를 강제 종료 시킴. 다시 실행시킬 때 체크포인트로 롤백시킴)(이는 주기적으로 자원할당 그래프를 검사해야 하기 때문에 오버헤드가 발생함)(하지만 가벼운 교착 상태 검출로 검출 될 수 있는 억울하게 종료되는 프로세스는 발생하지 않는다.)컴파일과 프로세스1. 프로그래밍 언어: 컴파일 언어 vs 인터프리터 언어프로그래밍 언어는 컴파일 언어와 인터프리터 언어로 구분할 수 있다.컴파일 언어개발자가 작성한 코드를 컴파일 과정을 거쳐 실행 파일(기계어)로 변환한다.컴파일 과정에서 문법 오류를 검사하고, CPU에서 처리 가능한 기계어로 변환하므로 실행 속도가 빠르다.인터프리터 언어코드를 미리 기계어로 변환하지 않고, 실행 시 한 줄씩 해석하여 실행한다.실행 전 오류 검사를 하지 않으므로 실행 중 오류가 발생할 가능성이 높으며 속도가 느리다.2. 프로세스의 메모리 구조프로세스는 실행될 때 CODE, DATA, HEAP, STACK 영역으로 나뉜다.① 코드(Code) 영역실행해야 할 코드가 저장되는 공간.예시:ret = num1 + num2; ② 데이터(Data) 영역전역 변수나 정적 변수가 저장되는 공간.예시:int global_A = 1; int arr[10]; ③ 스택(Stack) 영역함수 호출 시 생성되는 지역 변수와 함수 호출 기록(스택 프레임)이 저장된다.함수가 종료되면 해당 스택 영역은 자동으로 해제된다.④ 힙(Heap) 영역실행 중 동적 메모리 할당이 이루어지는 공간.개발자가 직접 할당 및 해제해야 한다 (malloc, free 등 사용).3. 컴파일 언어의 실행 과정컴파일 언어로 작성된 코드가 실행 파일이 되기까지의 과정은 다음과 같다.#include <stdio.h> #define MY_NUMBER 100 int main() { int num1 = 50; printf("result: %d", num1 + MY_NUMBER); getchar(); return 0; } 실행 과정전처리기 (Preprocessor) → test.i#include <stdio.h>의 내용을 포함시키고, #define MY_NUMBER 100을 치환한다.코드에 있는 모든 주석을 제거한다.컴파일러 (Compiler) → test.sC 코드(test.i)를 어셈블리 코드로 변환한다.어셈블러 (Assembler) → test.o어셈블리 코드를 목적 파일(기계어)로 변환한다.링커 (Linker) → test.exe여러 목적 파일과 라이브러리를 합쳐 실행 파일(Executable)을 생성한다.실행 파일과 프로세스exe 파일에는 코드(Code) 영역, 데이터(Data) 영역이 명확하게 구분되어 있다.운영체제(OS)는 실행 파일을 읽어 새로운 프로세스를 생성하며:코드, 데이터를 프로세스 메모리에 로드.빈 상태의 스택(Stack)과 힙(Heap) 영역을 할당.PCB(Process Control Block) 생성 후 관리 가능하도록 설정.프로그램 카운터(PC)*를 코드 영역의 첫 번째 명령어 주소로 설정하여 실행을 시작한다.이러한 과정을 통해 프로세스가 실행되며, CPU가 이를 스케줄링하여 프로그램이 동작하게 된다. 메모리의 종류와 주소 체계1. 메모리의 종류컴퓨터에서 사용되는 주요 메모리는 다음과 같이 구분된다.1.1 레지스터 (Register)CPU 내부에 위치하며 가장 빠른 기억장소전원 차단 시 데이터가 사라지는 휘발성 메모리CPU의 비트 수(예: 32비트, 64비트)는 레지스터의 크기를 의미CPU는 연산 시 메인메모리(RAM)의 데이터를 레지스터로 가져와 계산 후 다시 메인메모리에 저장1.2 캐시 메모리 (Cache Memory)레지스터보다 느리지만 메인메모리보다 빠른 휘발성 메모리메인메모리 접근 속도를 개선하기 위해 사용CPU가 자주 사용할 것 같은 데이터를 미리 저장해 속도 차이를 줄임성능 향상을 위해 여러 단계(L1, L2 캐시 등)로 구성됨1.3 메인메모리 (RAM, Random Access Memory)운영체제와 프로세스가 실행되는 공간전원이 꺼지면 데이터가 사라지는 휘발성 메모리프로그램 실행 및 데이터 처리 속도에 직접적인 영향을 줌1.4 보조 저장장치 (HDD, SSD)전원이 차단되어도 데이터가 유지되는 비휘발성 메모리하드디스크(HDD)는 비교적 저렴하지만 속도가 느림솔리드스테이트드라이브(SSD)는 빠르지만 가격이 높음2. 메모리와 주소 체계운영체제는 메모리를 효과적으로 관리하기 위해 1바이트 단위로 구역을 나누고 각 구역에 **주소(Address)**를 부여한다.2.1 32비트 vs 64비트 CPU32비트 CPU레지스터 크기: 32비트연산 장치(ALU), 데이터 버스도 32비트다룰 수 있는 메모리 크기: 2^32=4GB64비트 CPU레지스터 크기: 64비트연산 장치(ALU), 데이터 버스도 64비트다룰 수 있는 메모리 크기 : 2^64 (거의 무한대)2.2 물리 주소와 논리 주소물리 주소 공간: 메모리를 실제로 연결하면 0x0번지부터 시작하는 주소 공간논리 주소 공간: 운영체제가 사용자 프로그램을 위해 제공하는 가상의 주소 공간사용자는 논리 주소만 인식하며, 운영체제가 이를 물리 주소로 변환운영체제 보호를 위해 **경계 레지스터(Boundary Register)**를 사용하여 프로세스가 메모리 접근 시 경계를 넘지 않도록 관리함2.3 절대 주소 vs 상대 주소절대 주소 (Absolute Address): 실제 메모리에서 사용되는 물리 주소상대 주소 (Relative Address): 프로그램이 실행될 때 기준이 되는 시작 주소를 기반으로 한 주소프로그램 실행 시 **재배치 레지스터(Relocation Register)**를 사용해 논리 주소를 절대 주소로 변환2.4 메모리 주소 변환 예시사용자가 논리 주소 0x100의 데이터를 요청CPU가 메모리 관리자에게 0x100번지 데이터를 요청메모리 관리자는 **재배치 레지스터 값(예: 0x4000)**을 더해 **절대 주소 0x4100*의 데이터를 가져옴프로그램 시작 주소가 변경되더라도 재배치 레지스터 값만 수정하면 됨메모리 할당 방식과거 유니프로그래밍 환경에서는 메모리보다 큰 프로그램을 실행할 때 필요한 부분만 메모리에 올리고, 나머지는 하드디스크에 저장하는 메모리 오버레이 기법을 사용했다. 이를 통해 큰 프로그램을 여러 조각으로 나누어 일부만 실행하며, 나머지는 하드디스크의 스왑 영역에 저장했다.현대의 멀티프로그래밍 환경에서는 메모리 할당 방식이 **가변 분할 방식(세그멘테이션)**과 **고정 분할 방식(페이징)**으로 나뉜다.1. 가변 분할 방식 (세그멘테이션)프로세스의 크기에 따라 메모리를 동적으로 나누는 방식하나의 프로세스가 메모리에 연속된 공간에 할당됨 (연속 메모리 할당)✅ 장점낭비되는 공간인 내부 단편화가 발생하지 않음❌ 단점외부 단편화가 발생할 수 있음2. 고정 분할 방식 (페이징)프로세스의 크기와 관계없이 일정한 크기의 블록(페이지)로 나누어 메모리에 할당하나의 프로세스가 메모리 내 비연속적인 공간에 할당됨 (비연속 메모리 할당)✅ 장점구현이 간단하고 오버헤드가 적음❌ 단점사용되지 않는 공간이 발생하여 내부 단편화가 많음메모리 단편화 문제와 해결 방법외부 단편화프로세스가 종료된 후 남은 메모리가 조각나서, 새로운 프로세스가 올라갈 수 없는 현상해결 방법: **조각 모음(Compaction)**을 통해 단편화된 메모리 공간을 정리하지만 조각 모음 과정에서 오버헤드(추가적인 연산 비용)가 발생내부 단편화프로세스 크기보다 큰 고정된 메모리 블록을 할당하면서 사용되지 않는 공간이 생기는 현상해결 방법:할당되는 블록 크기를 조정하여 내부 단편화를 최소화버디 시스템을 사용하여 효율적인 메모리 할당버디 시스템2의 승수 단위로 메모리를 분할하여 할당하는 방식프로세스의 요청 크기에 가장 적합한 크기의 블록을 할당하여 외부 단편화를 방지하지만 내부 단편화는 일부 발생할 수 있음예시2048B(2^11)의 메모리가 있음500B 크기의 프로세스 A가 메모리를 요청512B(2^9) 크기의 블록을 할당이처럼 프로세스 크기에 맞게 할당되며, 불필요한 공간 낭비를 줄일 수 있음.현대의 메모리 관리 방식현재는 가변 분할(세그멘테이션)과 고정 분할(페이징) 방식을 조합하여 사용한다.이를 통해 내부·외부 단편화 문제를 최소화하면서도 효율적인 메모리 활용이 가능하다.

Versa

[3기] 워밍업 클럽-백엔드-code 2주차 발자국

미션 회고DAY7 미션은 스터디카페 코드를 추상화를 진행하는 것이었는데 거의 10줄도 바꾸지 못했다.이것저것 해야될 것 같고 하고 싶은건 많은데 코드로 막상 옮기려니 루미큐브를 하듯이다 벌려놓다가 마지막 하나가 부족해서 다시 처음으로 rollback 을 해야하는 것의 반복이었다.아직 바쁘다는 핑계로 한두번 손을 대고는 더 못댔다.그래도 아예 시작을 못할뻔 했는데 조금이라도 적용해보려고 노력한 내 자신에게 심심한 박수를 주었다.다음에 다시 할때는 한 클래스라도 더 추상화할 수 있을 것이라 생각한다.회고사실 강의도 섹션 5부터는 앞서가는 사람을 쫓아가려는 느낌으로 강의를 들었다. 그래서 그런지 DAY7 과제를 할때 내 생각만큼 추상화를 진행할 수 없었다. 영어를 배울대 읽기와 듣기가 되어도 쓰기와 말하기와 같이 출력하는 것은 다르듯이 실제로 코드를 적용하는 것은 쉽지 않은 일이었다.아직은 읽기와 듣기를 위해 열심히 지식을 입력하는 단계라고 생각한다. 이번 워밍업에서 한번에 다 이해할 수 있을 것이라 생각하지말고 한번 듣고 다음에 또 복습하고 적용해보는 시간을 꼭 가져야겠다.이번 발자국은 남기기 위해 작성했다면 다음 발자국은 남기고 싶어서 남기는 발자국이었으면 좋겠다.

백엔드백엔드워밍업클린코드

노을

[인프런워밍업클럽] 2주차 발자국 미션

섹션4 프로세스 동기화유닛 1 프로세스간 통신프로세스는 독립적으로 실행 or 다른 프로세스와 데이터를 주고 받으며 통신통신은 한 컴퓨터 내에서 실행되고 있는 다른 프로세스와 할 수도 있고, 네트워크로 연결된 다른 컴퓨터에 있는 프로세서와 할 수 도 있음종류한 컴퓨터 내에서 통신파일과 파이프파일통신을 하려는 프로세스들이 하나의 파일을 이용해 읽고 쓰는 방법파이프운영체제가 생성한 파이프를 이용해 데이터를 읽고 쓰는 방법스레드코드, 데이터, 힙 영역을 공유하고 스택만 각자 자기의 것을 가지고 있음데이터 영역에 있는 전역변수나 힙을 이용하면 통신이 가능네트워크운영체제가 제공하는 소켓통신이나 다른 컴퓨터에 있는 함수를 호출하는 RPC(원격 프로시저 호출)를 이용해 통신유닛2 공유자원과 임계구역공유자원프로세스 간 통신을 할 때 공동으로 이용하는 변수, 파일문제공유 자원은 여러 프로세스가 공유하고 있기 때문에 각 프로세스의 접근 순서에 따라 결과 달라짐컨텍스트 스위칭으로 시분할 처리를 하기 때문에 어떤 프로세스가 먼저 실행되고 어떤 프로세스가 나중에 실행되는지 예측하기 힘듦연상결과를 예측하기 힘들고 여기에 발생한 문제를 동기화 문제라고 함예) 게임을 예시로 듦캐릭터 총 체력 100, 현재 체력 20지금은 적에게 공격을 받고 있고 플레이어는 죽지 않기 위해 물약을 먹음이때 물약을 먹는 코드와 적에게 공격받는 코드에서 발생할 수 있는 동기화 문제를 살펴봄두 가지 코드가 동시에 실행됐는데 CPU 스케줄러에 의해 공격받는 코드가 먼저 실행됐다고 가정두번째임계구역여러 프로세스가 동시에 사용하면 안되는 영역경쟁조건공유자원을 서로 사용하기 위해 경쟁하는 것임계구역 문제 해결 방법상호배제의 메커니즘이 필요함요구사항주어진 시간에 항상 하나의 프로세스만 임계구역에 접근 가능동시에 여러개의 요청이 있더라도 하나의 프로세스만 진입하도록 허용임계구역에 들어간 프로세스는 최대한 빠르게 나와야함 → 다른 프로세스들이 오래 기다리기 떄문에유닛3 세마포어프로세스 : 프린트를 사용하려는 직원, 프린터는 여러 프로세스들이 같이 쓰고 있는 공유자원대기큐 : 프린트를 사용하기 위해 프로세스가 기다리는 공간운영체제 : 열쇠관리자세마포어 : 열쇠관리자가 들고 있는 열쇠, 정수형 변수사용법세마포어를 사용하면 공유자원에 여러 프소세스가 동시에 접근하지 못함 → 동기화 문제가 일어나지 않음세마포어는 실제로 여러개의 열쇠를 가질 수 있음정수형 변수, 공유자원이 2개라면 세마포어의 값은 2, → 열쇠 2개로 설정단점웨이트 함수와 시그널 함수의 순서를 이상하게 호출해서 세마포어를 잘못 사용할 수 있다는 가능성섹션5 데드락교착상태여러프로세스가 서로 다른 프로세스의 작업이 끝나기를 기다리다가 아무 작업도 진행하지 못하는 상태이유공유자원 때문에 발생어떤 자원을 여러개의 포로세스가 공유하지 않는다면 교착상태는 발생하지 않음예시) 식사하는 철학자필요조건상호배제 : 어떤 프로세스가 한 리소스를 점유했다면 그 리소스는 다른 프로세스에게 공유가 되면 안됨비선점 : 프로세스 A가 리소스르 점유하고 있는데 프로세스 B가 리소스를 뺏을 수 없음점유와 대기 : 어떤 프로세스가 리소스 A를 가지고 있는 상태에서 리소스 B를 원하는 상태여야만 함원형대기 : 점유와 대기를 하는 프로세스들의 관계가 원형을 이루고 있다는 것해결방법교착상태 회피프로세스들에게 자원을 할당할 때 어느 정도 자원을 할당해야 교착상태가 발생하는지 파악해서 교착상태가 발생하지 않는 자원을 할당함시스템의 총 자원 : 운영체제는 프로세스들에게 자원을 할당하기 전에 자기가 가지고 있는 전체 자원의 수를 알고 있어야 함최대 요구 자원 : 프로세스들은 각자 자기가 필요한 자원의 초대 숫자를 운영체제에게 알려줘야 함교착상태 알아내는 법가벼운 교착상태 검출타이머를 이용하는 방식, 프로세스가 일정시간동안 작업을 진행하지 않는다면 교착상태가 발생했다고 간주하고 교착상태를 해결무거운 교착상태 검출자원할당 그래프를 이용, 현재 운영체제에서 프로세스가 어떤 자원을 사용하는지 지켜보고 교착상태가 발생했다면 해결섹션 6 컴파일과 프로세스컴파일언어개발자가 코드 작성 → 컴파일 → 0과1 기계어로 실행파일 만듦인터프리터언어개발자가 작성한 코드를 미리 기계어로 만들지 않고 실행시 코드를 한 줄 씩 해석해 실행하는 언어프로세스의 메모리 구조스택 : 지역 변수, 함수 관련 값힙 : 실행 중 메모리 공간을 할당할 수 있는 유동적인 공간데이터 : 전역변수나 배열코드 : 실행해야 할 코드중간정리하드웨어, 운영체제 구조, 프로세스 회고운영체제는 강의를 듣고 복습을 하면 이해가 조금 잘 되는데 자료구조와 알고리즘은 이해하는데 시간이 많이 필요하다.. 복습을 더 많이 하고, 관련 서적들도 좀 찾아서 공부해야 할 것 같다

알고리즘 · 자료구조

워밍업 클럽 3기_PM/PO_2주차 발자국

강의 정보강의명: 시작하는 PM/PO들에게 알려주고 싶은, 프로덕트의 모든 것강사명: 김민우링크: https://inf.run/gQh4a강의 내용고객과 직접 만나야 하는 이유고객을 직접 만나는 것이 고객에 대한 이해를 높이는 가장 좋은 방법이다. 고객과 서비스에 대해 직접 문답하면서 고객이 가진 멘탈 모델을 정확하고, 구체적으로, 해상도 높게 가져갈 수 있다.중간 매개자로부터 받는 고객의 의견은 매개자의 시선에서 생략 및 요약되기 때문에 핵심 문제들을 놓치게 될 수 있다. 고객 리서치 방법의사결정을 명확하게 하고, 그에 맞는 리서치 방법과 계획을 세워야 한다.1:1 심층 인터뷰제품 사용 동기, 경험, 문제점 등에 대한 고객의 의견을 수집하는 방식이다.행동이 아니라 말에 의존해서 정보를 수집한다는 점을 유의해야 한다.인터뷰 대상은 10명을 기본으로 추천하나, 의사결정을 하기 충분한 답변을 모았다면 멈춰도 된다.사업>리서치>인터뷰로 질문을 만들고 준비해야 한다. 사업 상의 목적을 명확히 하고, 이를 알아가기 위해 필요한 리서치 방향을 생각한 뒤에 인터뷰 대상자가 답변 가능한 쉬운 질문으로 다듬어 가야 한다. 인터뷰 가이드 작성이 필요하다.답변은 유형화, 전반적인 테마를 발굴하여 중요 내용을 추려서 활용한다.사용성 테스트유저가 사용, 이해, 기능을 발견할 수 있는 제품이 좋은 제품이다.매몰 비용을 최소화하기 위해 사용성 테스트를 진행해야 한다.어림 법칙에 따라 5명 정도면 테스트는 충분하다. 그러나 유저 그룹에 여러 개라면 이를 고려하여 진행해야 한다.테스트 진행 시에는 2인 1조, 녹화 및 녹음이 필수이다.PM이 갖춰야 할 데이터 역량데이터 축적 역량과 활용역량이 필요하다.축적 역량은 로그 데이터를 설계하는 것을 의미한다.활용 역량은 지표를 이해하고 해석하는 것이다.데이터를 쪼개서 자세히 바라보는 연습이 필요하다.후기사용자의 의견을 듣기 위해 온라인 설문조사를 진행한 경험이 있었다. 그땐 가이드가 없어서 알고자 하는 목적에 집중해서 문항을 작성했는데, 지금 생각해 보니 너무 직접적인 질문이었던 것 같다. 목적을 선명히 해야 이후의 작업들을 펼치고 모을 수 있다는 것을 배웠다.국내가 아닌 국외 사용자들은 어떻게 심층 인터뷰나 사용성 테스트를 진행하는 게 좋을지 고민해 보게 되었다.데이터를 활용한 업무를 진행하기 위해서는 그런 환경이 놓인 회사에 가는 것이 필요하다는 이야기가 맘에 와닿았다. 데이터를 수집하기 위해서는 앞서 선행되어야 할 작업들이 많고, 후에 해석에도 많은 시간이 걸린다. 이를 낭비라고 생각하지 않는 회사로 가려면 면접에서 어떤 것을 확인해 봐야 하는 지 궁금해졌다. 미션앱 고도화 작업 이후에 특정 기능을 활용하는 사용자의 수가 감소한 사례가 있었다. 경험한 사례를 기준으로 고객 조사 방법을 설계해보려 한다.  

기획 · PM· PO워밍업클럽3기

안지수

[워밍업 클럽] CS 전공지식 2주차 발자국

운영체제프로세스 동기화공유 자원 : 프로세스 간 통신을 할 때 공동으로 이용하는 변수나 파일들임계 구역(Critical Section) : 여러 프로세스가 동시에 사용하면 안되는 영역경쟁 조건(Race Condition) : 공유 자원을 서로 사용하기 위해 경쟁하는 것상호 배제(Mutual Exclusion) : 임계 구역 문제 해결하기 위한 메커니즘상호 배제 요구사항1. 임계영역엔 동시에 하나의 프로세스만 접근한다.2. 여러 요청에도 하나의 프로세스의 접근만 허용한다.3. 임계구역에 들어간 프로세스는 빠르게 나와야한다.세마포어 : 상호 배제 메커니즘/정수형 변수/동기화 방지/잘못 사용할 가능성 있음모니터 : 세마포어 단점 해결한 상호 배제 메커니즘/프로그래밍 언어 차원에서 지원(예: 자바의 synchronized)데드락데드락(교착상태) : 여러 프로세스가 서로 다른 프로세스의 작업이 끝나기를 기다리다가 아무도 작업을 진행하지 못하는 상태/공유자원 때문에 발생교착상태의 필요조건 상호배제비선점점유와 대기원형 대기 교착상태 회피(Deadlock avoidance) - 은행원 알고리즘교착상태 검출가벼운 교착 상태 검출 : 타이머 이용무거운 교착 상태 검출 : 자원 할당 그래프 이용자료구조재귀어떠한 것을 정의할 때 자기 자신을 참조하는 것재귀 함수는 호출할 때마다 콜스택의 영역을 차지기저 조건(탈출 조건)이 반드시 있어야하위 문제의 결과를 기반으로 현재(상위) 문제 계산하는 데 유용(하향식 계산) 회고칭찬하고 싶은 점강의를 듣고 주력 언어인 자바로 복습하고 있다.아쉬웠던 점계획보다 진도가 밀려서 목표한 학습량을 채우지 못한 점보완하고 싶은 점공부한 내용을 나의 언어로 정리해서 발행하기(Output 만들기)

삼각커피포리

[인프런 워밍업 스터디 클럽 3기] 디자인 2주차 발자국

🐾 두번째 발자국개인적인 일정으로 평일에 시간이 많이 나지 않았고, 업데이트 된 입력 컴포넌트 강의 분량이 늘어나면서 시간이 많이 소요한 주차였다. 그래도 매일 조금씩 들었는데 이번주 분량을 모두 듣지 못 한 것 같아서 개인적으로 매우 아쉬운 주차였다. 📚 배운 점FrameAll 플러그인으로 모든 프레임을 쉽게 선택할 수 있다.아이콘은 오픈소스 아이콘을 사용하여 시간을 단축할 수 있다. 아이콘 미션아이콘이 이상한 경우 가장 추천하는 정리 방법은 Union → Flatten Selection아이콘을 10배 크기로 키워서 픽셀이 어긋난 부분을 화살표를 이용하여 위치를 조절하여 수정해두고 다시 10배 축소 시켜서 정리하면 깔끔하다.입력 컴포넌트 미션Q를 누르면 multi-edit이 가능해서 컴포넌트 편집 시 유용하다.버튼 스택 파트가 추가 되었는데 그 전에 버튼을 각각 만들어서 썼던 경험이 떠올라서 왜 이런 생각을 못했지 싶었다.한 번 컴포넌트를 만들어두면 다음 컴포넌트에서 반복적으로 사용되는 것들이 많다.😊 좋았던 점입력 컴포넌트 미션에서 각 컴포넌트 별로 설명과 만들어야 하는 Type, Style, State 같은 프로퍼티 값이 섹션에 쓰여 있어서 동영상을 보며 놓쳤던 것을 쓰여진 것을 보면서 확인 할 수 있었다.복습임에도 불구하고 내용이 업데이트 되어 새로 강의를 듣는 것과 같았다.전에는 라이브로 진행했던 앤트맨 작전이 강의에 업데이트 되어 복습할 수 있어서 좋았다. 😭 아쉬웠던 점매일매일 조금씩 강의를 듣고 multi-edit을 사용하며 과제를 했는데도 입력 컴포넌트 미션에 시간이 많이 소요되었다. (그래도 보너스 미션까지 완료했다!)이번주에는 미션4와 미션5를 해야하는데 시간이 부족하여 미션4만 수행할 수 있었다. 

UX/UI피그마Figma피그마배리어블

양종문

워밍업 클럽 3기 BE 클린코드&테스트 - 2주차 발자국

Reable Code 강의 요약섹션 6. 코드 다듬기주석의 양면성주석이 많다는 것은, 그만큼 비즈니스 요구사항을 코드에 잘 못 녹였다는 이야기.코드를 설명하는 주석을 쓰면, 코드가 아니라 주석에 의존한다. 주석에 의존하여 코드를 작성하면, 적절하지 않은 추상화 레벨을 갖게 되어 낮은 품질의 코드가 만들어진다.우리가 가진 모든 표현 방법을 총동원해 코드에 의도를 녹여내고, 그럼에도 불구하고 전달해야 할 정보가 남았을 때 사용하는 주석변수와 메서드의 나열 순서변수는 사용하는 순서대로 나열한다.공개 메서드를 상단에 배치하는 것을 선호하는 편.공개 메서드끼리도 기준을 가지고 배치하는 것이 좋다.상태 변경 >> 판별 >= 조회 메서드비공개 메서드는, 공개 메서드에서 언급된 순서대로 배치한다.공통으로 사용하는 메서드라면, (가장 하단과 같은) 적당한 곳에 배치한다.패키지 나누기패키지는, 문맥으로써의 정보를 제공할 수 있다.패키지를 쪼개지 않으면 관리가 어려워진다.패키지를 너무 잘게 쪼개도 마찬가지로 관리가 어려워진다.처음 만들 때부터 잘 고민해서 패키지를 나눠놓는 것이 제일 좋다.IDE의 도움 받기코드 포맷 정렬 (Ctrl + Alt + L)코드 품질 (Sonarlint)포맷 규칙 (.editorconfig)   섹션 7. 리팩토링 연습 스터디 카페 이용권 선택 시스템리팩토링 포인트추상화 레벨객체로 묶어볼만한 것은 없는지객체지향 패러다임에 맞게 객체들이 상호 협력하고 있는지SRP : 책임에 따라 응집도 있게 객체가 잘 나뉘어져 있는지DIP : 의존관계 역전을 적용할만한 곳은 없는지일급 컬렉션리팩토링 한 단계마다, 그 이유를 설명할 수 있어야 한다. 섹션 8. 기억하면 좋은 조언들능동적 읽기복잡하거나 엉망인 코드를 읽고 이해하려 할 때, 리팩토링하면서 읽기공백으로 단락 구분하기메서드와 객체로 추상화 해보기주석으로 이해한 내용 표기하며 읽기핵심 목표는 우리의 도메인 지식을 늘리는 것. 그리고 이전 작성자의 의도를 파악하는 것.오버 엔지니어링필요한 적정 수준보다 더 높은 수준의 엔지니어링은탄환은 없다클린 코드도 은탄환이 아니다.모든 기술과 방법론은 적정 기술의 범위 내에서 사용되어야 한다. 미션 (Day7)지금까지 배운 내용을 기반으로 리팩토링 진행결과: https://github.com/iPhone-design/readable-code/pull/1 과정추상화 레벨 리팩토링Early return 리팩토링DIP 리팩토링 아쉬운점새로운 도메인을 도출하는 과정에서 많은 어려움을 겪었습니다. 도메인 모델을 명확히 정의하고 적절한 개념을 추출하는 작업이 예상보다 복잡하고 까다로워 리팩토링에 많은 시간이 소요되었습니다. 또한, 리팩토링 과정에서 새로운 버그가 유입되거나 기존 기능이 손상되는 등의 부작용도 발생하여 기대만큼 만족스러운 결과를 얻지 못한 점이 아쉬웠습니다. 특히, 도메인을 명확히 정의하고 코드의 책임을 명확히 분리하는 클린 코드의 기본 원칙과 사고방식을 더욱 깊이 이해하고 습관화할 필요가 있다고 생각합니다. 앞으로는 작은 단위로 점진적으로 리팩토링을 진행하고, 자동화된 테스트를 적극적으로 활용하여 코드의 품질과 안정성을 높이도록 노력해야겠다 느꼈습니다.Pratical Testing 강의 요약섹션 2. 테스트는 왜 필요할까?우리가 얻고자 하는 것빠른 피드백자동화안정감테스트 코드를 작성하지 않는다면변화가 생기는 매순간마다 발생할 수 있는 모든 Case를 고려해야 한다.변화가 생기는 매순간마다 모든 팀원이 동일한 고민을 해야 한다.빠르게 변화하는 소프트웨어의 안정성을 보장할 수 없다.테스트 코드가 병목이 된다면프로덕션 코드의 안정성을 제공하기 힘들어진다.테스트 코드 자체가 유지보수하기 어려운, 새로운 짐이 된다.잘못된 검증이 이루어질 가능성이 생긴다.올바른 테스트 코드는자동화 테스트로 비교적 빠른 시간 안에 버그를 발견할 수 있고, 수동 테스트에 드는 비용을 크게 절약할 수 있다.소프트웨어의 빠른 변화를 지원한다.팀원들의 집단 지성을 팀 차원의 이익으로 승격시킨다.가까이 보면 느리지만, 멀리 보면 가장 빠르다.테스트는 귀찮다. 귀찮지만 해야 한다. 섹션 3. 단위 테스트단위 테스트작은 코드 단위를 독립적으로 검증하는 테스트검증 속도가 빠르고, 안정적이다.JUnit 5단위 테스트를 위한 테스트 프레임워크AssertJ테스트 코드 작성을 원활하게 돕는 테스트 라이브러리풍부한 API, 메서드 체이닝 지원테스트 케이스 세분화하기암묵적이거나 아직 드러나지 않은 요구사항이 있는가?테스트 케이스 세분화하기 (해피 케이스, 예외 케이스)테스트하기 어려운 영역을 구분하고 분리하기관측할 때마다 다른 값에 의존하는 코드현재 날짜/시간, 랜덤 값, 전역 변수/함수, 사용자 입력 등외부 세계에 영향을 주는 코드표준 출력, 메시지 발송, 데이터베이스에 기록하기 등 섹션 4. TDD: Test Driven DevelopmentTest Driven Development프로덕션 코드보다 테스트 코드를 먼저 작성하여 테스트가 구현 과정을 주도하도록 하는 방법론실패하는 테스트 작성 > 테스트 통과 최소한의 코딩 > 구현 코드 개선 테스트 통과 유선 기능 구현, 후 테스트 작성테스트 자체의 누락 가능성특정 테스트 케이스만 검증할 가능성잘못된 구현을 다소 늦게 발견할 가능성선 테스트 작성, 후 기능 구현복잡도가 낮은, 테스트 가능한 코드로 구현할 수 있게 한다.쉽게 발견하기 어려운 엣지(Edge) 케이스를 놓치지 않게 해준다.구현에 대한 빠른 피드백을 받을 수 있다.과감한 리팩토링이 가능해진다. 섹션 5. 테스트는 문서다.문서프로덕션 기능을 설명하는 테스트 코드 문서다양한 테스트 케이스를 통해 프로덕션 코드를 이해하는 시각과 관점을 보완어느 한 사람이 과거에 경험했던 고민의 결과물을 팀 차원으로 승격시켜서, 모두의 자산으로 공유할 수 있다.DisplayName을 섬세하게명사의 나열보다 문장으로테스트 행위에 대한 결과까지 기술하기도메인 용어를 사용하여 한층 추상화된 내용을 담기테스트의 현상을 중점으로 기술하지 말 것BDD(Behavior Driven Development) 스타일로 작성하기TDD에서 파생된 개발 방법함수 단위의 테스트에 집중하기보다, 시나리오에 기반한 테스트케이스(TC) 자체에 집중하여 테스트한다.개발자가 아닌 사람이 봐도 이해할 수 있을 정도의 추상화 수준(레벨)을 권장Given / when / then 발작국 2주차 회고이론으로만 접하고 있었던 부분을 실제 리팩토링 실습을 통해 더욱 피부로 와닿게 느낄 수 있었습니다. 특히, 직접 코드를 개선하는 과정에서 이론과 실무 간의 차이를 명확히 이해할 수 있었고, 클린 코드와 리팩토링의 중요성을 더욱 깊이 깨닫게 되었습니다. 또한 이번 주는 다른 개발자분들의 코드를 함께 리뷰하고 피드백을 주고받는 시간을 통해 다양한 접근법과 사고방식을 경험할 수 있었던 의미 있는 시간이었습니다. 혼자서는 생각하지 못했던 다양한 관점과 해결책을 알게 되었고, 협업을 통한 코드 리뷰의 중요성도 다시금 느끼게 되었습니다. 더불어 두 번째 강의에서 다루었던 테스트 코드의 중요성 또한 다시 한번 상기하게 되었습니다. 리팩토링 과정에서 테스트 코드가 얼마나 중요한 역할을 하는지 실질적으로 체감할 수 있었으며, 앞으로 테스트 코드 작성 능력을 향상시키기 위해 더욱 노력해야겠다는 생각이 들었습니다.

백엔드워밍업클럽

이제

[인프런 워밍업 클럽 스터디 3기 디자인] 2주차 발자국

2주 차 - 학습했던 내용 요약피그마 베리어블과 스타일 파운데이션 실습을 저번 주차에 이어서 작업했고 이번주는 컴포넌트들을 만드는 법에 대해 배웠t습니다. 목표한 진도까지는 아직 나가지 못해서 다음주에 조금 더 시간내서 과제랑 마무리해보려고 합니다. [주요 내용 복습] [이론📖] 간격 배리어블 이름, 구조 짜기일관성 있는 간격과 유연한 레이아웃을 구축하기 위해 그리드를 사용1.5배수 랜더링 이슈로 주로 8-point grid를 사용함일반적으로 더 작은 단위로 레이아웃을 정렬하고 싶은 경우 4-point grid를 사용함+1.5배수 랜더링 이슈란?1.5배수 렌더링 이슈란?1.5배수는 1픽셀을 1.5배 크기로 변환해야 하는데, 픽셀은 소수점 단위로 정확히 나눌 수 없는 정수 단위의 단위라서 렌더링 시 오류가 발생할 가능성이 높음.✅ 예제:10px 크기의 요소를 1.5배수 스케일로 렌더링 → 10 × 1.5 = 15px하지만 15px을 정확히 2배 또는 3배 해상도에 맞출 수 없음결과적으로 픽셀 보정(Anti-aliasing) 과정에서 모호한 렌더링(Blurry)이 발생그래서 8pt 그리드를 사용하는 이유8pt 그리드는 모든 크기를 8의 배수(8, 16, 24, 32...)로 설정하는 디자인 시스템.8의 배수를 사용하면, 2배수(2x)나 3배수(3x)와 같은 정수 배율에 정확히 맞출 수 있어서 렌더링 오류를 방지 가능!✅ 예제:8px → 2x 스케일 적용 → 8 × 2 = 16px (정확히 나눠짐)8px → 3x 스케일 적용 → 8 × 3 = 24px (정확히 나눠짐)8px → 1.5x 스케일 적용 → 8 × 1.5 = 12px (정수 단위로 맞춰짐)→ 1.5배수에서 발생하는 반올림 문제를 최소화할 수 있음.[이론&실습] 그리드 시스템과 반응형 기준점 설정하기 ✅break pointmobile(320-767)Count4 stretch Margin:16 Gutter: 16{FluidRange: 320-767} tablet(768-1023)Count8 stretch Margin:24 Gutter: 24{fluiderange: 768-1023} laptop(1024-1415)Count12 stretch Margin:24 Gutter: 24{fluiderange:1024-1415} desktop(1424-)Count12 center W:96 Gutter: 24{Fixedrange:1416-} Grid 적용 후 구현 plugin:Layout Grid Visualizer2주 차 - 회고2주 차에는 1주차 내용을 거의 복습하고 마무리했고 컴포넌트 수업도 조금 듣는 정도로 진도를 나갔습니다. 요즘 ai에게 물어보면서 수업을 정리해가고 있는데 더 머리에 잘 들어오고 좋은 것 같아 좋은 것 같은데 진도가 스케쥴 보다는 많이 뒤쳐지고 있는것 같아서 다음주에 조금 더 많이 진행해보려고 합니다. 아직 진행을 많이 못했지만 컴포넌트 실습 부분이 정말 유익한 것 같은데 많이 연습해봐야 할 것 같습니다. +완성된 배리어블을 Variable Print 로 문서화 했는데 완성작의 문서들이랑 조금 다른 것 같아서 다시 복습해봐야 할 것 같습니다. 인프런 워밍업 클럽 스터디 - 후기유익하고 과제일자가 정해져 있으니 확실히 스터디에 속도가 나는 것 같아서 좋은 것 같습니다. 앞으로도 열심히 진행해보려고 합니다.

UX/UIUXUIfigma디자인시스템베리어블

Berry

[인프런 워밍업 클럽 스터디 3기] 프로덕트 디자인 2주 차 발자국

2주 차 강의 회고아쉬웠던 점 / 보완하고 싶은 점 / 다음 주 계획수업과 과제를 더 열심히 해야하는데 그부분이 아쉽습니다. 다음 주에는 학습한 내용을 더 많이 반복하고, 실제 상황에 적용해보는 연습을 할 계획입니다. 이해안가는 부분도 다시 공부하고, 실무에서 어떻게 활용할 수 있을지 구체적으로 생각하며 학습할 예정입니다.2주 차 미션 해결 과정이번 미션에서는 주어진 강의 내용에 따라 컴포넌트 만들기 준비, 라이브러리 세팅, 디스플레이 및 입력 컴포넌트들을 활용한 실습을 진행했습니다. 반복 학습을 통해 더욱 확실하게 이해하였습니다.특히 버튼, 체크박스, 라디오 버튼, 스위치와 같은 기본적인 컴포넌트들을 실제로 사용하면서, 아이콘 등록과 UI 스타일링도 함께 실습한 점이 중요했습니다. 이러한 컴포넌트들은 실제 프로젝트에서 자주 사용되기 때문에, 실제 프로젝트에서 바로 적용할 수 있는 능력을 키우는 데 큰 도움이 되었습니다. 미션을 해결하는 과정에서 강의 내용을 실무에 바로 적용할 수 있도록 학습하는 점이 인상 깊었습니다.이번 주 학습을 통해 실무에서 사용할 수 있는 기술들을 체계적으로 연습했고, 앞으로도 더 깊이 있는 학습을 통해 실력을 쌓아 나갈 예정입니다. 2주 차 주요 학습 내용컴포넌트 만들기 준비: 기본적인 컴포넌트 구조 설계, 라이브러리 세팅입력 컴포넌트: 버튼, 체크박스, 라디오 버튼, 스위치 등디스플레이 컴포넌트: 아바타, 아코디언, 배지, 툴팁, 칩 등실제 활용: UI 요소를 실무에 맞게 커스터마이징하였습니다.이번 주 학습을 바탕으로, 다음 주에도 실무에서 바로 활용할 수 있는 능력을 키우기 위해 꾸준히 실습하고, 더 심화된 내용을 공부할 준비를 하려고 합니다.

UX/UI

jinwoo2511

CS 전공지식 스터디 3기 [2주차] 자료구조와 알고리즘 미션

CS 전공지식 스터디 3기 [2주차] 자료구조와 알고리즘 미션Q. 재귀함수에서 기저조건을 만들지 않거나 잘못 설정했을 때 어떤 문제가 발생할 수 있나요?A.재귀 함수란 자기 자신을 호출하는 함수를 재귀 함수라고 합니다.문제를 작은 부분으로 나누어 해결하는 방식으로, 주로 반복적인 구조의 문제를 해결할 때 사용됩니다.재귀 함수에서 기저 조건(Base Case)을 만들지 않거나 잘못 설정했을 때 발생하는 문제는무한 루프(무한 재귀 호출) 발생기저 조건이 없으면 함수가 끝없이 자기 자신을 호출하게 되어 스택 오버플로우(Stack Overflow)가 발생합니다.잘못된 결과 반환기저 조건이 부정확하면 예상한 결과를 얻지 못할 수 있습니다.Q. 0부터 입력 n까지 홀수의 합을 더하는 재귀 함수를 만들어보세요.function sumOdd(n){ // 재귀 로직 } console.log(sumOdd(10)) // 25 A.function sumOdd(n) { if (n <= 0) return 0; // 기저 조건 return (n % 2 === 1 ? n : 0) + sumOdd(n - 1); } console.log(sumOdd(10)); // 25 Q. 다음 코드는 매개변수로 주어진 파일 경로(.는 현재 디렉토리)에 있는 하위 모든 파일과 디렉토리를 출력하는 코드입니다. 다음 코드를 재귀 함수를 이용하는 코드로 변경해보세요.const fs = require("fs"); // 파일을 이용하는 모듈 const path = require("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("."); // 현재 경로의 모든 하위 경로의 파일, 디렉토리 출력 A.const fs = require("fs"); const path = require("path"); function traverseDirectory(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); traverseDirectory(filePath); // 재귀 호출 } else { console.log("파일:", filePath); } } } traverseDirectory("."); // 현재 경로의 모든 하위 파일과 디렉토리 출력

주이

[워밍업 클럽 3기] CS 2주차 - 발자국

재귀어떠한 것을 정의할 때 자기 자신을 참조하는 것재귀적으로 정의된 함수 → 재귀함수 콜스택함수가 호출되면서 올라가는 메모리 영역 → 스택이라고도 부름First In Last Outfor문으로 처리할 수 있는 작업을 재귀함수로 처리한다면 더 비효율적인 상황이 생김→ 재귀함수가 더 많은 메모리 공간 차지대신, 재귀함수를 사용하면 처리하기 쉬운 예도 있음. ex) 팩토리얼패턴 1. 단순 반복 실행반복문 구현보다 큰 이점은 없음. 콜스택 공간을 많이 차지해 오히려 성능 저하패턴 2. 하위 문제 결과를 기반으로 현재 문제 계산예) 팩토리얼, 하노이탑for 문을 이용한 계산 - 상향식 계산재귀를 이용해 하위 문제 계산 - 하향식 계산 (상향식도 구현 가능하지만 성능 발휘는 딱히 X)// 재귀를 이용한 상향식 계산 function factorial2(number, i = 1, sum = 1) { if (i > number) return sum; return factorial2(number, i + 1, sum * i); }  정렬 알고리즘버블 정렬(Bubble Sort)앞에 있는 숫자와 옆에 숫자를 비교해서 자리를 바꾸는 알고리즘장점: 이해 및 구현 간단단점: 성능이 좋지 않음성능 - O(n^2)(n-1) + (n-2) + (n-3) … + 2 + 1 → 등차수열n(n-1)/2 → (n^2 - n)/2 선택 정렬(Selection Sort)배열의 정렬되지 않은 영역의 첫 번째 원소를 시작으로 마지막 원소까지 비교 후 가장 작은 값을 첫 번째 원소로 가져옴장점: 이해 및 구현 간단단점: 성능이 좋지 않음성능 - O(n^2)(n-1) + (n-2) + (n-3) … + 2 + 1 → 등차수열n(n-1)/2 → (n^2 - n)/2

인프런 워밍업 클럽 BE-박우빈 클린코드&테스트 2주차 회고

직접 리팩토링 해보기첫 리팩토링은 절망적이었다.강의를 들을 때는 분명 과정들을 이해했고 어떻게 해야하는지 알았다고 생각했다. 하지만 막상 직접 리팩토링 해야할 코드를 마주하니 정말로 머리속이 새하얗게 변했다.나는 지금까지 동영상을 틀어놓고 영혼 없이 타이핑만 했는가? 2주의 시간은 어디로 갔는가.조금 진정하고 왜 이렇게 어려울까 고민해본 결과, 일단 내용이 어려워서는 아닌 것 같다. 들은 설명은 충분히 이해했고 다른 학습에서 본 코드에 적용해볼만하다 생각 했다. 제일 큰 원인은 내가 코드에 아직 익숙하지 않다는 것. 나는 아직 직접 코드를 짜본 경험이 매우 적다. 스스로 생각해서 작성한 코드보다 강의 듣고 따라 타이핑한 코드 양이 훨씬 많다. 직접 짜본 코드도 백지에서 요구사항을 스스로 분석해서 내 마음대로 만들었기 때문에 자유로웠다. 반면 이미 만들어진 코드를 보니 내가 파악하지 못하는 부분들이 많았다. 무슨 요구사항에 의해 이 코드가 작성 된 건지, 어떤 의도로 이런 클래스, 메서드가 생겼는지 직접 코드를 읽고 파악해야하는게 낯설었다. Readable Code, 이 강의의 목표를 다시 한번 느낄 수 있는 순간이었다.여차저차 미션은 제출했지만 만족스러운 학습은 아니었다. 때문에 미션의 피드백인 섹션 7은 잠시 접어뒀다. 리팩토링 부분을 다시 학습하고, 다시 미션을 수행한 다음 남은 강의를 수강해 완주할 예정이다. 테스트 코드테스트 코드 학습이 시작되었다. 테스트의 중요성은 들은 적이 많지만 언제나 뒷전이었다. 여전히 내용은 어렵지 않아 보인다. 이전 실패를 기억해 좀 더 실전적인 것에 집중하여 여러 검증 메서드들을 정리해보고 직접 테스트 코드를 작성해봐야한다.

백엔드

찬우 이

인프런 워밍업 클럽 3기 풀스택 - 2주차 발자국

2주차 학습 내용Part 1 - Git Repository 생성 및 초기 설정 진행create-next-app을 통해 초기 세팅을 했으며,이전에 TODO에서 했던 코드들을 일부 가져와서 빠르게 세팅함. Part 2 - UI 작업알게된 사실 - page.tsx에는 클라이언트 컴포넌트를 사용하면 좋지않다.그 이유는 나중에 메타데이터를 쓰고 하는데 그건 서버 컴포넌트에서만 돌아가기 때문에 피해줘야 한다.나는 평소 flex만 사용하고 grid는 잘 사용하지 않는다. 항상 쓰던것만 써서 그렇기도 하고 grid로 편하게 구현하는 것도 flex로 구현은 가능하기 때문에 그렇게 했다. 강의에서는 grid를 사용했고 디테일하진 않지만 간단하게 3단계로 반응형도 쉽게 구현되는 모습을 보고 grid를 다시보게 됨className="grid md:grid-cols-3 lg:grid-cols-4 grid-cols-2"그 이후로는 컴포넌트 별로 분리해서 퍼블리싱 작업을 구현했다. Part 3 - 파일 업로드 구현(Supabase Storage) 사진을 업로드 하는데 알 수 없는 에러가 있었고, 분명 코드도 다른부분이 없는데 문제가 생겨서 오랫동안 붙잡고 있었다.원인은 사진이름이 한글로된 경우 안되는 부분이였고, 잠시 오류 수정으로 고쳐서 한글이름으로 된 사진도 업로드가 가능하게 했다. 하지만 한글이름이 아닌 a__a__a같은 이름으로 저장되는 문제가 발생해서 이 문제는 추후 고쳐봐야 할 문제 같다.// actions/storageActions.ts function sanitizeFileName(fileName: string) { return fileName .normalize("NFKD") // 유니코드 정규화 .replace(/[^\w.-]/g, "_") // 특수 문자 제거 .replace(/\s+/g, "_") // 공백을 `_`로 변경 .toLowerCase(); // 소문자로 변환 } export async function uploadFile(formData: FormData) { const supabase = await createServerSupabaseClient(); const file = formData.get("file") as File | null; if (!file) { console.error("❌ 업로드할 파일이 없습니다."); throw new Error("파일이 없습니다."); } // 파일 이름을 안전한 형식으로 변환 const safeFileName = sanitizeFileName(file.name); console.log("✅ 변환된 파일 이름:", safeFileName); const { data, error } = await supabase.storage .from(process.env.NEXT_PUBLIC_STORAGE_BUCKET!) .upload(safeFileName, file, { upsert: true }); if (error) { console.error("❌ Supabase 업로드 실패:", error.message); throw new Error(error.message); } return data; }  Part 4 - 파일제거 구현, Darg & Drop, 멀티파일 업로드 구현Darg & Drop을 위해 설치해줌.  npm i --save react-dropzone이번주 미션 - 파일의 마지막 수정(업로드) 시간을 표시하는 기능을 추가하기!// components/dropbox-image.tsx <div>생성일: {formatDate(image.updated_at)}</div> 간단하게 이 부분 넣어서 해결함. 미션 이외로...- 강사님과 같은 코드로 하니까 생긴 에러가 있어서 코드를 약간 수정함.수정한 부분은 actions/storageActions.ts 의 uploadFile 부분임1⃣ 파일 필터링 (undefined 값 제거)✅ 첫 번째 코드 (위 코드) → undefined 또는 잘못된 파일 제거const files = Array.from(formData.entries()) .map(([name, file]) => file as File) .filter((file) => file instanceof File && file.name); // ✅ undefined 제거 filter()를 사용하여 undefined 또는 비정상적인 파일을 제거파일이 null이거나 undefined면 upload()에서 에러 발생 가능성이 있음 → 이를 방지❌ 두 번째 코드 (아래 코드) → 필터링 없음const files = Array.from(formData.entries()).map(([name, file]) => file as File); undefined 파일이 포함될 가능성이 있음 → 업로드 시 오류 발생 가능 2⃣ 파일명 변환 (sanitizeFileName)✅ 첫 번째 코드 (위 코드) → 파일명 변환 추가function sanitizeFileName(fileName: string) { return fileName .normalize("NFC") // ✅ 한글 깨짐 방지 .replace(/[^a-zA-Z0-9ㄱ-ㅎㅏ-ㅣ가-힣_.-]/g, "_"); // ✅ 특수 문자 제거 } const safeFileName = sanitizeFileName(file.name); 특수 문자, 공백 제거 (file.name을 정리)한글 깨짐 방지 (NFC 정규화)→ Supabase는 일부 특수 문자나 공백이 포함된 파일명을 허용하지 않으므로 안정적❌ 두 번째 코드 (아래 코드) → 원본 파일명 그대로 사용supabase.storage .from(process.env.NEXT_PUBLIC_STORAGE_BUCKET) .upload(file.name, file, { upsert: true }); 파일명을 그대로 사용하기 때문에, 특수 문자나 공백이 포함되면 Supabase에서 오류 발생 가능 3⃣ async 처리 및 오류 핸들링✅ 첫 번째 코드 (위 코드) → async 사용 및 오류 처리const results = await Promise.all( files.map(async (file) => { // ✅ async 사용 const safeFileName = sanitizeFileName(file.name); const { data, error } = await supabase.storage .from(process.env.NEXT_PUBLIC_STORAGE_BUCKET) .upload(safeFileName, file, { upsert: true }); if (error) { // ✅ 오류 처리 console.error("❌ Supabase 업로드 실패:", error.message); throw new Error(error.message); } return data; }) ); 각 파일 업로드가 비동기(async)로 처리됨오류 발생 시 console.error로 출력하고 예외 처리각 파일 업로드 후 결과(data) 반환❌ 두 번째 코드 (아래 코드) → 오류 핸들링 없음const results = await Promise.all( files.map((file) => supabase.storage .from(process.env.NEXT_PUBLIC_STORAGE_BUCKET) .upload(file.name, file, { upsert: true }) ) ); async 키워드 없이 바로 upload() 실행오류가 발생해도 catch되지 않으며, 전체 업로드가 실패할 가능성이 있음업로드 성공 여부를 확인할 방법 없음 (data를 반환하지 않음)  2주차 회고 2주차에는 중간점검을 하는 시간을 가졌다. 수강생들이 하고 싶었던 질문을 하나하나 답변해주시는 시간을 가져서 꽤 유용한 시간이였고, 더 열심히 하자는 마음을 다지는 계기가 되었다.첫주때보단 수퍼베이스에 적응을 하는거같다. 아직 친해지기에는 시간이 더 많이 필요할꺼 같긴한데 정처기 준비하고 CS 스터디 하고, 다른 프젝도 마무리 하고, 매일 알고리즘 문제도 풀고 있다보니 시간이 많이 부족한 것 같다.중간점검때 강사님께서 시간관리에 대한 얘기도 했었는데, 매우 동감하는 부분...시간 관리나 스케줄 관리를 잘 해야 할 것 같다.. 의욕만 앞서서 살짝 망하는거 같기도함.그래도 뭐 흥미있고 재미있으니까 만족한다.

풀스택풀스택미션인프런워밍업클럽supabasenext.js

jinwoo2511

CS 전공지식 스터디 3기 [2주차] 운영체제 미션

CS 전공지식 스터디 3기 [2주차] 운영체제 미션Q. FIFO 스케줄링의 장단점이 뭔가요?A.FIFO(First In, First Out) 스케줄링은 먼저 도착한 프로세스가 먼저 실행되는 방식의 스케줄링 알고리즘입니다.이는 큐(Queue) 구조를 사용하며, 도착한 순서대로 실행되기 때문에 공평하지만 비효율적인 경우가 발생할 수 있습니다. 장점:공정성: 먼저 도착한 프로세스를 먼저 처리하기 때문에 기아(Starvation) 현상이 발생하지 않음간단한 구현: 큐(Queue) 자료구조를 사용하여 구현이 간단함비선점(Non-Preemptive) 방식: 한 프로세스가 CPU를 점유하면 끝날 때까지 다른 프로세스가 실행되지 않음단점:긴 작업이 먼저 도착하면 대기 시간이 증가예를 들어, 긴 실행 시간을 가진 프로세스가 먼저 들어오면 뒤의 짧은 프로세스들이 오래 대기해야 함이를 Convoy Effect(호위 효과)라고 부름 응답 시간이 일정하지 않음짧은 작업이 있어도 먼저 도착한 긴 작업이 끝날 때까지 기다려야 함 FIFO 스케줄링 수행 과정P1 → P2 → P3 순서로 실행됨P1이 먼저 CPU를 점유하고 끝날 때까지 P2와 P3는 기다려야 함 Q. SJF를 사용하기 여러운 이유가 뭔가요?A.SJF(Shortest Job First) 스케줄링은 CPU 실행 시간이 가장 짧은 프로세스를 먼저 실행하는 방식입니다.즉, Burst Time(실행 시간)이 짧은 순서대로 프로세스를 실행하기 때문에 평균 대기 시간(AWT)이 최소화되는 장점이 있습니다. SJF 스케줄링의 종류비선점형 SJF (Non-Preemptive SJF)실행 중인 프로세스가 끝날 때까지 CPU를 점유 (중간에 빼앗기지 않음) 선점형 SJF (Preemptive SJF, SRTF: Shortest Remaining Time First)새로운 프로세스가 도착하면 현재 실행 중인 프로세스와 실행 시간을 비교하여 더 짧은 실행 시간이 남은 프로세스가 있으면 CPU를 빼앗김 실행 순서먼저 도착한 P1 실행 (7ms)다음으로 P3 실행 (1ms)P2 실행 (4ms)마지막으로 P4 실행 (4ms)SJF를 사용하기 어려운 이유실행 시간이 가장 짧은 작업을 먼저 실행해야 하는데, 프로세스의 CPU Burst Time(실행 시간)을 정확히 예측하기 어렵습니다.I/O Bound 프로세스와 CPU Bound 프로세스를 구분하기 쉽지 않습니다.비선점(Non-Preemptive) 방식이라 실시간 시스템에 적합하지 않을 수 있습니다. Q. RR 스케줄링에서 타임 슬라이스가 아주 작으면 어떤 문제가 발생할까요?A.RR(Round Robin) 스케줄링은 각 프로세스가 일정한 시간(Time Quantum) 동안만 실행되며, 시간이 지나면 다음 프로세스로 넘어가는 방식입니다.즉, 모든 프로세스가 공평하게 CPU를 사용할 수 있도록 설계된 선점형(Preemptive) 방식입니다.RR스케줄링의 타임 슬라이스가 아주 작으면 아래와 같은 문제가 발생합니다.Context Switching 증가:타임 슬라이스가 너무 작으면 프로세스가 자주 CPU에서 교체되므로 컨텍스트 스위칭(Context Switching) 비용이 증가하여 오버헤드가 커진다.CPU 사용률 저하:CPU가 실제 작업을 수행하는 시간보다 문맥 전환(Context Switching) 처리에 더 많은 시간을 사용하게 되어 효율성이 떨어진다.하지만 RR 스케줄링은 모든 프로세스가 공평하게 실행되고, 응답 시간이 빨라서 실시간 시스템에 적합하다는 장점이 있습니다. Q. 운영체제가 MLFQ에서 CPU Bound Process와 I/O Bound Process를 어떻게 구분할까요?A.MLFQ(Multi-Level Feedback Queue, 다단계 피드백 큐) 스케줄링은 여러 개의 큐를 사용하여 프로세스를 우선순위별로 분류하고, 프로세스의 실행 시간이나 행동 패턴에 따라 다른 큐로 이동시키는 방식입니다.즉, CPU 사용 시간에 따라 우선순위가 조정되며, 프로세스가 낮은 우선순위로 이동할 수도 있고 다시 높은 우선순위로 복귀할 수도 있는 유동적인 스케줄링 방식입니다.운영체제는 프로세스의 행동 패턴을 기반으로 CPU Bound Process와 I/O Bound Process를 구분합니다.CPU Bound Process:CPU를 오래 사용하는 프로세스계산량이 많고, 연산이 많은 작업 (예: 영상 처리, 데이터 분석)CPU를 길게 사용하여 타임 퀀텀을 초과하면 하위 큐로 이동 I/O Bound Process:I/O 작업(디스크 접근, 네트워크 요청 등)이 잦은 프로세스키보드 입력, 파일 읽기 등의 작업이 많음 (예: 웹 브라우저, 텍스트 편집기)자주 I/O 요청을 하면 다시 상위 큐로 이동즉 운영체제는 프로세스가 얼마나 자주 I/O 요청을 하는지 모니터링하며 CPU Bound와 I/O Bound를 자동으로 구분합니다.Q. 공유자원이란무엇인가요?A.공유 자원이란 여러 개의 프로세스가 동시에 접근할 수 있는 자원을 의미합니다.예시:메모리 (공유 메모리 영역)파일 시스템 (파일 접근)프린터, 네트워크 소켓 등 Q. 교착상태에 빠질 수 있는 조건은 어떤 것들을 충족해야 할까요?A.교착 상태는 4가지 조건을 모두 만족해야 교착 상태에 빠지게 됩니다.아래 4가지 중 한가지라도 만족하지 않는다면, 교착 상태에 빠지지 않게 됩니다.교착 상태 4가지 조건상호 배제 (Mutual Exclusion):한 번에 하나의 프로세스만 자원을 사용할 수 있어야 한다.점유와 대기 (Hold and Wait):하나의 자원을 점유한 프로세스가 다른 자원을 기다리는 상태여야 한다.비선점 (No Preemption):프로세스가 강제로 자원을 빼앗기지 않는다.순환 대기 (Circular Wait):프로세스들이 원형(사이클)으로 자원을 서로 점유하고 대기한다.

팥우유

[인프런 워밍업 클럽 Full Stack 3기] 2주차

1. 학습 내용1.1. Supabase Storage파일과 이미지를 저장하고 관리하기 위한 서비스 (아마존 S3와 유사)1.1.1. 주요 개념버킷(Buckets): 파일을 논리적으로 구분하는 컨테이너객체(Objects): 저장된 개별 파일정책(Policies): 파일에 대한 접근 권한 규칙 2. 미션2.1. 미션 내용파일 목록에서 각 파일의 "마지막 수정 시간"을 표시2.2. 미션 진행- 리액트 쿼리로 요청, 응답 받은 이미지 데이터 객체 내 update_at 키-값을 이미지 컴포넌트에 표시함으로써 작업을 진행했습니다.3. 추가 학습 및 적용 기술3.1. pnpm 도입과 경험npm의 문제점(패키지 중복 설치, 디스크 낭비)에 불편함을 느껴 이번 기회에 pnpm을 도입했습니다. 설치 속도가 확연히 빨라진 것을 체감할 수 있었습니다.3.1.1. npm과 pnpm의 주요 차이점저장 구조와 디스크 사용량npm: 프로젝트마다 의존성 중복 저장으로 디스크 낭비pnpm: 전역 저장소에 패키지를 한 번만 저장하고 심링크로 연결하여 공간 절약성능npm: 중복 다운로드로 인한 네트워크 부하 및 시간 소요pnpm: 공유 저장소와 링크 기반 구조로 설치 속도 향상, 병렬 처리 최적화3.2. material-tailwind 경고 제거material-tailwind 컴포넌트 사용 시 발생하는 경고 메시지를 d.ts 파일을 통해 제거했습니다. 이 방법이 안전한지 고민했지만, 큰 문제가 없다고 판단하여 적용했습니다. 인프런 커뮤니티의 질문과 답변이 해결에 도움이 되었습니다.3.3. supabase storage type 적용db type과 달리 storage type은 supabase cli를 통해 자동 생성할 수 없다는 점을 알게 되었습니다. 대신 `@supabase/storage-js` 플러그인을 통해 필요한 type을 활용할 수 있었습니다.// UploadedImage Component import { FileObject } from '@supabase/storage-js'; // ...existing code... export default function UploadedImage({ file: { name, updated_at }, }: { file: FileObject; }) { return (// component) }3.4. prettier 설정GitHub Copilot의 도움을 받아 Next.js 프로젝트에 적합한 옵션으로 설정했으며, prettier-plugin-tailwindcss를 통해 Tailwind 클래스 자동 정렬 기능을 추가했습니다.// .prettierrc { "singleQuote": true, "semi": true, "useTabs": false, "tabWidth": 2, "trailingComma": "es5", "printWidth": 80, "arrowParens": "avoid", "jsxSingleQuote": false, "bracketSpacing": true, "bracketSameLine": false, "htmlWhitespaceSensitivity": "css", "requirePragma": false, "insertPragma": false, "proseWrap": "preserve", "endOfLine": "auto", "plugins": [ "prettier-plugin-tailwindcss" ] }3.5. eslint 설정@tanstack/eslint-plugin-query를 도입하여 React Query 사용 시 모범 사례를 따르도록 설정했습니다. 이를 통해 쿼리 키 검증, 의존성 확인 등의 이점을 얻을 수 있었습니다.// .eslint.json { "plugins": ["@tanstack/query"], "extends": ["next/core-web-vitals", "plugin:@tanstack/query/recommended"] } 4. 아쉽게 적용하지 못한 기술아래 3 가지 항목들은 모두 조사, 기능 개발 계획, 프로젝트에 일부 적용까지 하기도 했으나 시간이 부족해 결국 완성되지 못한 기능들입니다.4.1. 한글 파일명 업로드 문제 해결Supabase Storage에서 한글 이름의 파일을 업로드할 수 없는 문제에 직면했습니다. 원인은 파일명 인코딩 과정이 없어서 발생한 문제였습니다. 두 가지 해결책을 구상했지만 시간 부족으로 완성하지 못했습니다.파일정보 DB 테이블 접근법: 파일명과 UUID를 매핑하여 DB에 저장하고, 실제 스토리지엔 UUID로 업로드하는 방식customMetadata 활용: Supabase Storage의 메타데이터 기능을 활용하는 방식4.2. 직접 Tailwindcss 컴포넌트 구현 시도material-tailwind 대신 Tailwindcss만으로 모든 컴포넌트를 스타일링해보고 싶었으나, 시간 부족으로 실현하지 못했습니다.4.3. 컴포넌트 구조 설계의 고민개발자 관점에서 명확하고 구분하기 쉬운 파일 구조를 만들기 위해 다양한 React 컴포넌트 구조 패턴을 조사했습니다.각 패턴의 장단점을 분석하며 프로젝트에 가장 적합한 구조를 고민했지만, 시간 관계상 실제 적용은 제한적이었습니다.제가 찾아본 React 주요 패턴들은 다음과 같습니다. 이해를 돕기 위해 각 패턴마다 특징 및 예시 코드까지 준비하였으나 글이 너무 길어져 읽는데 어려움이 있을 것 같아 최종적으로 간단하게 한 줄로 요약했습니다.4.3.1. Presentational and Container Pattern로직과 UI를 분리하는 패턴으로, 재사용성과 테스트 용이성이 향상되지만 props drilling 문제가 발생할 수 있습니다.4.3.2. Compound Component Pattern복합적인 UI를 구성하는 관련 컴포넌트들을 그룹화하고 내부적으로 상태를 공유하는 패턴입니다. API 사용 경험은 향상되지만 TypeScript 타입 정의가 복잡해질 수 있습니다.4.3.3. Render Props Pattern컴포넌트의 렌더링 로직을 prop 함수로 전달하는 방식으로, 로직 재사용은 용이하지만 콜백 중첩으로 인한 디버깅 어려움이 있을 수 있습니다.4.3.4. Custom Hook Pattern로직을 훅으로 추출하여 여러 컴포넌트에서 재사용하는 패턴입니다. React의 핵심 패턴 중 하나로, UI와 로직의 분리가 명확합니다.4.3.5. Context API Pattern여러 컴포넌트에서 데이터를 공유하기 위한 패턴으로, props drilling을 방지할 수 있지만 불필요한 리렌더링이 발생할 수 있습니다.4.3.6. Atomic Design PatternUI 컴포넌트를 원자(Atoms), 분자(Molecules), 유기체(Organisms), 템플릿(Templates), 페이지(Pages)로 나누는 구조로, 체계적인 UI 구성이 가능하지만 초기 설계 시간이 많이 소요됩니다.4.3.7. Client/Server Component PatternNext.js 14 App Router의 핵심 패턴으로, 서버에서 데이터를 페칭하고 클라이언트에서 인터랙션을 처리하여 번들 크기를 최적화합니다.4.3.8. Server Components and Suspense Pattern데이터 로딩 상태를 선언적으로 처리하는 패턴으로, 점진적 UI 로딩을 지원하고 사용자 경험을 향상시킬 수 있습니다. 5.마무리이번 스터디를 통해 많은 것을 배우고 적용해보는 즐거움을 느꼈습니다. 계획했던 것보다는 적게 구현했지만, 새로운 기술들을 탐색하고 실험해본 경험은 매우 가치 있었습니다. 더 많은 공부 시간을 확보하니 다양한 시도를 해볼 수 있었지만, 동시에 욕심이 커져 모든 계획을 실현하지는 못했습니다. 3주 차에는 개인 약속으로 인해 학습 시간이 줄어들 것 같지만, 지금까지의 경험을 바탕으로 더 효율적으로 학습하고 구현해보겠습니다.무엇보다, 호기심을 가지고 새로운 기술을 탐색하고 적용해보는 과정 자체가 개발자로서 성장하는 중요한 발판이 된다는 것을 다시 한번 느낄 수 있었습니다. 

[인프런 워밍업 클럽 3기 / 백엔드 프로젝트] 1주차 발자국

1.강의 요약1.개요이번주는 컨트롤러, 서비스, 리포지토리, DTO설계와 개발 테스트 그리고 Thymeleaf를 중점으로 공부했던 시간을 가졌다. 2.이번에 배운 내용들@Controller용도: 컴포넌트 스캔 대상이 되어 빈으로 등록되며, 주로 서버 사이드 렌더링(SSR) 방식에서 사용특징: 리턴된 문자열과 동일한 이름의 HTML 템플릿 파일을 찾아 클라이언트에 응답한다@RestController용도: 컴포넌트 스캔 대상이 되어 빈으로 등록되며, 클라이언트 사이드 렌더링(CSR) 또는 API 개발 시 사용특징: 리턴 값이 HTTP 응답 본문에 직접 포함되며, String 이외의 객체는 JSON 등으로 자동 변환@RequestMapping용도: 클래스 또는 메소드에 붙여 HTTP 요청 경로를 지정특징: 클래스에 적용 시 해당 클래스의 모든 메소드에 기본 경로가 붙으며, 메소드 단위로 세부 경로와 HTTP 메서드를 설정할 수 있음@GetMapping용도: HTTP GET 요청에 대한 처리를 명시특징: @RequestMapping(method = RequestMethod.GET)과 동일하게 동작하며, 특정 경로에 GET 요청이 왔을 때 해당 메서드가 실행 @Service용도: 비즈니스 로직을 담당하는 서비스 레이어의 클래스에 사용특징: 빈으로 등록되어 컨트롤러와 리포지토리 사이의 중재자 역할을 수행@Repository용도: 데이터 접근 계층의 클래스를 지정하는 어노테이션특징: 데이터베이스 관련 작업을 수행하며, 컴포넌트 스캔을 통해 빈으로 등록@Component용도: 특별한 역할 분류 없이 범용적으로 사용되는 빈을 등록할 때 사용@Transactional 용도: 트랜잭션을 자동으로 시작하고 종료하며, 예외 발생 시 롤백할 대상을 지정할 수 있음특징: readOnly, rollbackFor, isolation 등의 속성을 통해 트랜잭션의 세부 동작을 설정할 수 있음@ExtendWith용도: JUnit 5에서 테스트 확장을 지원하기 위한 어노테이션@InjectMocks / @Mock용도: Mockito를 사용한 단위 테스트에서 대상 클래스에 필요한 의존성을 주입하거나 모의 객체를 생성할 때 사용@SpringBootTest용도: Spring Boot 애플리케이션의 전체 컨텍스트를 로드하여 통합 테스트를 실행할 때 사용@AutoConfigureMockMVC용도: Spring MVC를 모의 테스트할 수 있도록 MockMVC 객체를 자동 구성  2.미션이번주는 REST API 설계를 했다. https://github.com/Seunggyo/GameReviewHub/commit/95871575bcd3f9680b6089401de86df43e4abe9b  처음으로 원칙을 두고 API를 설계하다보니 어려움을 많이 느꼈지만 노력해보는 시간을 가져보았다. 

백엔드

채널톡 아이콘