블로그

별안간뿌우

[인프런 워밍업 클럽_3기 백엔드 프로젝트]2번째 발자국

지금부터는 실습 위주라 발자국을 자세하게 남기긴 힘들 것 같다. 데이터 베이스 초기화를 하여 데이터를 삽입을 하는 작업을 한다.코틀린을 써본 적이 없어서 아직 너무 미숙하다. 그리고 뭐가 뭔진 잘 모르겠지만 지금 데이터를 넣을 때 mutableListof 라는 메서드를 이용하여 삽입하고 있다.그리고 데이터를 삽입할 때컬럼이 여러개일 경우 그 컬럼의 값이 안 들어가게 되면 오류가 난다. 값이 여러개 일 경우 mutableListof 를 사용하여 리스트화 해서saveall 이라는 키워드를 사용해 값을 집어 넣는다.saveall은 영속성으로 값을 집어 넣는 것이다.실습을 하던 도중 Error creating bean with name '*': Invocation of init method failed이 에러가 떠 인터넷에 찾아보다가 강의를 다시 들으며 오타를 낸 부분이 있나 찾아봤더니 skill부분에 project로 의존주입을 해서 에러가 난 거였다. 테스트 코드는 매우 중요하다.인텔리제이는 테스트코드를 작성하기 매우 용이하다테스트 패키지안에 코틀린 파일을 만든다그리고 어노테이션을 @DataJpaTest 이것을 부착해준다.@DataJpaTest은 필요한 기능들만 초기화해준다롤백을 안해주면 다음 테스트에 영향을 미칠 수 있다 트랜잭션 어노테이션을 달아준다 @TestInstance(TestInstance.Lifecycle.PER_CLASS)한번 만들어주고 클래스 단위로 돌아가게 해준다. Assertions.assertThat(beforeInitialize).hasSize(0)테스트 통과 실패여부를 알려주는 코드

윤선미

인프런 워밍업 클럽 3기 :: 백엔드 프로젝트 2주차 발자국

강의입문자를 위한 Spring Boot with Kotlin - 나만의 포트폴리오 사이트 만들기https://inf.run/WM5mW실습뼈대를 갖추고 본격적인 실습을 진행했는데 포트폴리오 패키지 내 domain, presentation 패키지 2개로 나누어 개발을 진행하였습니다.Entity에 의해 생성된 DB에 접근하는 메서드들을 사용하기 위한 인터페이스인 Repository를 만들어 JPA를 통한 쿼리를 만들어 냈으며 테스트 코드를 작성하여 쿼리 호출의 흐름을 파악 할 수 있었던 2주차 강의였습니다.JPA에서 일어날 수 있는 N+1 이슈를 다뤄본 경험과 함께 포트폴리오 개발에 앞서,다양한 패키지를 만들고 그 안에 controller, sevice 테스트 코드를 통한 테스트를 진행 후 Thymeleaf를 통해 부트스트랩 템플릿 수정까지 진행하여 포트폴리오를 만들 수 있도록 개발 작업을 수행하고 있습니다.미션 REST API 설계하기조회 REST API 만들기 '프랜차이즈 커피 매장 관리 시스템' 이란 주제를 가지고 간단하게 CRUD를 구현하였습니다.일대 다 구조의 E-R 다이어그램을 설계하여 총 테이블은 4개로 구성하였고, 매장관리 / 직원관리 / 메뉴관리의 대분류를 만들고 그 안에서 기능 API를 설계하는 미션을 수행했습니다.REST API 설계 원칙은 검색을 통해 찾아 규칙에 맞게 설계하도록 했으며 각 대분류 내 CRUD를 만들었습니다. 조회 REST API 의 경우 매장 조회, 직원 조회, 메뉴 조회에 대한 조회 REST API를 설계 했으며 GET메소드로 조회를 할 수 있습니다.더해 API 상태 코드를 추가하여 200 코드를 받았을 경우, 요청 성공이란 메시지를 확인 할 수 있습니다.회고직장 다니면서 강의 및 실습, 발자국까지 남기는 것이 버거운 느낌이 더 들었던 2주차 강의었습니다.결국 주말에 몰아서 하게 되는 상황으로 이해하지 못한 강의 내용이 있어 이 부분은 전체적인 커리큘럼이 끝난 후 재수강을 통해 부족했던 부분을 채워 나가려고 합니다!미션에 대한 설계부터 신중하게 고려해야 할 부분들을 놓치고 간 것들이 많아 계속 수정을 진행하고 있습니다.이번주 미션 제출 전 수정 사항이 좀 더 줄어들 수 있도록 꼼꼼히 살펴 봐야 할 것 같습니다 🙂

