블로그

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

[2주차]강의수강이론으로 알고 있었지만 실습에 들어가니 스프링은 굉장히 개념들이 잘 세분화 되어있다는 것을 느낄 수 있었습니다.실습해보면서 배운 각 개념들에 대해 회고하며 복습해보도록 하겠습니다.Repository: 데이터베이스와 직접적으로 상호작용하는 계층. DB 쿼리에 대한 청사진을 그린다고 이해했습니다. -> 그 역할을 해주는 인터페이스가 JPA.그 인터페이스를 받아서 @Repository가 붙인 Presentation 컴포넌트 클래스에서 직접 사용.interface AchievementRepository : JpaRepository<Achievement, Long> { // 문법에 맞게 JPA를 작성하면 DB에서 다음과 같은 쿼리가 작용한다. // select * from achievement where is_active = :isActive fun findAllByIsActive(isActive: Boolean): List<Achievement> }// 개별적인 JPA Repository의 기능을 모아서 제공하는 서비스 성격의 Repository 클래스. @Repository class PresentationRepository( // 여러 개의 Repository 인터페이스를 필드로 주입받는다. private val achievementRepository: AchievementRepository, private val experienceRepository: ExperienceRepository, private val introductionRepository: IntroductionRepository, private val linkRepository: LinkRepository, private val projectRepository: ProjectRepository private val skillRepository: SkillRepository, ) { fun getActiveAchievements(): List<Achievement> { return achievementRepository.findAllByIsActive(true) } ... } DTO(Data Transfer Object, 데이터 전송 객체). 쉽게 말해, 여러 개의 데이터를 하나의 상자로 포장해 옮긴다.레이어드 계층 간에 데이터 전송을 위한 객체.순수 데이터 이동이 목적. 거기에 불필요한 데이터 전송을 방지해 보안성을 높인다고 함.사용 사례// Introduction Entity에는 content와 isActive 필드가 있다. // 그중에서 content 필드만 선택적으로 골라서 전송하는 것이다. data class IntroductionDTO( val content: String ) { constructor(introduction: Introduction) : this( content = introduction.content ) }@Service class PresentationService( private val presentationRepository: PresentationRepository ) { // 트랜잭션을 간편하게 열고 닫을 수 있게 해줍니다. @Transactional(readOnly = true) fun getIntroductions(): List<IntroductionDTO> { val introductions = presentationRepository.getActiveIntroductions() // 엔터티 리스트 가져오기 return introductions.map { introduction -> IntroductionDTO(introduction) } // DTO 변환 후 반환 } }Service: 비즈니스 로직을 담당하는 계층여러 개의 Repository에서 데이터를 가져와 비즈니스에 맞게 조합하는 계층.단순 조합을 넘어 요구사항에 맞는 규칙을 적용하는 것도 가능.Controller와 Repository 중간에서 데이터를 제어. Controller: 사용자의 요청을 처리하는 계층. 사용자가 원하는 데이터를 조회하거나, 자신이 알고있는 데이터를 서버에 전송한다. Request.Controller에서 검증사용자의 요청에 응답한다. 알고 있는 데이터를 보여준다던지 받아서 저장한다든지. Response.우리 실습에선 ApiController와 ViewController가 있었다. 각각 REST Api와 웹 페이지 담당이라고 하는데 ApiController가 잘 이해가 안돼서 다시 봐야될 것 같다... @Controller class PresentationViewController( private val presentationService: PresentationService ) { @GetMapping("/") fun index(model: Model): String { // 변수 model에 Introduction 정보를 추가한다. val introductions = presentationService.getIntroductions() model.addAttribute("introductions", introductions) // 변수 model에 Link 정보를 추가한다. val links = presentationService.getLinks() model.addAttribute("links", links) return "presentation/index" } }테스트 코드: 코드의 안정성을 보장하는 장치. 개발 시 가장 많은 시간이 소비되는 작업."코드가 잘 작동하는걸 증명할게!"라는 느낌으로 작성.각 계층마다 예상되는 오류를 최대한 많이 상정해서 테스트 코드를 많이 만드는게 좋음.given, when, then으로 나눠서 테스트 코드를 작성한다고 함.@SpringBootTest @AutoConfigureMockMvc @DisplayName("[API 컨트롤러 테스트]") class PresentationApiControllerTest( @Autowired private val mockMvc: MockMvc ) { @Test @DisplayName("Introductions 조회") fun testGetIntroductions() { // given val uri = "/api/v1/introductions" // when val mvcResult = performGet(uri) val contentAsString = mvcResult.response.getContentAsString(StandardCharsets.UTF_8) val jsonArray = JSONArray(contentAsString) // then assertThat(jsonArray.length()).isPositive() } } Thymeleaf 중복 처리에 대하여Thymeleaf: Spring Boot에서 사용하는 서버사이드 템플릿 엔진. 즉, 백엔드에서 동적으로 HTML을 생성할 수 있도록 도와주는 도구받아온 템플릿을 고치는 과정에서 중복 처리 과정을 거쳤다.페이지마다 중복되는 navigation, header, footer를 각 html로 옮긴뒤 불러오기 기능을 사용하는 것.새 페이지를 만들 때 사용하면 코드의 가독성도 오르고, 작업 효율도 오를 것이다.힘들었던 점실행을 해보니 resume와 projects 웹페이지의 응답이 이뤄지지 않아 적잖이 당황했었다.로그 메세지를 따라가면서 모든 계층을 확인해봐도 해결이 안되던 것이었는데 결국 문제는 Repository 이름 오타 때문에 클래스를 찾지 못해 Controller 작동이 안되던 것이었다.되게 단순한 문제였지만 동시에 찾기 어려웠다. 기본을 잘 지키며 개발해야겠다고 생각했다...

워밍업2주차

인프런 워밍업 클럽 스터디 3기 - 백엔드 클린 코드, 테스트 코드 2주차 발자국

학습 내용 정리 이번 주차에서는코드 외적인 부분에서 추구할 수 있는 클린 코드 규칙새로운 프로젝트에서 실습, 피드백테스트 코드 작성 입문 이론  1. 코드 외적인 부분으로도 맥락이 형성 된다.변수와 메서드를 어떻게 위치 시킬 것인가고도화 될 수록 변수, 메서드가 많아질 수 있다.이에 따라 필요한 변수 메서드를 찾는 비용이 점점 증가할 수 있다.이 때 특정 규칙/맥락에 따라 잘 정리한다면 비용을 상당히 많이 감소 시킬 수 있겠다.여러 사람이 같이 일할 때 특히 더 강력해지는 도구가 될 수 있다.주석에 대한 것주석의 필요성에 대해 모호하던 상황이었다.정책 의사 결정의 세부 사항, 히스토리 같은 것들은 코드로 표현하기 어렵고, 따로 문서로 정리하게 될 것이라고 생각된다.이 때 주석이 정말 강력한 도구가 될 수 있겠는 것을 알게 되었다. 문서를 따로 만들 필요 없이 단일화 할 수 있겠구나.다만 이 때 주석을 사용하게 된다면 버전 이라는 새로운 맥락을 형성하므로, 코드와 주석을 같이 업데이트 시켜주는 것에 매우 신경 써야 한다. 2. 새로운 프로젝트에서 실습, 피드백실습 진행 프로젝트 위치https://github.com/aammddkkzxc/readable-code/tree/main/src/main/java/cleancode/studycafe/practice피드백 요청 사항  https://github.com/aammddkkzxc/readable-code/blob/main/src/main/java/cleancode/studycafe/practice/needfeedback.md 피드백 적용 https://github.com/aammddkkzxc/readable-code/blob/main/src/main/java/cleancode/studycafe/practice/feedback.md내용 요약검증 메소드를 검증하고자 하는 해당 클래스 내부에 위치 시키자생성자에서 의미 부여를 피하자정적 팩토리 메서드의 강력한 점은 네이밍을 부여하여 역할을 명확히 할 수 있다는 것따라서 의미가 부여되는 초기화 작업이 있다면, 생성자 보다는 정적 팩토리 메서드 내부에서 하는 것이 좋을 수 있다정답을 찾아내려고 하지 말고 논리와 의도에 집중하자코드에 대한 선택은 모든 맥락에 의해서 정해진다. 심지어 팀 내부 상황 같은 외부적 요인까지도 영향을 미친다정답이 있다고 가정하고 접근하게 된다면, 각종 원칙이나 용어에 매몰될 위험이 있다. 언제까지나 원칙과 용어들은 더 나은 선택을 위한 도구일 뿐이라는 것을 잊지 말자.명확한 의도를 가지고 구현/리팩토링 하되, 요구 사항이나 합의가 변하면 언제든 변경할 수 있는 자세를 지니자클린 코드를 왜 추구하는가팀의 생산성을 위해서. 주종 관계의 역전에 주의하자느낀 점저번 주에 배운 원칙들을 적용 시키는 것에 대해 어려울 것으로 예상했는데, 역시 쉽지 않았다.보는 것 만으로는 한계가 있다는 것을 다시 한번 체감했다.이번에 실제 연습을 해봄으로써 좀 더 성장할 수 있었다최근 개발 공부를 하면서 침체기와 막막함을 느끼고 있었는데, "그래 나 이런 것 재밌어 했지"라고 리프래쉬 할 수 있었다.  3. 테스트 코드테스트 코드/TDD의 중요성이전엔 그냥 막연하게 확실히 하는 것이 좋으니까 중요하겠지라고 생각했었고, 크게 동기 부여가 되지 않았었다.강의를 통해 배운 중요성피드백이 빠르다클라이언트 관점으로 개발하여 해피케이스에 매몰되는 것을 피할 수 있다.모호한 기획이나 암묵적인 약속들을 찾아낼 수 있다과감한 리팩토링이 가능해진다테스트 하기 어려운 케이스란?코드를 실행 할 때마다 바뀌는 부분을 함수 내부에 가지고 있으면서, 제어하기 힘든 경우날짜/시간, 랜덤 값, 전역 변수/함수, 사용자 입력 등함수 내부에 갖고 있지 않도록 분리한다. (매개변수로 받아오는 형태로 만들면 제어 가능)어느 레이어 까지 분리 시킬 지 결정이 필요해진다외부에 영향을 주는 경우외부 세계라는 것 자체가 테스트 시 검증이 어렵다표준 출력(로그), 메세지 발송, 데이터베이스 에 기록 등코드외에 다른 테스트 도구 필요DisplayName을 섬세하게, BDD스타일단순 명사의 나열 x 행위부터 결과 까지도메인 관점으로 상세하게 작성메서드 자체의 관점 x테스트 현상 중점 x개발자가 아닌 사람이 봐도 이해할 수 있을 정도로출처 강의 : https://www.inflearn.com/course/readable-code-%EC%9D%BD%EA%B8%B0%EC%A2%8B%EC%9D%80%EC%BD%94%EB%93%9C-%EC%9E%91%EC%84%B1%EC%82%AC%EA%B3%A0%EB%B2%95/dashboard

노을

[인프런워밍업클럽] 2주차 운영체제 미션

운영체제1. FIFO 스케줄링의 장단점이 뭔가요?장점 : 단순하고 직관적단점 : 한 프로세스가 완전히 끝나야 다음 프로세스가 시작, 실행시간이 짧고 늦게 도착한 프로세스가 실행시간이 길고 빨리 도착한 프로세스의 작업을 기다려야 함CPU는 I/O작업 끝날 때까지 쉬고 있기 때문에 CPU 사용률이 떨어지게 됨2. SJF를 사용하기 여러운 이유가 뭔가요?어떤 프로세스가 얼마나 실행될지 예측이 힘듦BurstTime이 긴 프로세스는 아주 오랫동안 실행되지 않을 수 도 있음3. RR 스케줄링에서 타임 슬라이스가 아주 작으면 어떤 문제가 발생할까요?컨텍스트 스위칭이 자주 일어나게 되서 타임 슬라이스에서 실행되는 프로세스의 처리량보다 컨텍스트 스위칭을 처리하는 양이 훨씬 커짐, 배보다 배꼽이 더 커지는 상황이 발생, 즉, 오버헤드가 너무 크다 4. 운영체제가 MLFQ에서 CPU Bound Process와 I/O Bound Process를 어떻게 구분할까요?CPU Bound Process : 대부분의 시간을 CPU 연산 작업I/O Bound Process : 대부분의 시간을 I/O 작업, CPU 연산은 조금만 작업 5. 공유자원이란무엇인가요?공유자원 : 프로세스 간 통신을 할 때 공동으로 이용하는 변수, 파일 6. 교착상태에 빠질 수 있는 조건은 어떤 것들을 충족해야할까요?상호배제 : 어떤 프로세스가 한 리소스를 점유했다면 그 리소스는 다른 프로세스에게 공유가 되면 안됨비선점 : 프로세스 A가 리소스르 점유하고 있는데 프로세스 B가 리소스를 뺏을 수 없음점유와 대기 : 어떤 프로세스가 리소스 A를 가지고 있는 상태에서 리소스 B를 원하는 상태여야만 함

알고리즘 · 자료구조운영체제

[2주차 발자국] Readable Code 적용기

인프런 ‘Readable Code: 읽기 좋은 코드를 작성하는 사고법’을 수강한 후, 작성한 내용입니다.📌 2주차 강의 (Readable Code)코드 다듬기주석의 양면성주석이 많다 ⇒ 비즈니스 요구사항을 코드에 잘 녹이지 못했나 의심해보자.추상화로 설명이 덜 된 것은 아닐까?주석에 의존하면 적절하지 않은 추상화 레벨을 가지게 된다.좋은 주석우리가 가진 모든 표현 방법을 총동원해 코드에 의도를 녹여내고, 그럼에도 불구하고 전달해야 할 정보가 남았을 때 사용하는 주석의사 결정의 히스토리를 도저히 코드로 표현할 수 없을 때, 주석으로 상세하게 설명!번수와 메서드의 나열 순서변수는 사용하는 순서대로 나열하자.인지적 경제성메서드의 순서는 객체의 입장에서 생각해보자.객체는 외부 세계와 어떻게 소통할 것인지가 중요공개 메서드의 스펙을 통해 외부 세계와 소통객체는 협력을 위한 존재외부 세계에 내가 어떤 기능을 제공할 수 있는지를 드러낸다.공개 메서드끼리도 기준을 가져보자.상태 변경 > 판별 > 조회 메서드중요한 것은, 나열 순서로도 의도와 정보를 전달할 수 있다는 것!패키지 나누기패키지는 문맥으로서의 정보를 제공할 수 있다.패키지를 쪼개지 않으면 관리가 어렵다.너무 잘게 쪼개도 안됨대규모 패키지 변경은 팀원과의 합의를 이룬 시점에!기능 유지보수하기객체 지향적으로 책임이 잘 분리되어 있다면,문제가 되는 위치를 발견하여 수정하기 쉽다!알고리즘 교체와 같은 작업이 수월하다!IDE 도움 받기코드 포맷팅sonarlinteditconfig리팩토링 연습스스로 리팩토링을 진행해보고 비교해보는 시간이유를 가지고 리팩토링을 진행하자.변경 포인트는 그 이유를 명확하게 설명할 수 있어야 한다!!감으로 하는 리팩토링은 설득할 수 없는 코드가 될 확률이 높다.객체에 메시지를 보내자.객체의 책임과 응집도를 고려하자.기억하면 좋은 조언들능동적 읽기눈으로 복잡하게 보고 이해하려 애쓰는 것보다 직접 경험해보며 읽자.복잡하거나 엉망인 코드를 읽고 이해하려 할 때, 리팩토링하면서 읽기공백으로 구분메서드와 객체 추상화주석으로 이해한 내용 표기하며 읽기핵심 목표는 도메인 지식을 늘리는 것.그리고 이전 작성자의 의도를 파악하는 것.오버 엔지니어링필요한 적정 수준보다 더 높은 수준의 엔지니어링구현체가 하나인 인터페이스아키텍처 이해에 도움을 주거나, 근시일 내에 구현체가 추가될 가능성이 높다면 괜찮음구현체 수정 시, 인터페이스도 수정코드 탐색에 영향을 준다.너무 이른 추상화정보가 숨겨지기 때문에 복잡도가 높아짐은탄환은 없다만능 해결사 같은 기술은 없다.객체 지향적인 체스 프로그램but, 체스는 500년 동안 변하지 않았다.실무 : 2가지 사이의 줄다리기지속 가능한 소프트웨어의 품질 VS 기술 부채를 안고 가는 빠른 결과물모든 기술과 방법론은 적정 기술의 범위 내에서 사용되어야 한다.도구라는 것은, 한계까지 사용할 줄 아는 사람이 그것을 사용하지 말아야 할 때도 아는 법이다.📌 2주차 강의 (Practical Testing)Intro강의 소개무엇을 학습하는가?테스트 코드가 필요한 이유좋은 테스트 코드란 무엇일까?실무에서 진행하는 방식 그대로 테스트를 작성해가면서 API를 설계하고 개발하는 방법구체적인 이유에 근거한 상세한 테스트 작성 팁어떻게 학습하면 좋을까?무엇을 모르는지 아는 것 = 찾아볼 수 있게 된다는 것선택과 집중을 통해 아는 영역을 넓혀가고, 익숙하지 않은 것들을 익숙하게 하고, 들어보지 못했던 것을 들으면서 나에게 노출시키자.인덱스를 통해 영역을 넓혀가자.테스트는 왜 필요할까?테스트 코드를 작성하지 않는다면,변화가 생기는 순간마다 발생할 수 있는 모든 Case 고려해야 한다.변화가 생기는 순간마다 모든 팀원이 동일한 고민을 해야 한다.빠르게 변화하는 소프트웨어의 안정성 보장 X테스트 코드가 병목이 된다면,프로덕션 코드의 안정성 보장 X테스트 코드 자체가 유지보수하기 어려운 짐잘못된 검증이 이루어질 가능성 O테스트를 통해 얻고자 하는 것 ⇒ 빠른 피드백, 자동화, 안정감따라서, 올바른 테스트 코드는자동화 테스트로 빠른 시간에 버그를 발견하고 비용을 절약한다.소프트웨어의 빠른 변화를 지원한다.팀원들의 집단 지성을 팀 차원의 이익으로 승격시킨다.단위 테스트수동 테스트 vs 자동화된 테스트콘솔에 찍힌 내용을 보고 판단하는 테스트최종 단계에서 사람이 개입해야 함다른 사람이 봤을 때, 무엇을 검증하고 어떤 것이 맞는 상황인지 알 수 없다.과연 이것이 자동화된 테스트일까?JUnit5로 테스트하기단위 테스트작은 코드 단위를 독립적으로 검증하는 테스트작은 코드 = 클래스, 메서드독립적 = 외부 상황에 의존적이지 않아야 한다.검증 속도가 빠르고, 안정적이다.JUnit 5단위 테스트를 위한 테스트 프레임워크AssertJ테스트 코드 작성을 원활하게 돕는 테스트 라이브러리풍부한 API, 메서드 체이닝 지원리스트 사이즈 검증할 때 다음을 이용하자..hasSize().isEmpty()테스트 케이스 세분화하기해피 케이스예외 케이스assertThatThrownBy()경계값 테스트범위, 구간, 날짜 등테스트하기 어려운 영역 분리하기생성 시간 검증에 대한 테스트에서 생성 시간을 메서드 내부에서 측정한다면?테스트하는 시간에 따라 테스트 결과가 달라진다.외부로 분리하자!외부로 분리할수록 테스트 가능한 코드는 많아진다.테스트하기 어려운 영역관측할 때마다 다른 값에 의존하는 코드현재 시간에 의존하는 코드외부 세계에 영향을 주는 코드테스트 하기 좋은 영역 (순수함수)같은 입력에는 항상 같은 결과외부 세상과 단절된 형태TDD : Test Driven Development프로덕션 코드보다 테스트 코드를 먼저 작성하여 테스트가 구현 과정을 주도하도록 하는 방법론RED → GREEN → REFACTORRED : 프로덕션 코드 없이 테스트를 먼저 작성GREEN : 테스트가 통과할 수 있는 최소한의 코딩REFACTOR : 테스트 통과를 유지하면서 구현 코드 개선기능 구현 후, 테스트를 작성하면,테스트 자체의 누락 가능성특정 테스트 케이스만 검증할 가능성잘못된 구현을 다소 늦게 발견할 가능성테스트를 먼저 작성하면,복잡도가 낮은, 테스트 가능한 코드로 구현쉽게 발견하기 어려운 엣지 케이스를 놓치지 않게 해준다.구현에 대한 빠른 피드백과감한 리팩토링테스트를 구현부 검증을 위한 보조 수단이 아니라, 테스트와 상호 작용하며 발전하는 프로덕션 코드을 만든다고 바라본다.즉, 객체 사용자 관점에서의 피드백을 준다!추가 인덱스애자일 방법론일정한 주기를 가지고 빠르게 제품을 출시하여 고객의 요구사항, 변화된 환경에 맞게 요구를 더하고 수정해나가는 방법익스트림 프로그래밍빠른 개발 속도를 유지하며 고객이 원하는 요구들을 지속적으로 피드백하는 방법의사소통, 단순성, 용기, 피드백, 존중하나의 방법론 : TDD스크럼, 칸반스크럼 : 스프린트라는 일정기간 안에 완료할 수 있는 작업으로 업무를 분할한다.칸반 : 동시에 개발이 진행될 수 있는 아이템의 수를 제한하여, 업무의 병목 현상과 리소스 낭비를 처리할 수 있도록 한다.테스트는 [ ]다.테스트는 [문서]다.프로덕션 기능을 설명하는 테스트 코드 문서다양한 테스트 케이스를 통해 프로덕션 코드를 이해하는 시각과 관점 보완과거에 경험했던 고민의 결과물을 팀 차원으로 승격시켜, 모두의 자산으로 공유DisplayName을 섬세하게비교음료 1개 추가 테스트음료 1개 추가하면 주문 목록에 담긴다.명사의 나열보다 문장으로테스트 행위에 대한 결과까지 기술하기비교특정 시간 이전에 주문을 생성하면 실패한다.영업 시작 시간 이전에는 주문을 생성할 수 없다.도메인 용어를 사용하여 한층 추상화된 내용을 담기메서드 자체의 관점보다 도메인 정책 관점으로!테스트의 현상을 중점으로 기술하지 말 것BDD 스타일로 작성하기함수 단위의 테스트에 집중하기보다, 시나리오에 기반한 테스트케이스(TC) 자체에 집중하여 테스트개발자가 아닌 사람이 봐도 이해할 수 있을 정도의 추상화 레벨 권장Given / When / ThenGiven : 시나리오 진행에 필요한 모든 준비 과정When : 시나리오 행동 진행Then : 시나리오 진행에 대한 결과 명시, 검증명확하게 표현하지 못한 테스트는 나중에 우리의 사고를 제한하는 허들이 될 수 있다!추가 인덱스JUnit전통적인 Java 기반의 테스트 프레임워크어노테이션 사용SpockGroovy 기반의 BDD(Behavior-Driven Development) 프레임워크BDD 스타일 테스트로 가독성이 더 좋다.Groovy 언어로 작성해야하므로 작성이 어려울 것 같다.📌 Day 7 미션 & 중간 점검 라이브Day 7 미션 : 변경 포인트는 그 이유를 명확하게 설명할 수 있어야 한다!Day 7 미션은 ‘스스로 스터디 카페 이용권 선택 시스템 리팩토링해보기’였다.미션 수행 전 강의를 들으며 내용들에 대해 거부감 없이 받아들여졌고, 빨리 코드를 짜보고 싶다는 생각이 들도록 하였다. 하지만 실제로 코드를 작성하면서 고민되는 지점들도 꽤 많았고, 근거를 가지고 리팩토링을 하는 과정이 쉽지는 않았다. ‘이게 더 나은거 같은데…?’하며 감으로 진행한 부분도 꽤 있었던 것 같다. 미션을 진행하고 강의를 수강하면서 ‘변경 포인트는 그 이유를 명확하게 설명할 수 있어야 한다.’라는 말이 내가 유의해야 할 말로 느껴졌다.중간 점검 라이브중간 점검 라이브는 Day 4 미션 공통 피드백, Q&A, 코드 리뷰 순서로 진행되었다.Day 4 미션 공통 피드백Day 4 미션 공통 피드백 다음과 같다.추출한 메서드에 static이 있는 경우boolean을 return 하는 메서드에 예외 throw오버 엔지니어링나도 메서드를 추상화하기 위해 추출하다보면, IDE에서 static 키워드를 붙여서 따로 지워준 적이 있다. 추출하여 메서드명만 적지 말고, 전체적으로 확인해보자.상태를 체크하고 boolean을 반환하는 메서드가 있을 때 예외를 던지는 것 보다 상황에 맞게 리팩토링 하는게 좋은 것 같다. validateOrder에서 false를 반환해서 유효하지 않은 주문을 나타내면 되지 않을까?미션의 안내 사항을 잘못 이해한 것 같다. Order의 내부 구현 없이 단순한 리팩토링을 제안하는 것이 요구사항이다. 그런데 나는 ‘Order의 메서드를 추가하더라도 구현 내용은 안적어도 된다.’라고 이해했다. 미션에서 요구했던 내용은 Order에 추가적으로 구현되는 사항 없이 리팩토링을 진행하라고 했던 것 같다.Q&AQ&A의 많은 내용들이 나에게 도움이 되었다. 다른 분들께서 질문해주신 내용들이 생각 외로 많은 인사이트를 얻을 수 있었다.질문하고자 했던 내용들이 다른 분 질문에 있기도 했고 개발 외 질문을 하고 싶어서 우빈님께 개인 취향의 저가 커피 브랜드 1순위와 선호하는 취향에 대해 여쭤보았다.우빈님께서는 저가 커피는 거의 안 드신다고 한다… 그래도 재밌는 영상을 추천해주셨다.항상 카페가면 필터 커피가 있으면 필터 커피를 먹어보거나 그 카페의 스페셜한 원두를 맛을 보려 노력하는데, 항상 먹고 나면 기억이 나지 않는다… ‘이게 어떤 맛이었더라..?’ 하게 된다. 이런 소소한 것에서 취미를 가지는 것도 재밌는 것 같다.코드 리뷰기간 내에 신청해서 우빈님께 코드 리뷰를 받을 수 있었다! 라이브 동안 다른 분 코드 리뷰 해주시는 것도 같이 경청하였는데, 생각보다 내가 놓친 부분들을 여기서 얻을 수도 있었다. 물론 내가 작성한 코드를 리뷰 해주신 것이 직접적으로 바로 와닿았지만, 다른 분 코드 리뷰에서도 배울 점이 있었다.다른 분 코드 리뷰를 해주시면서 퀴즈로 내신 부분이 있다. 퀴즈 내용은 간략하게 설명하면 ‘try-catch에서 예외를 throw했는데 왜 잡히지 않을까?’이다. 코드를 보여주셨을 때 문제가 없어보였다. 그래서 나는 ‘import가 잘못된거 아니야?’라고 생각을 해서 정답을 맞췄다!사실 미션 진행하면서 정말 유사한 문제를 겪은 적이 있었다. 분명 메서드 파라미터가 똑같은데 파라미터가 다르다고 컴파일 에러가 났었다. 미션 특성 상, 맨 처음 리팩토링 이전 패키지와 이후 패키지의 클래스는 똑같다. 그래서 리팩토링 패키지에서 import를 잘못하면, 다른 패키지의 클래스를 가져온다. 그래서 문제가 발생했었는데 이와 똑같은 문제라 운이 좋게도 맞출 수 있었다.영광의 흔적!!코드 리뷰 해주시는 것을 보며 내가 배운 점들은 다음과 같다.Enum의 valueOf 메서드를 통한 생성valueOf 대신 String을 받아서 객체를 생성하는 정적 메서드를 구성사물함 이용 가능 여부를 StudyCafePassType에 저장하는 부분도 좋음get/set은 관용적인 어구로 필드에 대한 getter/setter가 아니더라도, 메서드에 get~~, set~~ 으로 네이밍하는 건 지양하자.early return 보다 else-if가 더 배타적인 내용을 나타내지 않을까?if 절 내에 return을 봐야한다.구조화보다 적절한 책임의 분배가 더 중요하다.위 내용은 다른 분들의 코드 리뷰에서 내가 배운 부분들이다. 다음은 내가 질문하거나 리뷰해주신 내용이다.있을 수도, 없을 수도 있는 필드에 대한 관리를 어떻게 해야할까요?사물함 이용권을 별도 필드로 관리하고 EMPTY 객체를 넣는다? (내용이 정확히 기억이 나지 않는다….)PassReader - FilePassReader로 PassReader의 책임을 부여하고, File에 저장된 Pass를 읽는 구현체로 분리해도 괜찮을까요?괜찮은 접근인 것 같다.Order order = Order.create() 후, order.add(pass) 와 같은 형식으로 주문이후에 주문의 내용이 바뀔 위험성이 존재하므로, 만들어놓고 추가하는 것보다 마지막에 한 번에 Order 객체를 만드는 것이 더 안정적이다. 위험성을 제거하자. 가변보다 불변이 더 좋다!우빈님꼐서 약 1시간 45분동안 라이브를 진행해주셨다. 긴 시간동안 라이브로 진행한다는 것이 쉽지 않으실텐데, 덕분에 나는 유익한 시간을 보낼 수 있었던 것 같다! 직접적으로 우빈님과 소통할 수도 있고 내가 얻을 수 있는 인사이트도 챙겨 소중한 시간이었다. 처음에 말씀하셨던 ‘함께 자라기’를 위해 더 노력해야겠다.

백엔드워밍업스터디발자국클린코드테스트

재영

[인프런 워밍업 클럽 3기] CS - 2주차 미션 (운영체제)

FIFO 스케줄링의 장단점이 뭔가요?장점 : 단순하고 직관적임단점 : 한 프로세스가 완전히 끝나야 다음 프로세스가 시작되기 때문에 실행시간이 짧고 늦게 도착한 프로세스가 실행시간이 길고 빨리 도착한 프로세스의 작업을 기다려야 한다는 것또한, IO 작업이 있다고 한다면 CPU는 IO 작업이 끝날 때까지 쉬고있기 때문에 CPU 사용률이 떨어짐  SJF를 사용하기 여러운 이유가 뭔가요?SJF은 Shortest Job First의 약어로 버스트 타임이 짧은 프로세스를 먼저 실행하는 것사용이 어려운 이유는 다음과 같음어떤 프로세스가 얼마나 실행될지 예측하기 힘듬프로세스의 종료 시간은 예측하기가 거의 불가능버스트 타임이 긴 프로세스는 아주 오랫동안 실행되지 않을 수 있음버스트 타임이 짧은 프로세스가 중간에 계속 들어오면 버스트 타임이 긴 프로세스는 앞의 모든 프로세스가 종료될 때까지 기다려야함 RR 스케줄링에서 타임 슬라이스가 아주 작으면 어떤 문제가 발생할까요?문맥 교환 Context Switch 이 자주 발생하여 타임 슬라이스에서 실행되는 프로세스의 처리량보다 문맥 교환을 처리하는 양이 훨씬 커지게됨 운영체제가 MLFQ에서 CPU Bound Process와 I/O Bound Process를 어떻게 구분할까요?CPU를 사용하는 프로세스가 실행하다가, 스스로 CPU를 반납하면 CPU 사용이 적은것이니 I/O Bound Process 일 가능성이 높다 생각하고 I/O Bound Process 로 판단CPU를 사용하는 프로세스가 타임 슬라이스 크기를 오버해서 CPU 스캐줄러에 의해 강제로 CPU를 뺏기는 상황이면 CPU Bound Process 일 확률이 높다 생각하고 CPU Bound Process로 판단 공유자원이란무엇인가요?프로세스 간 통신을 할 때 공동으로 이용하는 변수나 파일 들을 공유자원이라고 함 교착상태에 빠질 수 있는 조건은 어떤 것들을 충족해야할까요?상호 배제비선점점유와 대기원형 대기

인프런워밍업클럽3기CS2주차미션운영체제

codestudy

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

🚀 Dropbox 클론코딩 - 파일 스토리지 서비스 제작하기📚 강의 수강일주일 동안 학습한 내용 요약🔧 프로젝트 설정 (섹션 4-2)Next.js 프로젝트 초기 설정 방법Tailwind CSS와 TypeScript 환경 구성Material-Tailwind, React Query 등 필요한 라이브러리 설치프로젝트 페이지 구조와 레이아웃 설정환경 변수(.env) 구성🎨 UI 구축 (섹션 4-3)Dropbox 클론의 직관적인 인터페이스 구현logo.tsx, dropbox-image, search-component 등 재사용 컴포넌트 개발Next.js의 이미지 처리와 정적 파일 관리Tailwind CSS의 flex, grid 시스템을 활용한 반응형 디자인useState 훅을 활용한 검색 기능 상태 관리🗄 Supabase Storage 설정 및 파일 업로드 (섹션 4-4)Supabase Storage 버킷 생성 및 설정Form 요소와 onSubmit 이벤트를 활용한 파일 업로드 기능FormData 객체를 활용한 파일 데이터 처리React Query의 useMutation 훅을 통한 파일 업로드 상태 관리업로드된 이미지 URL 생성 및 표시🔄 고급 기능 구현 (섹션 4-5)Supabase Storage의 remove 함수를 활용한 파일 삭제 기능react-dropzone 라이브러리를 활용한 드래그 앤 드롭 구현useDropZone 훅 활용 및 onDrop 콜백 함수 설정multiple 옵션을 활용한 여러 파일 동시 업로드 기능Promise.all을 활용한 비동기 파일 업로드 병렬 처리로딩 상태 표시 및 사용자 피드백 개선학습 내용 회고이번 주 학습을 통해 Next.js와 TypeScript를 활용한 모던 웹 애플리케이션 개발 과정을 경험할 수 있었습니다. TypeScript의 타입 시스템을 적극 활용하면서 인터페이스 정의와 컴포넌트 타입 적용에 많은 배움이 있었지만, Material Tailwind 컴포넌트와의 타입 호환성 문제를 해결하는 과정에서 any 타입을 사용한 것은 아쉬움으로 남습니다.  🛠 미션 해결 과정TypeScript 타입 문제 해결Material Tailwind 컴포넌트와 TypeScript의 타입 호환성 문제에 직면했을 때, 다음과 같은 과정으로 해결했습니다:문제 정의: IconButton, Input, Spinner 등의 컴포넌트에서 다음과 같은 TypeScript 타입 에러가 발생했습니다.'{ value: string; onChange: (e: ChangeEvent<HTMLInputElement>) => void; label: string; icon: Element; }' 형식에 'Pick<InputProps, ... 284 more ... | "shrink">' 형식의 onPointerEnterCapture, onPointerLeaveCapture 속성이 없습니다. 해결 방안 탐색: 여러 가지 해결 방법을 고려했습니다:@ts-ignore 또는 @ts-expect-error 주석 사용타입 단언(Type Assertion) 사용props 객체와 any 타입 활용효율적인 접근법 선택: 코드 가독성과 유지보수성을 고려하여 props 객체와 any 타입을 활용하는 방법을 선택했습니다:const inputProps: any = { value: searchInput, onChange: (e: ChangeEvent<HTMLInputElement>) => setSearchInput(e.target.value), label: "Search Images", icon: <i className="fa-solid fa-magnifying-glass" /> }; return <MaterialInput {...inputProps} />; 일관된 패턴 적용: 비슷한 문제가 발생하는 다른 컴포넌트에도 동일한 패턴을 적용하여 코드의 일관성을 유지했습니다. 예를 들어 IconButton, Spinner 등의 컴포넌트에도 같은 방식으로 타입 문제를 해결했습니다.로딩 상태 처리: boolean 값 처리 문제도 해결했습니다.// 경고: Received `false` for a non-boolean attribute `loading` // 해결: loading 속성 제거 후 조건부 렌더링으로 처리 const iconButtonProps: any = { onClick: () => { deleteFileMutation.mutate(image.name); }, color: "red", children: deleteFileMutation.isPending ? ( <Spinner {...spinnerProps} /> ) : ( <i className="fas fa-trash" /> ) }; 외부 라이브러리와의 통합 과정에서는 때로는 타입 시스템을 부분적으로 우회해야 할 필요가 있다는 것을 배웠습니다.미션 해결 회고기능에 집중을 하다가도...아무래도 빨간줄 에러표시가 뜨는 것이 저는 너무 신경이 쓰였던 것 같습니다. 중간중간마다 타입에러를 해결하는데 시간투자를 했었습니다. (ai에게도 많은 질문을 했습니다)저는 결국, 에러 무시하는 방법 혹은 TypeScript를 사용하여 타입 안전한 코드를 작성하는 방법 중 타입스크립트를 적용해보는 것을 선택했습니다.틈틈이 타입스크립트 공부도 해야할 것 같습니다.이번 풀스택 강의가 끝나고 나서 컴포넌트 안에서 공통으로 적용하여 재사용가능한 타입으로 빼서 리팩토링 할 시간도 가져보면 좋을 것 같습니다.그리고 프로젝트를 진행하면서 업로드 날짜 표시 기능과 한글 파일명 변환하는 작업은 하지 못한 점은 아쉬움으로 남습니다. 다른 수강생분들은 강의 따라하는 것 외에 새로운 추가 기능도 넣기도 한 것 같은데 저는 기본을 따라 가는 것에도 벅차서 추가적인 기능은 넣지 못했습니다..복습을 좀 더 해서 빠르게 지나쳤던 용어나 코드들을 재점검해야 할 것 같습니다... 감사합니다.

프론트엔드dropboxsupabase

Giyeon Pak

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

강의 URL : https://www.inflearn.com/course/readable-code-%EC%9D%BD%EA%B8%B0%EC%A2%8B%EC%9D%80%EC%BD%94%EB%93%9C-%EC%9E%91%EC%84%B1%EC%82%AC%EA%B3%A0%EB%B2%95/dashboard 학습 내용상속과 조합Value Object일급 컬렉션Enum 활용다형성 활용하기숨겨져 있는 도메인 개념 도출하기리팩토링 연습 ( 스터디카페 키오스크 프로젝트 ) 강의를 들을수록 강사님이 얼마나 많은 고민을 하면서 예제를 만들었을지 깨닫게 되었습니다.정말 사소한 부분까지 흘려 넘기는게 아니라 피와 살이 되는 정말 중요한 내용이라, 항상 긴장하며 듣고 있었습니다.( 물론, 아직 놓친 부분도 많지만 따로 부족한 부분은 기록해두어서 다시 들으면서 복습할 예정입니다 ) 제 발자국의 내용은 , 다른분들처럼 강의 내용을 정리하기보다는 '제가 느끼고 성장한 이야기'에 대해서 말씀드리고 싶습니다 1주차, 2주차 진행하면서 단기간에 성장한 모습을 확인할 수 있습니다(물론, 강사님의 정해주신 일정대로 따라가는건 정말 힘들었습니다..심지어 워밍업 클럽에 참가하기 전에 이미 완강을 한 상태였는데도.. 회사업무랑 같이 하다보니 시간이 부족하더라구여 ㅠ) 아직 부족하지만 제가 성장했다고 느끼는 포인트에 대해서 살펴보면추상화 레벨을 맞춰서 코드를 일관성 있게 만들려고 노력하고 있다책임을 분리하여 로직을 도메인 안에서 작성하려고 한다 ( 애그리거트 루트 내부 )SOLID의 기본 원칙을 준수하려고 노력한다 ( 특히, 이번에 OCP를 활용해서 업무에서 중복 IF를 제거 )Enum의 활용능력 상승 ( 매직넘버, 매직스트링을 Enum으로 대체 )사고의 depth + early return + stream 사용 능력 향상 ( 코드를 이전보다 깔끔하게 작성 )부정어 대신 다른 방식으로 처리할 수 있는 방식 고민 ( 불필요한 부정어 사용 X )이 외에도 훨씬 많이 배운점이 많은거 같습니다 ㅎ 사실 좀 더 일찍 이 강의를 보고 워밍업 클럽에 참여할 수 있었다면 좀 더 성장할 수 있지 않았을까 아쉬운 마음은 있지만, 그런 아쉬운 마음을 느끼는 만큼 더 열심히 배우려고 노력하고 있습니다. 최근에 인상깊었던 책의 문구가 있는데..'영화를 봤을 때 그 영화의 줄거리를 이야기 하지 못한다면? 그건 영화를 봤다고 할 수 있을까?'그건 단순하게 '영화를 구경했다고 하는게 아닐까?''독서도 마찬가지야. 책을 읽고 줄거리를 말하지 못한다면? 그건 책을 읽은게 아니라, 책을 구경한거야''실력을 향상하고 싶으면 줄거리를 읽고 말할 수 있는 정도가 되어야해'[공부머리 독서법 by 최승필 ] 아직까지는 강사님이 말씀해주신 모든 내용을 완벽하게 이해하지 못하고 있지만, 3번, 4번, 5번 이상씩 반복하면서 완전히 습득하기 위해 노력하겠습니다. 다른 강의는 보통 1번만 보고 다시 반복하지는 않지만, Reaable Code는 Java라는 언어를 떠나서 개발자들이 알면 좋은 지식이라고 생각하고 좋은 개발자가 되기 위해서는 기본적으로 갖춰야하는 아주 좋은 내용들로 구성되어 있다구 생각합니다 만약 다른 분들이 워밍업 클럽 4기, 5기 이후 참석하신다면!! 꼭!!!! 미리 강의를 듣고 참여하시는게 좋을거 같습니다!! ( 그래도 쉽지 않더라구여 ㅎ ) 두서없이 너무 느낀점만 작성한 느낌이지만, 정말 워밍업클럽 참여하기 잘 했다는 내용을 조금 이상하게 풀어서 작성한거 같습니다!!  

워밍업클럽백엔드

[워밍업 클럽 3기 BE code] 2주차 발자국

 강의 수강 테스트는 왜 필요할까?추가한 기능이 기존 프로덕션 코드와 겹치는 상황(기존 코드를 건드리는 상황) 발생 이런 일들이 비일비재함이런 상황에서 사람이 테스트를 진행하면 문제가 발생할 확률이 높음- 커버할 수 없는 영역 발생- 경험과 감에 의존- 늦은 피드백- 유지보수 어려움- 소프트웨어 신뢰도 낮아짐 테스트코드를 통해 얻고자 하는 것- 빠른 피드백- 자동화- 안정감 만약 테스트코드가 엉망이라면?프로덕션코드를 잘 지원하지 못한다.테스트코드를 잘 짜야한다. 테스트코드를 작성하지 않는다면?- 변화가 생기는 매순간마다 발생할 수 있는 모든 Case를 고려해야 한다.- 변화가 생기는 매순간마다 모든 팀원이 동일한 고민을 해야 한다.- 빠르게 변화하는 소프트웨어의 안정성을 보장할 수 없다. 테스트코드가 병목이 된다면?- 프로덕션 코드의 안정성을 제공하기 힘들어진다.- 테스트코드 자체가 유지보수하기 어려운, 새로운 짐이 된다.- 잘못된 검증이 이루어질 가능성이 생긴다. 올바른 테스트코드는?- 자동화 테스트로 비교적 빠른 시간 안에 버그를 발견할 수 있고, 수동 테스트에 드는 비용을 크게 절약할 수 있다.- 소프트웨어의 빠른 변화를 지원한다.- 팀원들의 집단 지성을 팀 차원의 이익으로 승격시킨다.- 가까이 보면 느리지만, 멀리 보면 가장 빠르다.단위 테스트  - 작은 코드 단위(클래스, 메서드)를 독립적으로 검증하는 테스트- 검증 속도가 빠르고, 안정적이다. JUnit 5- 단위 테스트를 위한 테스트 프레임워크- Xunit(SUnit, JUnit, NUnit...) - Kent Beck AssertJ- 테스트 코드 작성을 원활하게 돕는 테스트 라이브러리- 풍부한 API, 메서드 체이닝 지원  테스트 케이스 세분화하기질문하기: 암묵적이거나 아직 드러나지 않은 요구사항이 있는가?- 해피 케이스- 예외 케이스경계값 테스트 중요! -> 범위(이상, 이하, 초과, 미만), 구간, 날짜 등  회고  테스트코드 강의를 처음 학습하였다.이전부터 테스트코드가 중요하다는 것을 많이 들어왔지만, 실제로 많이 작성해보진 못했다.강의를 통해 테스트코드의 중요성과 테스트 방법에 대해 배웠고 내 프로젝트에도 적용해 볼 생각이다.앞으로 배우는 구체적인 내용들도 학습해서 테스트코드를 잘 작성할 수 있도록 노력해야겠다. 

허진혁

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

코드 리팩토링을 통한 성장: 주간 회고1. 리팩토링을 시작하게 된 계기이번 주는 코드 리팩토링을 집중적으로 진행했다. 기존 코드에서 개선할 점을 찾아 수정하는 과정에서 단순한 문법 개선을 넘어, 코드의 유지보수성과 가독성을 향상시키는 것이 얼마나 중요한지 다시금 깨닫게 되었다.리팩토링을 진행한 코드(PR): GitHub 링크이 과정을 통해 단순한 기능 구현이 아니라, 보다 효율적인 코드 작성법과 객체 지향적인 사고 방식을 익히게 되었다.2. 리팩토링 과정과 개선 포인트(1) 중복 코드 제거 및 메서드 추출기존 코드에서는 비슷한 로직이 여러 메서드에서 반복적으로 사용되고 있었다. 이를 해결하기 위해 메서드 추출 기법을 적용했다.기존 코드에서는 여러 곳에서 동일한 로직을 복사-붙여넣기 했지만, 공통 로직을 별도의 메서드로 분리하여 재사용성을 높였다.이 과정에서 단일 책임 원칙(SRP, Single Responsibility Principle) 을 더욱 깊이 이해할 수 있었다.(2) 가독성을 높이는 네이밍 개선리팩토링 전에는 변수명과 메서드명이 애매하여 코드의 의도를 명확히 파악하기 어려웠다. 개선 과정에서 다음과 같은 기준을 적용했다.메서드명은 동작을 명확하게 설명할 수 있도록 동사 + 목적어 형식으로 변경변수명은 의미를 명확하게 전달할 수 있도록 명명 (예: temp → formattedDate)코드 리뷰 과정에서 네이밍의 중요성을 다시금 깨달았다. 가독성이 높아지면 코드의 이해도가 높아지고, 유지보수도 쉬워진다.(3) 불필요한 의존성 제거 및 클래스 분리기존 코드에서는 한 클래스가 너무 많은 역할을 담당하고 있었다. 이를 해결하기 위해 책임을 분리하고, 역할에 맞는 클래스를 생성했다.기존의 거대한 클래스에서 역할별로 클래스를 분리하여 객체 지향적인 구조로 개선불필요한 의존성을 제거하고, 의존성 역전 원칙(DIP, Dependency Inversion Principle) 을 적용하여 유연성을 높였다.SRP를 적용한 후, 코드의 변경이 필요할 때 한 곳만 수정하면 되어 유지보수성이 크게 향상되었다.3. 다른 개발자들의 경험에서 배운 점이번 리팩토링을 진행하면서 다른 개발자들이 작성한 후기도 참고했다. (Inflearn 블로그 링크 모음)여러 후기에서 공통적으로 강조하는 몇 가지 핵심 사항을 발견했다.리팩토링의 본질은 단순한 코드 변경이 아니라 유지보수성과 확장성을 높이는 것코드가 동작한다고 끝이 아니라, 더 나은 코드로 개선하는 과정이 필요함.리팩토링은 협업과 코드 리뷰를 통해 더욱 효과적으로 이루어진다혼자 작업할 때는 발견하지 못했던 문제점들이, 코드 리뷰를 통해 드러남.다른 개발자들의 시각에서 개선점을 찾는 것이 중요함.객체 지향 원칙을 적용하는 것이 리팩토링의 핵심이다SOLID 원칙을 고려하며 리팩토링할 때 코드가 더욱 구조적으로 개선됨.특히 단일 책임 원칙(SRP), 의존성 역전 원칙(DIP) 을 적용하면 코드의 확장성이 크게 증가함.이번 리팩토링을 통해 나 또한 이 점을 깊이 체감했다.4. 리팩토링을 통해 얻은 교훈이번 경험을 통해 얻은 가장 큰 교훈은 "리팩토링은 단순한 코드 수정이 아니라, 코드의 가치를 높이는 과정이다." 라는 것이다.코드는 팀원과 미래의 나를 위한 문서와 같다. 가독성이 좋고, 유지보수가 쉬운 코드가 진짜 좋은 코드다.코드 리뷰를 적극적으로 활용하자. 다른 개발자들의 피드백을 통해 더 나은 개발자가 될 수 있다.객체 지향 원칙을 익히고 실천하자. SOLID 원칙을 고려하며 개발하는 것이 장기적으로 가장 효율적인 방법이다.이러한 리팩토링 경험을 반복하면서, 더욱 성장하는 개발자가 되어야겠다는 다짐을 하게 되었다. 앞으로도 주간 단위로 배운 내용을 정리하며 지속적인 성장을 기록할 예정이다.✍ 앞으로의 다짐매주 코드 리팩토링을 진행하고, 개선된 내용을 블로그에 정리하기코드 리뷰 문화를 적극적으로 활용하고, 동료 개발자들과 협업하며 성장하기SOLID 원칙과 디자인 패턴을 공부하고, 실무에서 적용할 수 있도록 연습하기이번 리팩토링 경험을 통해 얻은 교훈을 앞으로도 개발 과정에 적용하며, 더 나은 개발자로 성장해 나가겠다!

백엔드워밍업클럽3기클린코드

taeminseo

[인프런 워밍업 클럽 3기] CS - 2주차 미션

2주차 미션운영체제FIFO 스케줄링의 장단점이 뭔가요?장점 : 먼저 들어온 작업을 먼저 처리하는 방식으로 구현이 단순하고 직관적단점 : 작업시간이 긴 작업이 앞에서 발생한다면 이 작업이 끝날때 까지 완전 끝날때 까지 뒤에 있는 작업들이 비효율적으로 대기시간이 길어짐. 대기시간이 길어지면 응답 시간이 길어질 수 있음.SJF를 사용하기 여러운 이유가 뭔가요?실행 시간 예측이 불가능 하고, burst time이 긴 프로세스가 아주 오랫동안 실행이 되지 않을 수 있음. burst time이 짧은 프로세스가 중간에 계속 들어오면 burst time이 긴 프로세스는 계속 뒤로 밀림.RR 스케줄링에서 타임 슬라이스가 아주 작으면 어떤 문제가 발생할까요?컨텍스트 스위칭이 많이 발생해 오버헤드가 증가함.운영체제가 MLFQ에서 CPU Bound Process와 I/O Bound Process를 어떻게 구분할까요?CPU를 사용하는 프로세스가 실행하다가 스스로 CPU를 반납하면 CPU 사용이 적은 것이므로 I/O Bound Process라고 취급한다.반대로 타임 슬라이스 크기를 오버하여 CPU 스케줄러에 의해 강제로 CPU를 뺏기는 상황이면 CPU Bound Process라고 취급한다.공유 자원 이란 무엇인가요?여러 프로세스가 동시 접근하여 사용하는 자원 (EX 파일)여러 프로세스가 사용하기에 Race Condition , Deadlock 등의 문제가 발생 할 수 있음문제 해결을 위해 여러 프로세스가 동시에 사용되면 안되는 구역인 임계구역을 설정하고 관리 해야함.,교착상태에 빠질 수 있는 조건은 어떤 것들을 충족해야할까요?상호 배제(Mutual Exclusion)한 번에 한 프로세스만 자원을 사용할 수 있어야 함.점유와 대기(Hold and Wait)이미 자원을 가진 프로세스가 추가 자원을 기다려야 함.비선점(No Preemption)프로세스가 자원을 강제로 빼앗길 수 없어야 함.순환 대기(Circular Wait)프로세스들이 원형으로 자원을 점유한 채 서로 기다려야 함.자료구조와 알고리즘재귀함수에서 기저조건을 만들지 않거나 잘못 설정했을 때 어떤 문제가 발생할 수 있나요?기저조건이 없으면 무한 루프에 빠져 스택 오버 플로우가 발생할 수 있고 , 불필요한 연산이 증가 하여 성능이 저하됨.0부터 입력 n까지 홀수의 합을 더하는 재귀 함수를 만들어보세요.function OddSum(n){ if (n <= 0) return 0; // 기저 조건 (n이 0 이하이면 종료) if (n % 2 === 0) return sumOdd(n - 1); // 짝수면 n-1로 이동 return n + sumOdd(n - 2); // 홀수면 더하고 n-2로 이동 } console.log(sumOdd(10)) // 결과 값 : 25 다음 코드는 매개변수로 주어진 파일 경로(.는 현재 디렉토리)에 있는 하위 모든 파일과 디렉토리를 출력하는 코드입니다. 다음 코드를 재귀 함수를 이용하는 코드로 변경해보세요.const fs = require("fs"); // 파일을 이용하는 모듈 const path = require("path"); // 폴더와 파일의 경로를 지정해주는 모듈 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); traverseDirectory(filePath); // 재귀 호출 } else { console.log('파일:', filePath); } } } traverseDirectory("."); // 현재 경로의 모든 하위 경로의 파일, 디렉토리 출력

클린코드 발자국 2주차

## 5. 코드 다듬기### ✨ 요약- 주석이 많다는 것은 코드가 비즈니스 로직을 명확히 반영하지 못했다는 신호일 수 있다. - 코드만으로도 의미를 전달할 수 있도록 가독성을 높이는 것이 중요하다.- 메서드와 변수 정렬 방식에도 신경 쓰자. - public → private 순서, 상태 변경 > 판별 > 조회 순서를 유지하면 가독성이 올라간다.- 패키지 구조를 의미 있게 나누는 것이 중요하다. - 너무 세밀하게 나누면 관리가 어렵고, 너무 큰 단위로 묶으면 유지보수가 어렵다. - 프로젝트의 규모와 요구사항에 맞는 적절한 구조를 고민해야 한다.---## 6. 리팩토링 연습### ✨ 요약- 리팩토링은 단순한 코드 변경이 아니라, 코드의 응집도를 높이고 결합도를 낮추는 과정이다. - 리팩토링을 할 때는 단순한 코드 변경이 아니라, 객체 간의 관계와 책임을 다시 한번 점검하는 것이 중요하다.- DIP(의존 관계 역전 원칙)를 고려하면서 설계해야 한다. - 의존성을 인터페이스에 두고, 구체적인 구현체를 변경할 수 있도록 설계하면 유연성이 증가한다.- 일급 컬렉션의 개념을 적극적으로 활용해야겠다. - 컬렉션을 직접 노출하는 것은 유지보수 측면에서 위험하므로, 이를 감싸는 클래스를 활용하면 더 안전하다.---## 7. 기억하면 좋은 조언들### ✨ 요약- 리팩토링과 코드 리뷰는 꾸준히 해야 한다. - 직접 코드를 개선해보면서 배우는 것이 가장 좋은 학습법이다.- 오버 엔지니어링을 피하기 위해 현실적인 선택을 하자. - 너무 많은 추상화나 인터페이스는 오히려 유지보수를 어렵게 만들 수 있다.- "한계까지 사용해본 개발자가 적정 수준을 더 잘 안다." - 새로운 기술을 도입할 때는 충분히 사용해보고, 어느 수준에서 활용해야 할지 감을 잡아야 한다.---## 8. Outro### ✨ 요약- 처음부터 완벽한 추상화를 만들려고 하기보다는, 개선해 나가는 과정이 중요하다. - 개발을 하면서 추상화의 필요성이 점점 더 명확해지는 순간이 있다. - 이를 경험하면서 더 좋은 설계를 할 수 있게 된다.- 변경이 용이한 코드를 작성하는 것이 가장 중요하다. - 코드의 가독성을 유지하면서도, 변경이 필요할 때 쉽게 수정할 수 있도록 구조를 만들어야 한다.---## 최종 결론- 객체 지향 설계의 핵심은 변경에 유연한 구조를 만드는 것 - 좋은 코드는 단순히 동작하는 코드가 아니라, 이해하기 쉽고 유지보수하기 쉬운 코드 - 완벽한 설계는 존재하지 않으며, 지속적인 개선을 통해 더 나은 구조를 찾아가는 과정이 중요하다.  

백엔드클린코드

동동

[인프런 워밍업 클럽_3기 CS] 두번째 발자국 🐾🐾

📌 이 글은 워밍업 클럽 3기 감자님의 CS 강의인 ‘그림으로 쉽게 배우는 자료구조와 알고리즘’과 ‘그림으로 쉽게 배우는 운영체제’를 학습하며 정리한 내용을 담고있습니다. 🙇‍♂1⃣ 자료구조와 알고리즘📌 1. 재귀 (Recursion)재귀 개념재귀란, 자기 자신을 호출하는 방식으로 문제를 해결하는 기법콜 스택 (Call Stack)을 사용하여 함수 호출을 관리대표적인 예 : 팩토리얼 계산, 하노이 탑 문제 하노이 탑 (Tower of Hanoi)원반을 규칙에 맞게 기둥 사이로 이동시키는 문제재귀 호출을 활용하여 해결 가능const hanoi = (count, from, to, temp) => { if (count == 0) return; hanoi(count - 1, from, temp, to); console.log(`원반 ${count}를 ${from}에서 ${to}로 이동`); hanoi(count - 1, temp, to, from); }; hanoi(3, 'A', 'C', 'B');재귀적으로 생각하는 두 가지 패턴단순히 반복 실행하는 방식하위 문제의 결과를 기반으로 현재 문제를 계산하는 방식 (하향식 계산) 📌 2. 정렬 알고리즘버블 정렬 (Bubble Sort)인접한 두 데이터를 비교하며 정렬하는 방식시간 복잡도 : O(n²) (비효율적)장점 : 이해하기 쉽고 구현이 간단함단점 : 성능이 좋지 않음for (let i = 0; i < arr.length - 1; i++) { for (let j = 0; j < arr.length - i - 1; j++) { if (arr[j] > arr[j + 1]) { let temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } 선택 정렬 (Selection Sort)가장 작은 값을 선택하여 앞으로 이동시간 복잡도 : O(n²)장점 : 이해하기 쉽고 구현이 간단함단점 : 성능이 좋지 않음for (let i = 0; i < arr.length - 1; i++) { let minValueIndex = i; for (let j = i + 1; j < arr.length; j++) { if (arr[j] < arr[minValueIndex]) { minValueIndex = j; } } let temp = arr[i]; arr[i] = arr[minValueIndex]; arr[minValueIndex] = temp; } 2⃣ 운영체제📌 1. 운영체제 개요운영체제의 역할프로세스 관리 : CPU 스케줄링, 멀티태스킹메모리 관리 : 프로세스 메모리 할당파일 및 입출력 관리 : 파일 시스템, 장치 드라이버 제어컴파일 과정test.c -> 전처리기 -> test.i -> 컴파일러 -> test.s -> 어셈블러 -> test.o -> 링커 -> test.exe전처리기 : #include, #define 등을 처리컴파일러 : C 코드를 어셈블리 코드로 변환어셈블러 : 어셈블리 코드를 기계어로 변환링커 : 실행 가능한 바이너리 파일 생성 📌 2. 프로세스 스케줄링FIFO (First In First Out)도착 순서대로 CPU를 할당장점 : 구현이 간단하고 공정함단점 : 실행 시간이 긴 프로세스가 먼저 도착하면 대기 시간이 증가 SJF (Shortest Job First)실행 시간이 짧은 프로세스를 우선 실행단점 : 프로세스의 실행 시간을 미리 예측하기 어려움 RR (Round Robin)타임 슬라이스(Time Slice)를 사용하여 프로세스를 순환 실행타임 슬라이스가 너무 작으면 문맥 전환 비용이 증가하여 비효율적 MLFQ (Multi-Level Feedback Queue)CPU Bound Process와 I/O Bound Process를 구분하여 처리CPU Bound Process : CPU 사용 시간이 길면 낮은 우선순위 큐로 이동I/O Bound Process : CPU를 짧게 사용하며 높은 우선순위 큐 유지 📌 3. 프로세스 간 통신공유 자원과 임계 구역공유 자원 : 여러 프로세스가 공동으로 사용하는 변수, 메모리, 파일임계 구역 (Critical Section) : 한 번에 하나의 프로세스만 접근해야 하는 구역 임계 구역 문제 해결을 위한 3가지 조건하나의 프로세스만 접근 가능여러 요청이 있을 경우 순차적으로 접근 허용임계 구역에 들어간 프로세스는 빠르게 종료해야 함 세마포어 (Semaphore)동기화 기법으로 공유 자원에 대한 접근을 제한 모니터 (Monitor)세마포어의 단점을 보완한 기법프로그래밍 언어 수준에서 지원 (synchronized 키워드 사용) 📌 4. 데드락 (교착 상태)여러 프로세스가 서로 자원을 기다리며 작업이 멈추는 상태 데드락 발생 조건 (4가지)상호 배제 (Mutual Exclusion) : 한 번에 하나의 프로세스만 자원 사용 가능비선점 (No Preemption) : 자원을 강제로 빼앗을 수 없음점유와 대기 (Hold and Wait) : 자원을 점유한 상태에서 추가 자원을 기다림원형 대기 (Circular Wait) : 프로세스들이 서로 자원을 기다리며 원형 구조 형성 데드락 해결 방법교착 상태 회피 (Deadlock Avoidance) 자원 할당 시 교착 상태 발생 여부를 예측은행원 알고리즘 (Banker’s Algorithm) 사용하여 안전 상태 유지교착 상태 검출 및 해결가벼운 교착 상태 검출 : 일정 시간 동안 프로세스가 멈춰 있으면 강제 종료무거운 교착 상태 검출 : 운영체제가 직접 프로세스의 자원 사용을 모니터링 후 해결 📌 5. 메모리 관리메모리 종류레지스터 : CPU 내부의 가장 빠른 기억 장치 (휘발성)캐시 메모리 : CPU가 미리 가져온 데이터를 저장하는 고속 메모리메인 메모리 (RAM) : 실제 운영체제와 프로세스가 올라가는 공간 (휘발성)보조 저장 장치 (HDD, SSD) : 비휘발성 메모리 메모리 할당 방식가변 분할 방식 (Segmentation) : 프로세스 크기에 맞게 메모리를 할당고정 분할 방식 (Paging) : 프로세스 크기와 관계없이 일정한 크기로 할당 버디 시스템 (Buddy System)2의 승수 단위로 메모리를 분할하여 할당내부 단편화 최소화 & 프로세스 크기에 따라 유동적 할당 가능 3⃣ 회고첫 주차에 듣지 못했던 강의를 들으면서 다시 정상적으로 강의를 듣기 시작했다. 🙇‍♂ 재귀함수 강의 중 하노이 탑 내용은 혼자서 시도를 해보면 절대 구현을 못해낼 거 같다... 이 부분을 다시 공부해야할 것 같습니다 ㅠㅠ.. 이번 2주차 강의를 들으면서 자료구조와 알고리즘은 되게 묵직한 그런 느낌이고, 운영체제는 뭔가 이 컴퓨터란 존재에 대해서 다시 생각해보는 강의였던 것 같습니다..! 🐾🐾

인프런워밍업클럽CS

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

회고2주차에도 많은 것을 학습하였습니다. 특히, 7일차 미션에서 직접 리팩토링을 진행해본점이 인상깊었습니다.강의를 들으면서 이해했다고는 생각했지만, 막상 실제로 적용해보려니 어려웠고, 배웠던 개념을 떠오르기가 쉽지않았습니다. 그 후 강의를 들으면서 부족한점을 채워가면서 복습도 되고 좋았습니다! 또한 같은 수강생분들의 코드를 보면서 배울점도 많았습니다. 남은 주차와 테스트 강의도 열심히 듣고 참여하겠습니다!강의 내용 요약섹션 6. 코드 다듬기1⃣ 주석의 양면성주석이 많다는 것은 비즈니스 요구사항을 코드에 제대로 녹이지 못했다는 신호만약 의사 결정의 히스토리를 코드로 파악할 수 없다면, 상세한 설명이 필요하다.하지만, 불필요한 주석은 오히려 가독성을 해치므로 최소화하는 것이 중요하다.2⃣ 변수와 메서드의 배치 순서변수는 사용되는 순서대로 나열하여 인지적 경제성을 높인다.공개 메서드(Public)는 기준을 가지고 배치하고, 비공개 메서드(Private)는 공개 메서드의 호출 순서에 맞춰 정리하는 것이 좋다.3⃣ 패키지 구조 설계패키지는 문맥을 제공하는 역할을 한다.패키지를 너무 크게 두면 관리가 어렵고, 반대로 너무 세분화해도 유지보수가 어렵다.처음부터 신중하게 패키지 구조를 고민하고 설계해야 한다. 4⃣ IDE의 도움받기코드 스타일을 유지하면 가독성이 향상된다.자동 포맷팅, 린트 도구, 코드 스타일 설정 등을 적극 활용하자.섹션 8. 기억하면 좋은 조언들1⃣ 능동적 코드 읽기복잡한 코드나 난잡한 코드를 읽을 때, 그냥 이해하려 하지 말고 리팩토링하며 읽자.핵심 목표는 코드를 이해하는 것이 아니라, 도메인 지식을 늘리는 것이다.2⃣ 오버 엔지니어링 피하기필요 이상의 복잡한 설계를 하는 것은 불필요하다.적정 수준의 설계를 유지하고, 꼭 필요한 곳에만 적용하자.3⃣ 은탄환은 없다현실적인 소프트웨어 개발은 빠른 결과물과 기술 부채 간의 균형을 맞추는 과정이다.모든 기술과 방법론은 적정 수준에서만 활용해야 한다. Practical Testing (실전 테스트)섹션 2. 테스트는 왜 필요할까?사람이 직접 테스트하면 예측하지 못한 사이드 이펙트(부작용)가 발생할 가능성이 높다.테스트 코드를 작성하면 빠른 피드백, 자동화, 안정감을 확보할 수 있다.테스트는 귀찮더라도 소프트웨어의 품질을 보장하기 위해 필수적이다.섹션 3. 단위 테스트 (Unit Test)✅ JUnit5로 단위 테스트하기단위 테스트: 작은 코드 단위를 독립적으로 검증하는 테스트JUnit5: 자바의 대표적인 단위 테스트 프레임워크AssertJ: 테스트 코드 작성을 더 간결하고 명확하게 도와주는 라이브러리✅ 테스트 케이스 세분화하기암묵적인 요구사항이 있는지 고민하자.해피 케이스(정상적인 입력) & 예외 케이스(잘못된 입력)에 대한 테스트를 함께 고려해야 한다.✅ 테스트하기 어려운 영역을 분리하기테스트하기 어려운 부분을 외부로 분리하면 테스트 가능성이 높아진다.예를 들어, DB 접근 로직을 인터페이스로 분리하면 더 쉽게 테스트할 수 있다.섹션 4. TDD (Test-Driven Development)TDD는 프로덕션 코드보다 테스트 코드를 먼저 작성하는 개발 방법론이다.TDD 3단계:실패하는 테스트 작성 (프로덕션 코드 없이 테스트부터 작성)테스트를 통과하는 최소한의 코드 작성 (엉터리라도 우선 통과)리팩토링하여 코드 개선섹션 5. 테스트는 문서다✅ 테스트는 곧 문서다테스트 코드는 프로덕션 코드의 동작을 설명하는 문서 역할을 한다.@DisplayName을 활용하여 테스트 의도를 명확하게 기술하자.✅ 테스트 네이밍 가이드라인명사의 나열보다는 문장으로 작성하기테스트 행위에 대한 결과까지 기술하여 명확한 의도를 전달하기도메인 용어를 사용하여 한층 추상화된 내용을 담기✅ BDD 스타일로 작성하기BDD (Behavior-Driven Development, 행위 주도 개발) 방식은 테스트를 더 직관적으로 만든다.Given / When / Then 패턴을 활용하여 테스트를 구조화하면 가독성이 향상된다.@DisplayName("주문 목록에 담긴 상품들의 총 금액을 계산 할 수 있다.") @Test void calculateTotalPrice() { //given CafeKiosk cafeKiosk = new CafeKiosk(); Americano americano = new Americano(); Latte latte = new Latte(); cafeKiosk.add(americano); cafeKiosk.add(latte); //when int totalPrice = cafeKiosk.calculateTotalPrice(); //then assertThat(totalPrice).isEqualTo(8500); }✅ 테스트가 읽기 쉬워지고, 테스트가 곧 문서 역할을 하게 됨 미션Day 7 -리팩토링 연습https://github.com/5jeong/readable-code/tree/main/src/main/java/cleancode/mission/day7리팩토링을 진행하고, 강의내용과 남들의 코드를 보니 부족함을 많이 느꼈다. 그만큼 얻는것도 많았다!

2주차 발자국 🐾 - 인프런 워밍업 클럽 PM 스터디 3기

학습 요약유저를 직접 만나야, 고객의 멘탈 모델을 더 정확하게 알 수 있다. 고객 리서치에는 심층 인터뷰, 사용성 테스트 등이 있다.리서치를 할 때는 “어떤 의사결정을 위해 리서치를 하는지”에 대해 정의하고 설계하는 것이 중요하다.심층 인터뷰를 할 때는 경험을 구체적으로 물어보는 것이 중요하며 유도 질문을 하지 않아야 한다. 후속 질문을 계속해 심층적으로 파악해야 한다.사용성 테스트를 할 때는 과업을 수행하게 하고 질문을 하며 올바른 멘탈 모델을 가질 수 있는지 파악할 수 있다. 학습 회고어떻게 유저 리서치를 하면 효과적으로 할 수 있을지에 대해 알게 되었다. 개발자 커뮤니티를 하며 사이드 프로젝트 관련 설문조사 모집하는 글을 보거나 회사에서 PM 분들이 인터뷰하는 걸 본적이 있는데 설계자 관점에서 보는 부분이 흥미로웠다.가장 중요한 것은 의도를 가지고 (의사결정을 위한 리서치) 목표를 명확히 해야 한다는 것. 얼마 전에 회사에서 10명으로 인터뷰를 했었는데 수가 굉장히 적다고 생각했는데 의외로 많은 사람을 인터뷰 하는 것이 중요한 게 아니라는 점에 대해 알게 됨. 언뜻봐서 유저 인터뷰, 사용성 테스트 같은 것이 쉽다고 생각했는데 직접 미션을 수행해보니 큰 오산이었다는 것을 알게 되었다. 이 부분에 대해 설계 과정을 직접 보여주셔서 이해가 더 쉬웠고 따라하기 좋았다. 미션 회고막상 강의를 들었음에도 리서치를 설계하려니 막막해 강의와 PPT를 다시 보며 한 단계씩 따라가 보았다.자꾸 "00했을 때 00할 것 같나요?" 등의 유도 질문을 나도 모르게 적게 되었다. 이걸 유도하지 않고 열린 질문으로 바꾸는 게 어려웠다. 유도를 적게 하면서 인터뷰 참가자에게 원하는 정보를 얻는 것은 생각을 많이 해야 되는 것 같았다. 다른 사람들의 고객 인터뷰 사례를 많이 보고 어떤 질문하는지 봐야겠다고 생각했다. 2주 전에 회사 PM 분들이 인터뷰 설문지와 결과를 공유해주신 적이 있는데 사실 나는 저런 질문들이 효과가 있나? 원하는 정보를 얻을 수 있을까 생각했는데 강의를 듣고 미션을 하고 나서 아 다 의도와 목표가 있는 질문이었구나 알게 됨.

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

s6511s45

[2주차] 인프런 워밍웝 클럽 Backend

인프런 워밍업 클럽 스터디 3기 -백엔드 프로젝트(Kotlin) 2주차 발자국 입니다. 강의내용 간단한 정리데이터베이스 초기화애플리케이션이 시작될 때 필요한 기본 데이터를 DB에 미리 삽입하는 역할을 합니다 @Component @Profile(value = ["default"]) class DataInitializer( private val achievementRepository: AchievementRepository, private val introductionRepository: IntroductionRepository, private val linkRepository: LinkRepository, private val skillRepository: SkillRepository, private val projectRepository: ProjectRepository, private val experienceRepository: ExperienceRepository ) {@Profile : 환경변수 설정을 정할 수 있다.@Component : Bean Configuration 파일에 Bean을 따로 등록하지 않도록 도와준다. 리포지토리 개발스프링에서 제공하는 Spring Data JPA를 사용하면, 인터페이스 상속만으로 기본적인 CRUD 기능을 사용할 수 있다.도메인에 종속되는 기능이라도 메소드명 네이밍 규칙을 따르면 그에 맞는 쿼리를 자동으로 생성해주기도 합니다.//select * from skill where name : name and skill_type = :type fun findByNameIgnoreCaseAndType(name: String, type: SkillType):Optional<Skill> @Query("select e from Experience e left join fetch e.details where e.id = :id") override fun findById(id: Long): Optional<Experience> }@Query : SQL과 유사한 JPQL (Java Persistence Query Language) 라는 객체지향 쿼리 언어를 통해 복잡한 쿼리 처리를 지원합니다.  N+1문제JPA를 사용할 때, 연관된 엔티티를 조회할 때 추가적인 쿼리가 다량으로 발생하는 문제를 N+1 문제라고 합니다.먼저 부모 테이블에서 조회를 한 후, 엔 티티의 연관관계를 바탕으로 조회해온 데이터의 개수만큼 부모에 매핑된 자식 테이블의 데이터를 조회하기 위해 데이터베이스를 호출합니다.해결방법으로는 FetchType은 Eager을 사용하거니 default_batch_fetch_size: 10 사이즈를 조절해서 해결하는 방법이 있다.@Query 를 사용하여 JOIN FETCH을 사용함으로써 해결 할 수 있다. DTO개발엔티티(Entity) 자체를 노출하는 대신, 필요한 데이터만 전달합니다.엔티티 그대로 노출 시 불필요한 데이터까지 포함될 위험이 있습니다.필요 없는 필드를 제외하여 네트워크 트래픽 감소시킬 수 있습니다.data class AchievementDTO( val title: String, val description: String, val host: String, val achievedDate: String? ) 컨트롤러 개발@Controller 와 @RestController 를 사용할 수 있다.@Controller는 웹 페이지를 반환 할 때 사용하고, @RestController는 데이터를 반환할 경우 사용한다.@GetMapping Get매소드를 알려준다. 회고회사 다니면서 피곤하다는 핑계로 조금씩 미루다 보니, 어느새 강의만 겨우 따라가는 수준이 되어버렸다. 처음엔 하루만 쉬자는 생각이었는데, 점점 습관처럼 미루게 됐다. 결국 복습도 부족했고, 깊이 있는 공부를 할 시간도 없었다.다음 주는 미루기보다는 바로바로 시작을 해야겠다. 미루기보다는 바로 실행하고 공부를 조금씩이라도 더 해야겠다.

yeajinny

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

운영체제운영체제에 대해서 운영체제는 프로세스 관리, 메모리 관리, 하드웨어 관리, 파일 시스템 관리 등의 역할을 함커널은 프로세스와 메모리를 관리 역할 (사용자 - 인터페이스, 애플리케이션 - 시스템콜, 하드웨어 - 드라이브)폰 노이만 구조 - CPU와 메모리 사이를 버스(데이터 전달 통로)로 연결하는 구조CPU는 ALU(산술논리연산장치), 제어장치, 레지스터로 구성폴링 방식은 CPU가 주기적으로 확인이 필요, 인터럽트는 입출력 관리자가 작업이 완료되면 ISR을 실행시켜 작업프로세스와 스레드프로그램은 하드 디스크에 저장된 명령문의 집합체, 프로세스는 실행중인(메모리에 올라간 상태) 프로그램프로그램은 수동적이지만, 프로세스는 능동적으로 필요에 따라 CPU를 사용하고 입력 출력을 함.프로세스의 구조(Code, Data, Heap, Stack) 멀티프로그래밍과 멀티프로세싱(유니프로그래밍의 단점 보완)멀티 프로그래밍: 메모리에 여러개의 프로세스 올려서 처리멀티태스킹: 서로 다른 프로세스를 짧게씩 실행하며 동시에 처리하는것처럼 보이게 함CPU가 여러개라면 멀티프로세서, 이렇게 작업하는 건 멀티프로세싱PCB(Process Control Block) - 프로세스의 정보 저장(연결리스트 구조)프로세스의 상태 (생성, 준비, 실행, 대기, 완료)컨텍스트 스위칭다른 프로세스 실행을 위해 프로세스 상태를 저장하고 다른 프로세스 상태값으로 교체프로세스 생성 시에 기존의 프로세스를 fork로 복사해서 사용(자식 프로세스)쓰레드 - 한 프로세스 내에 여러개 있을 수 있으며, PCB, 데이터, 코드, 힙영역을 공유(스택은 고유)TCB(Thread Control Block), TID(쓰레드 아이디)프로세스는 독립적이어서 안정적, 쓰레드는 프로세스에 문제가 생기면 전체 문제 생겨서 불안정적프로세스는 고유한 영역, IPC로 통신해 오버헤드 큼, 쓰레드는 데이터 공유가 가능해 오버헤드가 작음CPU 스케쥴링준비, 대기 상태는 큐로 관리PCB는 다중 큐에 들어가서 준비 상태, CPU 스케쥴러가 결정해서 실행 상태로 전화시킴목표: 리소스 사용률, 오버헤드 최소화, 공평성, 처리량, 대기시간, 응답시간스케쥴링 알고리즘FIFO: 먼저 들어온 순서대로 작업(실행시간에 따라 유동적으로는 작업X, I/O작업으로 인한 비효율)SJF(Shortest Job First): 짧은 작업 먼저(시간 예측 힘듦, 긴 프로세스는 너무 오래 대기)RR(Round Robin): 모두 공평한 Time Slice를 쓰고 다음 프로세스에게 뺏김(컨텍스트스위칭 시간 고려 필요)MLFQ(Multi Level Feedback Queue): Time slice를 작게 쓰고, 프로세스의 구분에 따라 다르게 줌자료구조와 알고리즘자료구조와 시간 복잡도자료구조는 데이터가 어떤 구조로, 저장, 사용되는지 나타냄알고리즘은 문제를 해결하기 위한 방법(자료구조에 영향을 받음)시간 복잡도란 특정 알고리즘이 문제를 해결하는데 걸리는 시간 (반복문을 최소화 하는 것이 목표)big-O 표기법은 계산량이 얼마나 늘었는지 표현법이므로 정확하지 않음(상수는 무시, 가장 큰 영향의 숫자만 표기)배열운영체제는 배열의 주소를 기억하고 데이터를 가져옴인덱스 참조는 길이에 상관X, 한번에 가져오기 때문에 높은 효율 -> O(1) 그러나 삽입, 삭제 성능은 좋지않음연결리스트데이터를 분산 저장 후 서로 연결 (노드를 사용)추가, 삭제는 데이터 연결 부분을 수정만 하면 되서 간단, 참조는 다 따라가서 봐야해서 효율 나쁨스택FILO구조, 먼저 들어간 데이터가 나중에 나옴배열, 연결리스트로 구현 가능(head사용)큐FIFO구조, 먼저 들어간 데이터가 먼저 나옴먼저 들어간 데이터 삭제시, head부터 다 따라가야 나오므로, tail추가 해서 구현tail에 있는걸 삭제해도 tail도 업데이트가 필요하므로 양방향 변경 필요덱데이터 삽입, 삭제를 head와 tail에서 자유롭게 가능해시테이블인덱스로 배열에 접근(빈공간 발생 가능), 특정 숫자를 배열에 넣기 위해 하는 연산인 해시 함수 필요하나의 인덱스에 여러개의 데이터 들어가는 문제 발생시, 연결리스트로 해결 가능데이터 삽입, 탐색, 삭제가 효율적이나 공간 효율이 나쁘고 해시 함수 구현이 필수적셋데이터 중복을 허용하지 않는 자료구조value는 사용X, Key만 사용 칭찬할 점: 강의를 여러번 들은 게 잘한 것 같습니다. 2~3번 정도 들으니 머리에 더 잘 들어오는 것 같아요.보완할 점: 목~금에 강의가 좀 밀렸습니다. 앞으론 밀리는 일 없게 오며가며 계속 들어야 할 것 같습니다.다음 주 목표: 다음주에는 자바스크립트 공부를 좀 더 해서 자료구조 부분은 제가 복습하면서 더 활용해보고 싶습니다.   

워밍업클럽cs

[인프런 워밍업 클럽 3기] CS - 2주차 미션

운영체제 FIFO 스케줄링의 장단점이 뭔가요?장점: 구현이 간단, 공정한 실행 순서, 기아 현상 없음단점: 평균 대기 시간이 길어질 수 있음, 짧은 프로세스가 긴 프로세스 뒤에서 대기 SJF를 사용하기 여러운 이유가 뭔가요?프로세스의 실행 시간을 미리 정확히 예측하기 어려움예측 오류로 최적화 효과 감소기아 현상 발생 가능성RR 스케줄링에서 타임 슬라이스가 아주 작으면 어떤 문제가 발생할까요?문맥 교환(context switch) 오버헤드 증가CPU 효율성 저하프로세스 실행보다 스케줄링에 더 많은 시간 소비운영체제가 MLFQ에서 CPU Bound Process와 I/O Bound Process를 어떻게 구분할까요?운영체제는 프로세스가 얼마나 오랫동안 CPU를 사용하는지를 기반으로 CPU Bound와 I/O Bound 프로세스를 구분하고, I/O Bound 프로세스는 상위 우선순위로, CPU Bound 프로세스는 하위 우선순위로 배치공유자원이란무엇인가요?여러 프로세스나 스레드가 동시에 접근하여 사용할 수 있는 자원메모리, 파일, 데이터베이스, 입출력 장치 등교착상태에 빠질 수 있는 조건은 어떤 것들을 충족해야할까요?상호 배제: 자원을 한 번에 한 프로세스만 점유.점유 및 대기: 자원을 점유한 상태에서 다른 자원을 기다림.비선점: 자원을 강제로 빼앗을 수 없음.순환 대기: 프로세스들이 자원을 순환적으로 기다림. 자료구조와 알고리즘재귀함수에서 기저조건을 만들지 않거나 잘못 설정했을 때 어떤 문제가 발생할 수 있나요?0부터 입력 n까지 홀수의 합을 더하는 재귀 함수를 만들어보세요.function sumOdd(n){ // 재귀 로직 } console.log(sumOdd(10)) // 25 1 ) 무한 재귀 호출이 발생하여 스택 메모리가 넘쳐서 Stack Overflow 에러가 발생할 수 있습니다. 재귀 함수가 종료되지 않고 계속해서 자신을 호출하는 문제가 생깁니다. 2) function sumOdd(n) { if (n <= 0) return 0; // 기저조건: 0 이하일 경우 합이 0 if (n % 2 !== 0) return n + sumOdd(n - 1); // 홀수일 경우 더하고 다음 재귀 호출 return sumOdd(n - 1); // 짝수일 경우 다음 재귀 호출 } console.log(sumOdd(10)); // 25   다음 코드는 매개변수로 주어진 파일 경로(.는 현재 디렉토리)에 있는 하위 모든 파일과 디렉토리를 출력하는 코드입니다. 다음 코드를 재귀 함수를 이용하는 코드로 변경해보세요.변경 이전 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("."); // 현재 경로의 모든 하위 경로의 파일, 디렉토리 출력  변경 이후function traverseDirectory(directory) { const files = fs.readdirSync(directory); // 인자로 주어진 경로의 디렉토리에 있는 파일or디렉토리들 for (const file of files) { const filePath = path.join(directory, file); //directory와 file을 하나의 경로로 합쳐줌 const fileStatus = fs.statSync(filePath); // 파일정보 얻기 if (fileStatus.isDirectory()) { // 디렉토리라면 console.log('디렉토리:', filePath); traverseDirectory(filePath); // 재귀 호출로 하위 디렉토리 순회 } else { // 파일이라면 console.log('파일:', filePath); } } } traverseDirectory("."); // 현재 경로의 모든 하위 경로의 파일, 디렉토리 출력

동동

[인프런 워밍업 클럽_3기 CS] 2주차 자료구조와 알고리즘 미션 🐾🐾

자료구조와 알고리즘1. 재귀함수에서 기저조건을 만들지 않거나 잘못 설정했을 때 어떤 문제가 발생할 수 있나요?기저 조건이 없으면 함수가 무한히 호출되어 스택 오버플로우가 발생된다. 2. 0부터 입력 n까지 홀수의 합을 더하는 재귀 함수를 만들어보세요.function sumOdd(n){ if (n <= 0) return; if (n % 2 === 1) { return n + sumOdd(n - 2); } else { return sumOdd(n - 1); } } console.log(sumOdd(10)) // 25 2. 다음 코드는 매개변수로 주어진 파일 경로(.는 현재 디렉토리)에 있는 하위 모든 파일과 디렉토리를 출력하는 코드입니다.다음 코드를 재귀 함수를 이용하는 코드로 변경해보세요. 기존 코드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("."); // 현재 경로의 모든 하위 경로의 파일, 디렉토리 출력 재귀함수 코드const fs = require("fs"); // 파일을 이용하는 모듈 const path = require("path"); // 폴더와 파일의 경로를 지정해주는 모듈 function traverseDirectory1(directory) { const files = fs.readdirSync(directory); for (const file of files) { const filePath = path.join(); const fileStatus = fs.statSync(filePath); if (fileStatus.isDirectory()) { console.log('디렉토리:', filePath); traverseDirectory1(filePath); } else { console.log('파일:', filePath); } } } traverseDirectory1("."); // 현재 경로의 모든 하위 경로의 파일, 디렉토리 출력

인프런워밍업클럽CS

동동

[인프런 워밍업 클럽_3기 CS] 2주차 운영체제 미션 🐾🐾

운영체제 1. FIFO 스케줄링의 장단점이 뭔가요?장점구현이 간단하고 공정한 방식CPU를 먼저 요청한 순서대로 처리하기 때문에 이해하기 쉽다.단점실행 시간이 긴 프로세스가 먼저 도착하면, 이후 프로세스들의 대기 시간이 길어짐.I/O 작업을 포함한 프로세스가 있으면 CPU 사용률이 저하됨.평균 대기 시간이 증가할 수 있어 비효율적이다. 2. SJF를 사용하기 여러운 이유가 뭔가요?프로세스의 실행 시간을 사전에 알 수 없음.실행 시간이 긴 프로세스는 무한정 대기할 수도 있음. 3. RR 스케줄링에서 타임 슬라이스가 아주 작으면 어떤 문제가 발생할까요?컨텍스트 스위칭이 너무 자주 발생하여 오버헤드가 커짐.CPU 성능이 저하되고 비효율적인 실행이 발생한다. 4. 운영체제가 MLFQ에서 CPU Bound Process와 I/O Bound Process를 어떻게 구분할까요?CPU Bound ProcessCPU 연산을 많이 사용하는 프로세스긴 CPU Burst를 가지며, 우선순위가 낮은 큐로 이동한다.I/O Bound ProcessI/O 작업이 많아 CPU를 짧게 사용함.짧은 CPU Burst를 가지며, 우선순위가 높은 큐에서 처리된다. 5. 공유자원이란무엇인가요?여러 프로세스가 공동으로 사용하는 변수, 파일, 메모리 등의 자원을 의미한다.공유 자원을 관리하지 않으면 경쟁 조건이 발생할 수 있다.동기화 기법을 활용해 임계 구역 문제를 해결해야 한다. 6. 교착상태에 빠질 수 있는 조건은 어떤 것들을 충족해야할까요?상호 배제 : 한 번에 하나의 프로세스만 자원을 사용 가능.비선점 : 자원을 강제로 빼앗을 수 없음.점유와 대기 : 프로세스가 자원을 점유한 상태에서 추가 자원을 기다림.원형 대기 : 프로세스들이 서로 자원을 기다리며 원형 구조를 형성한다. 

인프런워밍업클럽CS

워밍업 클럽 3기 BE 클린코드 (2주차 발자국) - 값진 경험을 하다

값진 경험을 하다대학교 때부터, 취준시절, 그리고 실무를 하고 있는 현재까지 단 한번도 객체지향적인 사고 방식으로 리팩토링을 하겠다고 마음먹었던 적은 없었다. 하지만 이번주에 처음으로 객체지향을 적용시키는 경험을 하였고, 이는 굉장히 값진 경험이었다. 배웠던 내용을 요약하자면.. 지난주 커리큘럼은 이론 위주였다면, 이번 주 커리큘럼에서 배울 수 있었던 것은 미션을 통한 리팩토링 실전 경험이었다. 리팩토링/클린코드에 필요한 자잘한 팁 (주석, 패키지 분리 등등..) 도 배울 수 있었지만 미션에서 얻었던 지식 적용 경험(?) 이 나에게는 가장 큰 수확이었다. 미션과정에서 느꼈던 감정은 아래에 정리해보도록 하겠다.미션 과정에서 느꼈던 점3일정도 미션 내용을 수행하기 위해 노력했기에 그만큼 얻었던 점들이 많았던 것 같다.특히 중복 로직 제거, 일급 컬렉션 적용, 추상화의 수준을 맞추는 메서드 추출 경험은 나 자신에게 칭찬할만한 경험이라고 생각했다. 실제로 지식공유자이신 박우빈님과 일치된 생각으로 비슷하게 리팩토링이 이루어졌다는 것을 확인했을 때, 참 뿌듯했다. 또한, 일급 컬렉션이라는 개념 자체를 이번 강의에서 처음 알게 되었는데 이를 실제 리팩토링 과정에 적용해보면서 필요 이유를 직접적으로 느끼게 되면서 실무에도 적용해보는 순간을 기대하는 중이다.하지만, 부족했던 점도 도드라졌다. 특히 SRP/OCP부분이다. 나름대로 객체의 역할을 분리하기 위해 노력했는데 생각보다 이를 적용한 포인트는 한,두군데 밖에 되지 않았다. 고작 csv 파일을 parsing하기 위한 CsvParser 객체를 둔 점..? 그정도인데, 내가 생각했던 것 보다 기존 코드에서 객체의 역할을 분리할 곳이 훨씬 많았다는 점에서 좀 아쉬웠다. 뭔가 기존 코드를 바라보는 습관때문이었던 것 같다. 한번도 객체지향적으로 리팩토링해보려고 하지 않았으니, 이러한 시야가 트이지 않았던 점이 문제가 아닐까 싶다. 그래서 지금부터라도 그런 시야를 키워보기로 했다! 그리고 지식고유자님이 StudyCafePass라는 인터페이스를 두고 SeatPass와 LockerPass를 구현한 점에서 신선한 충격을 느꼈다. 아, 이래서 인터페이스를 쓰는거구나 라는 확실한 감이 생겨서 비록 실질적으로 내가 구현한 내용은 아니지만, 왠지 모르게 나도 다음엔 이렇게 해볼 수 있을 것 같다. 라는 자신감을 가졌다! 좋은 경험을 할 수 있었던 한주였다.다음주부터 테스트코드를 작성해볼 텐데, 기존에 내가 테스트코드에 대해 가지고 있던 상식들이 또 어떻게 부숴질지 기대하는 중이다.  

백엔드리팩토링클린코드

채널톡 아이콘