백엔드

백엔드-코드 발자국 2주차

2주차, 코드 다듬기와 관련된 내용을 학습했다. 수업을 수강하기 전까지는 다른 팀원과 협업을 할 때, 주석을 친절히(?) 달아주어 내가 작업한 내용을 설명해주는 것이 좋은 습관이라고 생각했는데,,주석이 많다는 것이 비즈니스 요구사항을 제대로 반영하지 못한 것일 수 있다는 말에 머리가 띵해졌다.. 사실 속으로는 알고 있었을지도 모르겠다.. 그 방법을 몰랐을뿐! 수업 내용중 메서드와 변수의 나열 순서만으로도 의도와 정보를 전달할 수 있다는 말씀에 큰 깨달음을 얻었다!!여태까지 학습한 내용을 바탕으로 Day-7 미션을 진행햇다. 처음에 코드를 마주했을 때, 수업에서 실습도 해보고 개념으로 배운 내용이 눈에는 보이고 어떻게 리팩토링해야할 지 생각도 들었지만, 막상 이를 수행하는 과정이 마냥 쉽지만은 않았다.특히 좌석 이용권과 사물함 이용권이 구분된다는 도메인 지식을 깨달았지만, 분리하는 과정에서 어려움을 겪었다. 인터페이스를 생성하여 이를 implements 시킬 생각을 못하고 시도하다가,, 여러 문제를 겪고 계에에속 롤백하다가 미션 제출 시기를 놓쳐버렸다.. 관련된 내용을 수업을 통해 다시 시도하고 이해하려고 노력하는 과정이 꽤나 재밌었따. 이후 드디어 Test code와 관련된 강의를 수강했다. 학교를 다니면서 프로젝트를 진행할 때는 비즈니스 로직을 구현하기에 급급했다. 그런데 테스트 코드를 통해 먼저 관련 로직을 설계하는 Test Driven Development의 맛(?)을 느낄 수 있었다.개발 과정에 훨씬 유연하고 유지보수가 쉬우며, 엣지 케이스들을 찾을 수 있다는 것을 깨달았다.중간점검 라이브 세션도 너무 좋았다. 같은 내용을 다른 사람이 짠 코드를 보고 코드 리뷰를 들어본 경험이 처음이었는데 다른 사람들의 생각을 배우고, 선생님의 피드백도 배울 수 있어서 너무 좋았따.3주차에도 Test 강의는 물론 clean code 부분도 까먹지 않기 위해 계속 실습해보고, 강의도 짬짬이 라디오처럼 들으며 체화시켜야겠다!! 완주하기 위해 남은 2주도 열심히 달려야지

ykm8864

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

학습 내용2주차 발자국입니다.1. 데이터베이스 및 리포지토리데이터베이스 초기화: H2 및 MySQL을 활용한 데이터베이스 설정과 application.yml 환경 분리리포지토리 개발: JpaRepository<T, ID> 상속을 통해 기본적인 CRUD 메서드 활용리포지토리 테스트 코드 작성: Mock을 활용한 단위 테스트 (@DataJpaTest, @MockBean)리포지토리 성능 개선: N+1 문제 해결2. 엔티티 및 서비스 개발클래스 생성: 엔티티 정의 (@Entity, @Id, @GeneratedValue)DTO 개발: 엔티티와 분리된 data class 정의로 API 응답 최적화서비스 개발: 비즈니스 로직을 @Service 클래스에서 관리하여 Controller와 역할 분리서비스 테스트 코드 작성: @InjectMocks와 @Mock을 활용한 Mockito 기반 테스트3. 컨트롤러 및 API 개발컨트롤러 개발: @RestController와 @Controller를 활용한 API 및 뷰 렌더링 처리컨트롤러 테스트 코드 작성: MockMvc를 활용하여 API 응답 검증 (@SpringBootTest, @AutoConfigureMockMvc)4. Thymeleaf 기반 UI 개발부트스트랩 템플릿 적용: Start Bootstrap을 활용한 기본 레이아웃 구성템플릿 수정index.html: 주요 콘텐츠 및 네비게이션 구성resume.html: 경력 및 기술 스택 표시projects.html: 프로젝트 목록을 동적으로 표시레이아웃: th:fragment를 활용한 네비게이션 및 푸터 분리5. 인터셉터 개발인터셉터 활용: HandlerInterceptor를 구현하여 요청 전/후 로직 추가주요 기능: 인증/인가 체크, 요청 로깅, 공통 헤더 처리Keep (만족했고, 앞으로도 지속하고 싶은 부분)리포지토리와 서비스의 명확한 역할 분리로 유지보수성이 향상된 점을 느꼈다Mock 테스트를 활용하여 서비스 및 컨트롤러 단위 테스트를 효과적으로 구현했는데, 이전에 워밍업클럽에서 테스트코드를 들어서 그런지 쉽게 이해가 됐다Thymeleaf Fragment 적용으로 중복 코드 제거 및 템플릿 유지보수 능력을 길렀다Problem (아쉬웠던 점)jpa 성능 최적화에 대한 지식이 아직 부족한 거 같아서 김영한 강사님의 강의를 수강해볼 예정Thymeleaf에서 동적 데이터 처리의 한계가 있어 React/Vue 같은 프론트엔드 연계를 고민해야 할텐데 관련하여 지식이 너무 적다 Try (다음에 시도해볼 점)N+1 성능문제 개선 및 QueryDSL을 활용한 복잡한 검색 기능 최적화API 개발 시 OpenAPI(Swagger) 문서 자동화 적용Thymeleaf 대신 React와 연동인터셉터 로직이 복잡해질 경우 AOP를 활용하는 방법도 고려할 필요가 있어보이는데 AOP 구현하는 미니프로젝트 해볼 예정

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

[인프런워밍업클럽3기] PM/PO 발자국 2주차

2주차에 고객 리서치 회고 이번 강의를 통해 PM으로서 고객을 올바르게 이해하는 방법에 대한 새로운 시각을 얻게 되었다. 그동안 나는 고객의 의견을 수집하는 과정에서 주로 영업팀이나 CS팀이 전달해주는 피드백에만 의존했다. 이는 고객의 의견을 직접 듣는 것과 동일하다고 착각한 부분이었다. 그러나 강의를 듣고 나서, 영업이나 CS팀을 통해 듣는 의견은 고객의 일부 불편한 사항만을 전달할 뿐, 고객이 진정으로 원하는 것과 필요로 하는 핵심적인 가치를 파악하기엔 부족하다는 것을 깨달았다.특히, 고객의 진짜 니즈를 알기 위해서는 심층 인터뷰와 사용성 테스트가 반드시 필요하다는 점을 알게 되었다. 심층 인터뷰를 통해서는 고객이 특정 기능을 원하는 이유와 내면에 숨겨진 니즈를 구체적으로 파악할 수 있으며, 표면적인 문제 해결에서 더 나아가 고객의 근본적인 요구사항까지도 알 수 있다는 점이 인상 깊었다. 또한 사용성 테스트를 통해 실제 사용자가 어떻게 제품을 사용하는지를 관찰하며, 고객이 겪는 불편함이나 혼란스러운 부분들을 직접적으로 확인할 수 있어 서비스의 실질적인 개선점을 발견할 수 있을 것이다.이번 학습을 계기로, 앞으로는 고객을 직접 만나거나 심층 인터뷰 및 사용성 테스트와 같은 방법을 적극적으로 활용하여 더욱 실질적이고 의미 있는 고객의 목소리를 듣고 반영하는 PM이 되어야겠다고 다짐했다. 이를 통해 고객이 진정으로 원하는 가치를 제공하고, 더욱 성공적인 제품을 만들어 갈 수 있을 것으로 기대한다.

PM/PO발자국2주차

[인프런 워밍업 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("."); // 현재 경로의 모든 하위 경로의 파일, 디렉토리 출력

강동훈

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

재귀함수에서 기저조건을 만들지 않거나 잘못 설정했을 때 어떤 문제가 발생할 수 있나요?재귀함수는 함수 내부에서 자기 자신을 다시 호출하여 작업을 수행하는 함수를 의미한다. 즉, 자기 자신을 무한대로 호출하여 작업하기 때문에 함수 종료 조건인 기저조건을 설정하지 않는다면, 해당 함수가 실행됨에 따라 무한대로 콜스택에 메모리가 얹히게 되고 스택 오버플로우가 발생하여 프로그램이 강제 종료된다.// 기저 조건 없는 경우 function factorial(n){ return n * factorial(n - 1) } // RangeError : Maxmum call stack size exceeded // 기저 조건 설정 function factorial(n) { if (n == 0) return 1; return n * factorial(n - 1); }0부터 입력 n까지 홀수의 합을 더하는 재귀 함수를 만들어보세요.하위조건 : n - 1이 홀수인지 확인하고 홀수일 경우 n을 더하고 짝수일 경우 0을 더함기저조건: n이 0 이하일 경우 0을 반환하고 함수 종료function sumOdd(n){ // 재귀 로직 if (n <= 0) return 0; let oddNum = n % 2 === 0 ? 0 : n; return oddNum + sumOdd(n - 1); } console.log(sumOdd(10)) // 25다음 코드는 매개변수로 주어진 파일 경로(.는 현재 디렉토리)에 있는 하위 모든 파일과 디렉토리를 출력하는 코드입니다. 다음 코드를 재귀 함수를 이용하는 코드로 변경해보세요.const fs = require('fs'); // 파일을 이용하는 모듈 const path = require('path'); // 폴더와 파일의 경로를 지정해주는 모듈 function traverseDirectoryRecursive(directory) { const files = fs.readdirSync(directory); // 1. 인자로 받은 폴더 내부 파일들 추출 for (const file of files) { const filePath = path.join(directory, file); // 2. 파일 경로 합치기 const fileStatus = fs.statSync(filePath); // 2. 파일 정보 얻기 if (fileStatus.isDirectory()) { // 3-1. 폴더일 경우 재귀 console.log('디렉토리:', filePath); traverseDirectoryRecursive(filePath); } else { // 3-2. 파일일 경우 출력 console.log('파일:', filePath); } } } traverseDirectoryRecursive('.'); // 현재 경로의 모든 하위 경로의 파일, 디렉토리 출력하위 조건:인자로 받은 Directory의 파일과 폴더를 읽어온다파일 경로를 합치고 파일 정보를 얻어온다폴더일 경우, 재귀함수를 통해 내부 폴더의 파일과 폴더를 읽는다파일일 경우, 파일을 출력한다.기저조건:현재 폴더 내부 모든 파일 수만큼 반복📔 회고알고리즘 문제가 아닌 실전에서 사용할 수 있는 재귀 함수로 응용을 해보니 생각보다 하위조건을 파악하고 기저조건을 설정하는 것이 쉽지 않다는 것을 깨달았다. 처음에는 계속해서 코드를 읽어보면서 익숙하지 않은 fs모듈에 대해서 먼저 파악해보고, 제공되는 메서드들을 익혀보았다. 그렇게 코드의 흐름을 익혀가면서 반복되는 부분을 구분하였고, 재귀적으로 해결할 수 있는 부분은 while 문이라는 것을 파악했다. 기존에 스택을 통해서 파일들을 가져오고 데이터를 쌓아오면서 while 문을 통해 스택에 있는 데이터를 다시 출력하는 코드였다는 것을 파악하였고, 이를 재귀적으로 변경하기 위해서는 스택 자료구조를 사용하지 않고 하나의 함수에 하나의 폴더를 읽어오고 재귀적으로 함수를 다시 호출하면서 폴더 내부의 파일을 찾아가는 형식으로 수정할 수 있다는 것을 파악했다. 그렇게 하위조건을 설정하였고 기저조건을 만들어서 성공적으로 재귀함수로 코드를 수정할 수 있었다.이렇게 알고리즘을 응용하여 실전에서 사용할 수 있다는 것을 크게 깨달았고, 앞으로 알고리즘을 배울 때도 실전에서도 사용될 수 있는 다양한 사례를 함께 찾아보면서 공부하면 더 알고리즘 개념을 탄탄히 가져갈 수 있을 것 같다.

알고리즘 · 자료구조자료구조인프런워밍업

채널톡 아이콘