블로그

양성빈

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

이 블로그 글은 박우빈님의 인프런 강의를 참조하여 작성한 글입니다.드디어 마지막 발자국 작성차례이다. 어느덧 벌써 수료날짜가 얼마 남지 않았다. 남은 시간 끝까지 달려보자. Presentation Layer 테스트외부세계의 요청을 가장 먼저 받는 계층파라미터에 대한 최소한의 검증을 수행MockMVCMock 객체를 사용해 스프링 MVC 동작을 재현할 수 있는 테스트 프레임워크요구사항관리자 페이지에서 신규상품을 등록할 수 있다.상품명, 상품타입, 판매상태, 가격등을 입력받는다. 그래서 해당 요구사항으로 비즈니스 로직을 작성 후 해당 부분 테스트를 해보았다. 여기서 잠깐 주목할만한 부분이라면 바로 @Transactional(readOnly = true)와 @Transactional이다. readOnly옵션은 읽기 전용이라는 뜻이다. 해당옵션에서는 CRUD중에 R만 기능동작을 하게 한다. 또한 JPA에서 CUD스냅샷 저장과 변경감지를 하지 않아 성능향상에 이점을 줄 수 있다. 또한 CQRS에서 Command부분과 Read부분을 나누자는 것처럼 우리의 비즈니스 로직중에 해당 클래스를 readOnly옵션을 전체로 주고 CUD에 해당되는 부분만 @Transactional을 사용하자!또한 우리는 validation을 적용하고 예외를 처리하기 위해 spring-boot-starter-validation 의존성을 추가해주고 각 dto에 어노테이션들을 추가해주었다. 또한 각 예외상황에 맞게 처리할 RestControllerAdvice를 두었으며 공통응답객체를 만들어 진행을 해보았다. 여기서 유심히 볼 부분이 몇가지 존재한다.⚠ @NotBlank vs @NotNull vs @NotEmptyNotNull은 null값을 허용을 하지 않는 것이고 NotEmpty는 ""문자열만 허용을 하지 않으며 NotBlank는 이 둘을 다 포함하면서 " "문자열도 포함시키지 않는다.또한 해당 request DTO를 만들면서 하나의 DTO를 이용해서 presentation layer부터 Business Layer까지 쓰이곤 한다. 이런 점은 DTO를 두고 의존성을 둘 수 있다는 것이다. 이건 layered architecture에 어긋한다. 따라서 서비스용 DTO, 컨트롤용 DTO를 별도 개발해서 진행을 해보는 작업을 해보았다. 또한 컨트롤러에서는 최소한의 검증을 하고 그 외에는 서비스용으로 옮겨보는 법도 생각해보았다. 미션이번 미션은 레이어 아키텍쳐에 관하여 설명과 테스트 방법에 대해 나만의 언어로 풀어쓰는 미션이다. 처음에는 내 언어로 표현한다는게 막막했지만 차근차근 정리를 해가다보니 금방 쉽게 풀어써졌다.미션링크 Mockito로 Stubbing하기요구사항현재 관리자 페이지에서 당일 매출에 대한 내역을 메일전송을 받고 싶어한다.그래서 우리는 해당 요구사항을 바탕으로 비즈니스 로직을 작성하였다. 핵심은 테스트이다. 메일 전송은 외부 네트워크를 타고 전송이 되는 로직이라 매우 오랜 시간이 걸린다.(내 경험) 또한 메일을 계속 보내다보면 나중에 수 많은 테스트 메일이 쌓여 있는 것을 알 수 있다. 이럴때는 어떻게 할까? 메일 전송 행위자체를 mocking하면 되는데 이것을 stubbing이라고 한다. 우리는 메일 전송 로직을 mockBean을 이용해 mocking하고 행위 자체를 stubbing하여 테스트를 수행 할 수 있었다. Test Double출처배우 대역의 스턴트맨이 그 Test Double의 근원지이다.관련 용어Dummy: 아무것도 하지 않는 깡통객체Fake: 단순한 형태로 동일한 기능은 수행하나 프로덕션에서 쓰기에는 부족한 객체(ex. FakeRepository)Stub: 테스트에서 요청한 것에 대해 미리 준비한 결과를 제공하는 객체. 그 외에는 응답XSpy: Stub이면서 호출된 내용을 기록하며 보여줄 수 있는 객체. 일부는 실제 객체러첨 동작시키고 일부만 stubbingMock: 행위에 대한 기대를 명세하고 그에 따라 동작하도록 만들어진 객체 Stub과 Mock을 헷갈려한다. 동일한거 아닌가? 결론부터 말하자면 Mock은 Stub이 아니다. Mock은 행위에 대한 검증을 할때 사용하고 Stub은 상태에 대한 검증을 할때 사용된다. @Mock, @Spy, @InjectMocks순수 Mockito로 검증하는 시간을 가져보았다. 우리는 @SpringBootTest를 붙여서 통합 테스트를 가져보았는데 그렇게 하지 않고 순수 Mockito로 테스트할 수 있는 방법은 없을까?그래서 우리는 기존에 MailService를 테스트를 가져보았다. 의존성으로 주입된 것들을 mock()을 이용하여 만들어주고 MailService를 해당 mock()으로 만든 것을 생성자에 넣어주어서 실행했다.하지만 이렇게 하는것보다 더 좋은 방법은 @Mock과 @InjectMocks를 이용하는 방법이다. mock()으로 생성한 객체는 @Mock 어노테이션을 붙여서 사용이 가능하고 만들어진 mock 객체를 이용하여 생성한 객체 MockService는 @InjectMocks를 이용하여 더 간단히 사용이 가능하다. 추가적으로 해당 메서드 안에 특정메서드가 몇번 불렸는지 확인하는 것은 verify로 확인이 가능하다.@Mock을 사용할 때는 @ExtendWith(MockitoExtension.class)을 붙여줘야 한다.또한 @Spy를 이용할건데 사용법은 @Mock과 유사하다. 다른점은 @Mock을 사용할때 when().thenReturn()식을 이용했는데 @Spy는 doReturn().when().메서드()를 이용하면 된다. @Mock과 비교해보자. @Mock을 사용하면 해당 메서드만 mocking을 하여 사용하고 그 외의 메서드들은 작동을 안 한다. 하지만 @Spy를 사용하면 해당 객체에 호출한 메서드들이 전부 작동이 된다. 그래서 일반적으로 @Mock을 사용하지만 @Spy를 이용할 때도 있으니 알아두자. BDDMockitoBDD는 행위주도개발로 이전에 한번 살펴본 적이 있다. 이전에 실습한 코드를 보면 뭔가 이상하다고 느낄 수 있을 것이다.// given when(mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString())).thenReturn(true);분명 given절인데 when이 들어가져 있다. 그래서 만들어진 것이 BDDMockito다. BDDMockito의 given을 이용하면 아래와 같이 변경이 가능하다.given(mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString())).willReturn(true);그럼 정확히 given에 given을 이용하니 명확해진다. Classicist VS. MockistClassicist입장은 다 mocking하면 실제 객체들의 동작 및 두 객체들이 합쳐서 동작할때 그에 따른 사이드 이펙트는 어떻게 검증할건데라는 입장이며 Mockist 입장은 모든 걸 다 mocking하면 각 객체들의 기능에 대한걸 보장하니 굳이 통합테스트를 할 필요가 없다라는 입장이다.우리는 Persistence Layer에서 단위 테스트를 진행하고 Business Layer에서는 통합 테스트를 Presentation Layer에서 두 레이어를 모킹하여 진행했다. 이것을 Mockist가 본다면 굳이 시간낭비하고 있다고 할 것이다.우빈님의 생각은 Classicist입장이시며 mocking을 할때는 외부시스템을 사용할 일이 있을때 사용한다고 하셨다.즉 결론은 mocking을 했다 하더라도 실제 프로덕션 코드에서 런타임 시점에 일어날 일을 정확하게 stubbing했다 단언할 수 없으니 통합테스트를 해보자는 것 같다.나의 입장은 이렇다. QuerDSL같은 외부자원을 사용할때 나는 해당 부분을 테스트할때 테스트를 진행하고 비즈니스 레이어에는 해당 부분을 mocking처리한다. 그리고 컨트롤러 부분에서 통합테스트를 사용하는데 이 부분은 한번 질문을 드려봐야겠다. 한 문단에 한 주제이전 강의인 Readable Code에서도 배웠고 학창시절 영어독해시간에도 배웠듯이 한 문단에는 하나의 주제로 이루어져야 한다. 테스트도 문서다. 즉, 각각 하나의 테스트는 하나의 문단이고 그 테스트 코드는 하나의 주제를 가져야 한다. 완벽하게 제어하기테스트 코드를 작성할 때는 모든 조건들을 완벽히 제어가 가능해야 한다. 우리는 이전에 LocalDateTime.now()을 사용하면서 현재시간에 따라 테스트가 성공할때도 있고 실패할때도 있는 경우를 보았다. 그래서 우리는 이를 해결하기 위해 이 현재시간을 상위에 넘기고 파라미터로 받는 방식을 택하였다.그러면 만약에 LocalDateTime.now()를 사용해도 테스트가 무조건 성공한다면 사용해도 되나? 우빈님께서는 지양한다고 하셨다. 그 이유는 그 테스트는 성공할진 몰라도 팀 단위에서 해당 코드를 사용하면 그게 프로젝트에 번져서 빈번히 사용할 확률이 높기때문이라고 하셨다. 나도 이점을 한번 주의해야겠다. 테스트 환경의 독립성을 보장하자테스트 환경은 대부분 given절에서 환경을 세팅한다. 그런데 이런 given절에서 다른 API를 사용하게 된다면 어떻게 될까? 해당 API와 테스트 코드가 결합도가 생기게 된다. 이런 부분을 방지하고 테스트코드 독립성을 보장시켜야 한다.@Test @DisplayName("재고가 부족한 상품으로 주문을 생성하려는 경우 예외가 발생한다.") void createOrderWithNoStock() {     // given     LocalDateTime registeredDateTime = LocalDateTime.now();     Product product1 = createProduct(BOTTLE, "001", 1000);     Product product2 = createProduct(BAKERY, "002", 3000);     Product product3 = createProduct(HANDMADE, "003", 5000);     productRepository.saveAll(List.of(product1, product2, product3));     Stock stock1 = Stock.create("001", 2);     Stock stock2 = Stock.create("002", 2);     stock1.deductQuantity(1); // @todo     stockRepository.saveAll(List.of(stock1, stock2));     OrderCreateServiceRequest request = OrderCreateServiceRequest.builder()             .productNumbers(List.of("001", "001", "002", "003"))             .build();     // when & then     assertThatThrownBy(() -> orderService.createOrder(request, registeredDateTime))             .isInstanceOf(IllegalArgumentException.class)             .hasMessage("재고가 부족한 상품이 있습니다."); }위의 코드에서 todo부분을 살펴보자. 해당 코드는 주문생성관련 로직이다. 그런데 deductQuantity를 현재 재고보다 많이 차감시키면 해당 메서드에서 예외를 던질 것이다. 그러면 given절에서 테스트가 실패되고 내가 위에서 말했던 결합도가 생긴 케이스이다. 또한 이건 내 생각이지만 주문생성로직에 재고차감로직이 들어가 있으니 하나의 테스트코드에 주제가 2개가 되버리는 상황이 생긴다. 이런것을 방지하는 것이 좋다. 테스트 간 독립성을 보장하자테스트는 각각 수행되어야 하고 테스트 순서가 무작위여도 같은 결과가 나와야 한다. 하지만 만약 테스트에 공유자원을 사용하게 되면 예상치 못한 결과가 나올 우려가 있기에 테스트가 실패할 경우도 있을 것이다. 이런 점때문에 공유자원 사용은 지양하자. 한 눈에 들어오는 Test Fixture 구성하기Test FixtureFixture: 고정 틀, 고정되어 있는 물체 (given절에 생성한 객체들)테스트를 위해 원하는 상태로 고정시킨 일련의 객체 우리는 이에 관련해서 @BeforeEach BeforeAll에 대해 알아보았다. 그런데 @BeforeEach같은 경우 given절에서 만든 데이터를 넣는 행위는 지양하다고 하셨다. 결국 이것은 이전에 봤던 공유자원과 같은 역할을 한다. 또한 테스트는 문서인데 given절을 보려니 없어서 스크롤로 위로 왔다갔다 하는 상황이 발생하기 때문에 테스트 문서의 파편화가 일어난다.그러면 언제 @BeforeEach를 쓸까? 각 테스트 입장에서 봤을 때 아예 몰라도 테스트 내용을 이해하는데 문제가 없는가?라는 물음과 수정해도 모든 테스트에 영향을 주지 않는가?라는 물음에 괜찮다면 사용하자! 그렇지 않다면 지양하자.또한 data.sql을 이용해 미리 쿼리를 생성해 given절을 작성하는 행위는 지양하자. 왜냐하면 테스트 파편화가 일어나기도 하고 나중에 실무에 가면 수십개의 컬럼과 수십개의 테이블이 있고 이 테이블이나 컬럼이 바뀔때마다 수정을 해줘야 하기때문에 관리포인트가 늘어나기 때문이다.또한 given절에 객체를 생성 시, 필요한 파라미터만 주입받는것을 고려하면 작성하자. 해당 파라미터를 보고 이 파라미터는 테스트에 전혀 영향을 주지 않을 것 같은 것은 고정값으로 두고 파라미터를 빼는 것처럼 말이다.마지막으로 builder와 같이 given절에 들어가는 것을 하나의 테스트 config 클래스에 모아두는 행위는 지양하자. 왜냐하면 나중에 실무에서 작성하다보면 새로운 빌더가 생기고 메서드 오버로딩때문에 파라미터 순서만 바뀌는 빌더도 많이 생길 수 있으며 테스트 문서 파편화로 인해 더 불편해질 것 같다. 그래서 클래스마다 필요한 파라미터만 받아서 작성하는 것이 좋다. Test Fixture 클렌징deleteAll()과 deleteAllInBatch()에 차이에 대해 알아보자. 우빈님은 deleteAllInBatch()를 더 선호하신다고 하셨다. 그 이유에 대해 알아보자.deleteAllInBatch()는 delete from~ 절만 나가는 순수 테이블 전체 삭제에 용이하다. 하자민 단점이라하면 순서를 잘 생각해야 한다. 만약 A라는 테이블과 B라는 테이블이 M:N 연관관계를 맺어 중간테이블 AB라는 테이블이 있을때 AB부터 테이블을 삭제해주고 A, B순서대로 삭제를 해줘야 한다. 그렇지 않으면 예외가 발생한다.deleteAll()은 굳이 중간테이블을 삭제할 필요없이 중간테이블을 알고 있는 테이블만 삭제해도 알아서 삭제해준다. 하지만 단점은 해당 메서드를 실행하면 해당 엔티티를 먼저 전체 select를 하고 다음으로 delete from where 절이 나간다. 그리고 해당 절은 테이블에 있는 데이터 수 만큼 나가기 때문에 수많은 데이터가 존재하면 성능이 매우 떨어질 것이다.그래서 deleteAllInBatch()가 더 선호하는 이유를 알 것 같다. 하지만 이런것보다 side effect를 잘 고려해서 @Transactional을 잘 사용하는 것이 베스트일 것 같다. @ParameterizedTest테스트 코드에 if-else나 for문같이 조건문, 반복문등 읽는 사람의 생각이 들어가는 것을 지양해야한다고 말했다. 그래서 여러가지 테스트 로직이 하나의 테스트 코드에 있다면 분리하자고 하였다. 그런데 만약 단순히 값 여러개로 하나의 테스트를 하고 싶은경우 테스트를 나누는 것보다 @ParameterizedTest를 사용하는 것이 깔끔해진다.대표적인 예시로 내가 사이드프로젝트에서 작성했던 코드를 들 수 있을 것 같다.@ParameterizedTest @MethodSource("providedTestDataForSignup") @DisplayName("회원가입 통합 테스트 - 실패(유효하지 않은 회원가입 폼)") void member_signup_integration_test_fail_caused_by_invalid_signup_form(String name, String nickname, String email, String password, String confirmPassword, String phoneNumber, LocalDate birthday) throws Exception {     MemberSignupRequestDto requestDto = new MemberSignupRequestDto(name, nickname, email, password, confirmPassword, phoneNumber, birthday);     this.mockMvc.perform(post("/api/auth/signup")                   .contentType(MediaType.APPLICATION_JSON + ";charset=UTF-8")                     .accept(MediaType.APPLICATION_JSON + ";charset=UTF-8")                     .content(this.objectMapper.writeValueAsString(requestDto)))             .andDo(print())             .andExpect(status().isBadRequest())             .andExpect(jsonPath("message").exists())             .andExpect(jsonPath("status").value(GlobalExceptionCode.INVALID_REQUEST_PARAMETER.getHttpStatus().name()))             .andExpect(jsonPath("code").value(GlobalExceptionCode.INVALID_REQUEST_PARAMETER.getCode()))             .andExpect(jsonPath("timestamp").exists()); } private static Stream<Arguments> providedTestDataForSignup() {     return Stream.of(             Arguments.of("양성빈", "tester", "email@email.com", "1q2w3e4r5t!", "1q2w3e4r5t!", "010-1234-1234", LocalDate.of(1999, 1, 1)),             Arguments.of("양성빈", "robert", "test@email.com", "1q2w3e4r5t!", "1q2w3e4r5t!", "010-1234-1234", LocalDate.of(1999, 1, 1)),             Arguments.of("양성빈", "robert", "email@email.com", "1q2w3e4r5t!", "t5r4e3w2q1@", "010-1234-1234", LocalDate.of(1999, 1, 1)),             Arguments.of("양성빈", "robert", "email@email.com", "1q2w3e4r5t!", "1q2w3e4r5t!", "010-1111-1111", LocalDate.of(1999, 1, 1))     ); }이렇게 @MethodSource를 사용하는 경우 이외에오 @CsvSource를 이용하는 경우도 있고 다른 방법도 있으니 한번 찾아보면 좋을 것 같다. @DynamicTest공유변수를 가지고 여러개의 테스트가 사용하는 것은 지양하자고 하였다. 왜냐하면 테스트의 순서가 생겨버리고 서로 강결합이 되기 때문이다. 하지만 환경 설정 후 시나리오 테스트를 하는 경우가 있을 것이다. 그럴 경우 @DynamicTest를 이용하자. 사용법은 아래와 같다.@TestFactory @DisplayName("") Collection<DynamicTest> dynamicTests() {     // given     return List.of(             DynamicTest.dynamicTest("", () -> {                 // given                 // when                 // then             }),             DynamicTest.dynamicTest("", () -> {                 // given                 // when                 // then             })         ); } 테스트 수행도 비용이다. 환경 통합하기이제 전체 테스트를 돌려보자. 지금 테스트를 전체 돌려보면 2.x초라는 시간이 걸리고 spring boot 서버가 6번 뜨는 불필요한 행위가 발생한다.테스트 코드를 작성하는 이유가 인간의 수동화된 검증에 대한 불신도 있지만 가장 큰 이유는 시간을 아끼기 위해서이다. 하지만 테스트를 돌렸는데 2.x초라는 행위는 너무 아깝다. 그래서 우리는 하나의 통합추상 클래스를 만들어 service와 repository부분을 하나의 추상클래스를 상속받게 함으로 테스트 띄우는 횟수를 줄였다. 그리거 마지막 controller부분도 별도의 추상클래스를 만들어 해당 클래스를 상속받게 함으로 서버 띄우는 횟수를 줄여갔다. 결론적으로 총 서버는 2번 띄워졌고 2.x초에서 1.x초로 속도가 줄어갔다. Q. private 메서드의 테스트는 어떻게 하나요?정답은 할 필요도 없고 하려고 해서도 안된다. 클라이언트 입장에서는 제공되는 public 메서드만 알 수 있고 알아야하며 그 외의 내부 메서드는 알 필요가 없다. 또한 public 메서드를 테스트한다는 것은 내부 private 메서드도 자동으로 같이 테스트하는 것이므로 따로 테스트를 할 필요가 없다. 다만 만약 이렇게 해도 계속 위의 물음이 생각나면 객체를 분리할 시점인가를 검토해야한다. 그리고 객체를 분리시켜 해당 private 메서드를 해당 객체의 public 메서드로 두고 단위 테스트를 진행해야 할 것이다.나는 미션을 진행하면서 이런 물음이 생각났고 private 메서드를 리플렉션을 통해 테스트를 한 경우가 있는데 위의 해답을 듣고 나니 괜히 테스트를 한것이구나라는 생각이 들어 조금은 반성하게 된 계기였다. Q. 테스트에서만 필요한 메서드가 생겼는데 프로덕션 코드에서는 필요 없다면?답변은 만들어도 된다. 다만 보수적으로 접근해야 한다. 즉, 어떤 객체가 마땅히 가져도 되고 미래지향적이면 만들어도 상관없다. 학습 테스트잘 모르는 기능, 라이브러리, 프레임워크를 학습하기 위해 작성하는 테스트여러 테스트 케이스를 스스로 정의하고 검증하는 과정을 통해 보다 구체적인 동작과 기능을 학습관련 문서만 읽는 것보다 훨씬 재밌게 학습  Spring REST Docs테스트 코드를 통한 API 문서 자동화 도구API 명세를 문서로 만들고 외부에 제공함으로써 현업을 원활하게 한다.기본적으로 AsciiDOC을 사용하여 문서를 작성한다. Spring REST Docs vs SwaggerSpring REST Docs장점테스트 코드를 통과해야 문서가 만들어진다. (신뢰도가 높다)프로적션 코드에 비침투적이다.단점코드 양이 많다.설정이 어렵다.Swagger장점적용이 쉽다문서에서 바로 API 호출을 수행해볼 수 있다.단점프로덕션 코드에 침투적이다.테스트와 무관하기 때문에 신뢰도가 떨어질 수 있다. 미션3 진행테스트코드의 마지막 미션을 진행하였다. 이번에 배운 어노테이션들, @BeforeEach가 적용하여 BDD 스타일 적용하는 실습등 미션을 진행했는데 해당 미션을 통해서 해당 어노테이션들에 대해 확실히 알 수 있었으며 BDD 스타일이 조금 적응된 것 같다.미션링크 깜짝 특강Day18 미션 공통 피드백핵심은 중복 제거가 아니고 도메인이다. 사용자, 게시물은 간접적이므로 setup()으로 댓글은 직접적이므로 given절에 배치해야 한다.Q&A잘문) REST API의 조건 중 하나인 hateoas에 대해 실무에서 많이 사용하는지와 제가 제대로 적용하고 있는지답변) 아직까지 사용한 곳을 본적이 없다고 하셨다. 그 이유를 생각해보시는데 단순히 hateoas를 적용하기에는 APP-FE-BE 간 긴밀한 스펙과 복잡한 동작들이 너무 많고 또 이미 만들어져 있는 구조를 hateoas 형태로 전환한다는것은 불가능에 가깝다고 느끼신다고 하셨다. 또한 실무에서는 대부분 그런 규칙을 지키는 것보다 다른 중요한 것들이 더 많다고 판단하기 때문이라고도 하셨다.코드리뷰우빈님께서 많은 칭찬을 해주셔서 몸둘 바를 모르겠지만 몇가지 피드백 사항이 있었다. 그 중에 제일 생각나는 피드백을 말하면 다음과 같다. given / when / then절에 설명하는 주석은 생략해도 좋다. 하지만 given절이 몇십줄이고 서로 다른 특징들이 나열되어 있다면 간단히 적는 걸 추천하신다고 하셨다.이것으로 모든 워밍업 클럽 진도가 완료가 되었다, 나 자신에게도 뜻 깊은 경험과 성장이 되었으며 이러한 경험의 반복을 이뤄나가고 싶다.

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

또니

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

[운영체제]메모리의 종류는 어떤것들이 있나요? 각 메모리의 특징도 함께 적어주세요. => CPU에 존재하고 휘발성 메모리인 레지스터, 메인 메모리에 있는 값을 레지스터로 옮기는 시간을 줄이기 위해 데이터를 가져와 저장하는 캐시, 실제 운영체제와 프로세스가 올라가는 휘발성 메모리인 메모리, 비휘발성이며 작업된 데이터를 저장하는 보조 저장장치가 있습니다.사용자 프로세스가 메모리의 운영체제 영역에 침범하지 못하도록 만든 레지스터는 어떤 레지스터일까요?=> 경계 레지스터 메모리 할당 방식에서 가변 분할 방식과 고정 분할 방식의 장단점은 뭔가요?=> 가변분할 방식은 프로세스 크기에 따라 메모리를 할당하기 때문에 내부 단편화가 일어나지 않지만 외부 단편화가 발생합니다. 고정분할 방식은 외부 단편화를 해결하고, 메모리 관리를 효율적으로 하지만 내부 단편화가 일어나는 단점이 있습니다.CPU 사용률을 올리기 위해 멀티프로그래밍을 올렸지만 스왑이 더 많이 이루어져 CPU 사용률이 0%에 가까워 지는 것을 뭐라고 할까요?=> 스레싱 HDD나 SSD는 컴퓨터를 실행시키는데 꼭 필요한 걸까요? 이유를 함께 적어주세요.=> 컴퓨터를 활성화 시키기 위해선 CPU를 동작시켜야하는데 이때 운영체제가 필요하다. 이때 운영체제가 저장되어야하는데, RAM과 같은 메모리는 휘발성이므로 저장을 할 수 없지만 HDD나 SSD는 비휘발성으로 운영체제를 저장하여 사용하기 때문에 필요하다.파일을 삭제해도 포렌식으로 파일을 복구할 수 있는 이유가 무엇일까요?=> 파일을 삭제하면 모든 정보를 지우는 것 보다 헤더를 삭제하고 free block list에 추가한다. 이때 사용했던 데이터 블록이 그대로 저장되어 있어 복구할 수 있다.[자료구조와 알고리즘]1. 지금까지 배운 5개의 정렬 알고리즘의 장단점과 시간 복잡도를 적어주세요.버블 정렬장점: 가장 단순하고 이해가 쉽다.단점: 성능이 좋지 않다.시간 복잡도: O(n^2)선택 정렬장점: 이해와 구현이 간단하다.단점: 성능이 좋지 않다.시간 복잡도: O(n^2)삽입 정렬장점: 이해와 구현이 간단하다.단점: 성능이 좋지 않다.시간 복잡도: O(n^2)병합 정렬장점: 버블, 선택, 삽입 정렬보다 성능이 좋다.단점: 이해하기 어렵고, 구현하기 어렵다.시간 복잡도: O(n log n)퀵 정렬장점: 적은 메모리 공간을 사용해 성능이 좋다.단점: 이해하기 어렵고, 구현하기 어렵다. 시간복잡도: O(n log n)메모리가 부족한 시스템에서 어떤 문제를 해결하는데 재귀로 쉽게 구현이 가능할 것 같습니다. 여러분이라면 메모이제이션과 타뷸레이션 중 어떤 걸 이용하실 건가요? 이유를 함께 적어주세요.=> 메모이제이션은 재귀를 사용기 때문에 메모리 비용이 크지만, 타뷸레이션은 반복문을 사용하기 때문에 메모리의 크기를 예측 할 수 있습니다. 때문에 타뷸레이션을 사용할 것 같습니다.알고리즘 강의 링크 👉그림으로 쉽게 배우는 자료구조와 알고리즘 (기본편)운영체제 강의 링크 👉그림으로 쉽게 배우는 운영체제

알고리즘 · 자료구조CS지식인프런워밍업클럽2기

또니

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

[3주차 학습 내용]자료구조와 알고리즘삽입 정렬: 정렬되지 않은 위치에서 데이터를 꺼내 정렬된 위치의 적절한 곳에 삽입하는 알고리즘이해와 구현이 간단하지만 성능이 좋지 않다.O(n^2)의 시간복잡도를 가지고 있다.병합 정렬: 해결하기 힘든 문제가 발생하면 해결하기 쉬울 때까지 쪼개어 하나씩 해결하는 알고리즘이해와 구현이 어렵지만 성능이 좋다.O(n log n)의 시간복잡도를 가지고 있다.퀵 정렬: 분할 정복 알고리즘의 하나로 배열의 값 중 하나를 피벗으로 설정하여 정렬하는 알고리즘이름과 같이 보통은 빠르고, 메모리 사용량이 적다.피벗의 선택에 따라 성능의 차이가 있고, 최악의 경우 속도가 느려질 수 있다.보통은 O(n log n), 최악의 경우 O(n²)의 시간복잡도를 가지고 있다.메모이제이션: 계산 결과를 기억해 중복된 계산을 하지 않는 기법하향식 계산 방식속도는 빠르지만 메모리의 사용량이 있다.타뷸레이션: 계산에 필요한 값을 전부 계산 한 뒤 테이블에 저장하는 기법상향식 계산 방식 운영체제가상메모리, 동적주소변환, 세그멘테이션, 페이징, 페이지드 세그멘테이션, 디맨드 페이징, 페이지 교체 정책스레싱과 워킹셋, 입출력 장치,파일 시스템[3주차 회고]3주간의 스터디가 이렇게 마무리 되었다. 정말 필요했던 자료구조 지식을 공부하여 알고리즘 문제를 푸는데 큰 도움이 되었고, 회사에서 일을 하는데에 운영 체제 지식이 조금 필요했던 타이밍에 좋은 기회로 공부하여 의견을 제시할 수 있어서 일을 잘 마무리 할 수 있었다. 이번 CS지식 강의는 정말 어렵고 지루할 수 있었던 분야를 그림으로 쉽게 풀어 이해할 수 있도록 설명해주신 것이 이해하는데에 엄청 큰 도움이 되었다.비록 중간 점검때에 야근 이슈로..참여를 하지 못해 수료는 하지 못했지만 끝까지 공부할 수 있는 환경과 목표를 가질 수 있게 좋은 프로그램을 만들어주신 인프랩 직원분들과 좋은 강의를 제공해주신 감자님께 감사인사드립니다.알고리즘 강의 링크 👉그림으로 쉽게 배우는 자료구조와 알고리즘 (기본편)운영체제 강의 링크 👉그림으로 쉽게 배우는 운영체제

알고리즘 · 자료구조CS지식인프런워밍업클럽2기

양성빈

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

이 블로그 글은 박우빈님의 강의를 참조하여 작성한 글입니다.어느덧 벌써 워밍업 클럽이 막바지로 가고 있는 것 같다. 워밍업 클럽을 참여 전의 나보다 많이 성장했는가를 항상 발자국 쓸때 돌이켜 물어보는 것 같다. 과연 성장을 했을끼? 나는 당당히 성장을 하였다고 생각을 한다. 해당 스터디를 통해 나의 생활도 지식도 성장이 되었다 생각하며 해당에 대한 물음은 워밍업 클럽 수료 후에 다시 되물음을 해보겠다.이번 주차에서는 이제 Readable Code 강좌가 완강이 되고 Practical Testing 강좌를 시작하는 주차다. 이번주도 열심히 달려본 내역들을 작성해보겠다. 강의소개이 강좌는 테스트가 처음이거나 테스트 코드는 들어봤거나 작성하려고 시도를 해본 경험이 있는등 테스트가 궁금한 모든 분들을 위해 나온 강의이다. 나도 해당 테스트를 어떻게 하면 잘 작성할지가 궁금하여 이 강좌를 듣게 되고 해당 워밍업 클럽을 참여하게 된 이유이기도 하다.테스트를 작성하는 역량은 채용시장에서 주니어 개발자에게 기대하는 요소 중 하나다. 채용시 구현과제 등에서 테스트 작성여부, 테스트 코드 구현방식을 확인한다. 또한 소프트웨어의 품질을 보장하는 방법으로 그 중요성을 알고 있는지도 확인을 하기도 한다고 한다.이번 강좌에서는 다음과 같은 목표를 두고 학습을 진행한다고 한다.📚 목표1. 테스트 코드가 필요한 이유2. 좋은 테스트 코드란 무엇일까?3. 실제 실무에서 진행하는 방식 그대로 테스트를 작성해가면서 API를 설계하고 개발하는 방법4. 정답은 없지만 오답은 존재한다. 구체적인 이유에 근거한 상세한 테스트 작성 팁벌써부터 많은 기대를 품으며 다음 강의로 바로 가봐야 겠다. 어떻게 학습하면 좋을까?효과적인 학습을 하기 위해 가장 먼저 선행되어야 하는 것은 바로 무엇을 모르는지 아는 것이다. 무엇을 모르는 지 아는것은 찾아볼 수 있게 된다는 것이다.우리는 학습을 하면서 이 부분은 완벽히 아는 부분, 이 부분은 반만 아는 부분, 이 부분은 처음 들어보는 부분으로 구분된다. 그래서 강좌에서 함계 학습한 키워드와 추가 학습을 위한 키워드를 분리하여 키워드 기반으로 정리를 해주신다고 하니 많은 기대를 가지며 다음 강의부터 본격적으로 달려 볼 예정이다. 테스트는 왜 필요할까?기술 학습에 있어서 '왜?'가 중요하다. 테스트하면 생각나는게 무엇일까? 나는 처음 테스트코드를 볼때 굳이 해야하나? 개발시간만 더 늘릴뿐일텐데라는 생각을 하였다.그런데 만약 테스트코드가 없이 실제 인간이 수동으로 테스트를 하면 매우 큰 문제들을 야기할 수 있다. 인간은 실수의 동물이기 때문이다. 또한 만약 기능을 개발할때 기존 기능을 건들게 된다면 기존 기능도 다시 테스트를 하는 시간낭비가 발생한다. ✅ 테스트 작성을 안하면?1. 커버할 수 없는 영역 발생2. 경험과 감에 의존3. 늦은 피드백4. 유지보수 어려움5. 소프트웨어에 대한 신뢰가 떨어딘다. 테스트 코드를 작성하지 않으면?변화가 생기는 매 순간마다 발생할 수 있는 모든 case를 고려해야한다.변화가 생기는 매 순간마다 모든 팀원이 동일한 고민을 해야한다.빠르게 변화하는 소프트웨어의 안정성을 보장할 수 없다.테스트코드가 병목이 된다면?프로덕션 코드의 안정성을 제공하기 힘들어진다.테스트 코드 자체가 유지보수하기 어려운 새로운 짐이 된다.잘못된 검증이 이루어질 가능성이 생긴다.올바른 테스트 코드자동화 테스트로 비교적 빠른 시간 안에 버그를 발견할 수 있고 수동 테스트에 드는 비용을 크게 절약할 수 있다.소프트웨어의 빠른 변화를 지원한다.팀원들의 집단 지성을 팀 차원의 이익으로 승격시킨다.가까이 보면 느리지만 멀리보면 빠르다.샘플 프로젝트 소개 & 개발 환경 안내해당 테스트 섹션에서는 카페 키오스크 시스템을 만들면서 테스트 학습을 할 예정이다.🛠 개발환경- IntelliJ Ultimate- Vim(Plugin) 프로젝트 세팅인텔리제이를 활용하여 스프링부트 프로젝트를 생성하고 build.gradle의 의존성 정리를 하였다. 수동테스트 VS. 자동화된 테스트요구사항주문목록에 음료 추가/삭제 기능주문목록에 전체 지우기주문목록 총 금액 계산하기주문 생성하기 해당 부분을 토대로 콘솔기반 비즈니스 로직을 작성하였고 테스트 강의이니 해당 로직을 테스트 하기 위해 이 중 음료 추가에 대한 로직을 아래와 같이 작성했다.@Test void add() {     CafeKiosk cafeKiosk = new CafeKiosk();     cafeKiosk.add(new Americano());     System.out.println(">>> 담긴 음료 수: " + cafeKiosk.getBeverages().size());     System.out.println(">>> 담긴 음료: " + cafeKiosk.getBeverages().get(0).getName()); }위의 코드를 봤을 때 이렇게 테스트코드를 짜면 안된다고 직감을 했을 것이다. 왜냐하면 일단 최종단계에서 사람이 개입하고 어떤게 맞고 어떤게 틀리는지 모른다는 것이다. 또한 이 테스트는 100% 성공하는 케이스이기 때문에 뭔가 테스트라고 하기에 모호한것 같다. JUnit5로 테스트하기단위테스트작은 코드 단위를 독립적으로 검증하는 테스트검증속도가 빠르고 안정적이다.Junit5단위 테스트를 위한 테스트 프레임워크 AssertJ테스트 코드 작성을 원활하게 돕는 테스트 라이브러리풍부한 API, 메서드 체이닝 지원 해당 지식을 기반으로 우리가 이전 시간에 작성한 아메리카노부분과 카페머신의 대한 단위 테스트를 AssertJ를 이용하여 작성해보는 시간을 가졌다. 테스트 케이스 세분화하기스스로에게 질문해보자. 암묵적이거나 아직 드러나지 않은 요구사항이 있는지를 확인해보자. 그리고 해피케이스와 예외케이스를 둘다 생각하며 항상 경계값 테스트를 해보자.경계 값은 범위(이상, 이하, 초과, 미만), 구간, 날짜등을 일컫는다.그래서 우리는 음료에 여러잔을 담는 기능을 개발하고 해당 부분의 해피케이스에 관한 테스트를 작성했다. 또한 예외 케이스를 생각해 로직을 작성하고 해당 예외케이스에 대한 로직을 작성하게 되었다. 테스트하기 어려운 영역을 분리하기테스트하기 어려운 영역은 다음과 같다.관측할 때마다 다른 값에 의존하는 코드현재 날짜/시간, 랜덤 값, 전역변수/함수, 사용자 입력 등외부세계에 영향을 주는 코드표준출력, 메세지 발송, 데이터베이스 기록 그래서 우리는 실습으로 주문을 생성할때 가게 영업시간이 아닐시, 주문을 못하게 하는 상황의 로직을 작성했고 테스트코드 작성 시 문제가 생겼다. 내가 현재 새벽에 테스트코드를 돌렸고 영업시간 전이기에 테스트코드가 실패한것이다. 결국 이 부분은 날짜를 파라미터로 받게 변경하여 해결하였다.📚 순수함수- 같은 입력에는 같은 결과- 외부세상과 단절된 형태- 테스트하기 쉬운 코드 TDD: Test Driven Development프로덕션 코드보다 테스트 코드를 먼저 작성하여 테스트가 구현과정을 주도하도록 하는 방법론Red: 실패하는 테스트 작성Green: 테스트 통과하기 위한 최소한의 코딩Refactor: 구현코드 개서느 테스트 통과 유지피드백TDD는 빠르게 피드백을 자동으로 받을 수 있다.선 기능 후 테스트 작성테스트 자체의 누락 가능성특정 테스트 케이스(해피 케이스)만 검증할 가능성이 크다.잘못된 구현을 다소 늦게 발견할 가능성이 있다.선 테스트 후 기능 작성복잡도가 낮은 테스트 가능한 코드로 구현할 수 있게 된다.유연하며 유지보수가 쉬운쉽게 발견하기 어려운 엣지 케이스를 놓치지 않게 해준다.구현에 대한 빠른 피드백 가능과감한 리팩토링이 가능클라이언트 관점에서의 피드백을 주는 Test Driven 테스트는 []다.테스트는 무엇일까? 테스트는 문서라고 볼 수 있다.프로덕션 기능을 설명하는 테스트 코드 문서다양한 테스트 케이스를 통해 프로덕션 코드를 이해하는 시각과 관점을 보완어느 한 사람이 과거에 경험했던 고민의 결과물을 팀 차원으로 승격시켜서 모두의 자산으로 공유할 수 있다. DisplayName을 섬세하게@DisplayName을 사용하여 테스트 명을 구체화할때 명사의 나열보단 문장으로 작성하는 것이 좋다. 또한 테스트 행위에 대한 결과를 기술하는데 도메인 용어를 사용하여 매서드 자체의 관점보다 도메인 정책 관점으로 한층 추상화된 내용을 담는것이 좋다. 마지막으로 테스트의 현상을 중점으로 기술하지 말자. 예를 들어 ~실패라기 보단 도메인의 내용을 담는것이 좋을 것 같다. BDD(Behavior Driven Development) 스타일로 작성하기TDD에서 파생된 개발방법함수단위의 테스트에 집중하기보다 시나리오에 기반한 테스트 케이스(TC) 자체에 집중하여 테스트개발자가 아닌 사람이 봐도 이해할 수 있을 정도의 추상화 수준(레벨)을 권장 Given / When / ThenGiven: 시나리오 진행에 필요한 모든 준비 과정(객체, 값, 상태 등)When: 시나리오 행동 진행Then: 시나리오 진행에 대한 결과 명시 및 검증 어떤환경에서(Given) 어떤 행동을 진행했을 때(When) 어떤 상태 변화가 일어난다.(Then)라는것을 토대로 @DisplayName을 상세히 적을 수 있다. 미션이번 미션은 저번에 Readable Code에서 진행했던 마지막 과제 프로젝트인 '지뢰찾가', '스터디카페'중에 1개의 프로젝트를 가지고 테스트 코드를 작성해보는 시간을 가졌다. 조건은 BDD스타일로 3개이상의 클래스 총 7개 이상 테스트를 작성하는 것이었지만 나는 한층 공부한다는 마음으로 테스트 커버리지 툴인 jacoco를 가지고 스터디 카페부터 진행을 하였다. 그 결과 테스트 커버리지 98%라는 결과를 가지게 되었다. 그리고 조금 더 욕심이 나서 지뢰찾기도 일부 클래스를 진행하였다. 이번 미션을 해보면서 어려웠고 힘들었지만 테스트 작성에 많이 익숙해진 경험을 가지게 되었다. 깃허브 주소 레이어드 아키텍쳐(Layered Architecture)와 테스트레이어드 아키텍쳐에서는 아래와 같이 구성되어 있다.- Persentation Layer- Business Layer- Persistence Layer이렇게 레이어를 나눈 이유는 관심사의 분리때문일 것이다. 책임을 나눔으로서 유지보수성을 쉽게 가져가기 위함이다.🙋🏻 테스트 하기 어려워보여요!그렇게 보일 수는 있겠지만 앞선것과 기조는 비슷하다. 즉, 테스트하기 어려운 걸 분리하여 테스트하고자 하는 영역을 집중하며 명시적이고 이해할 수 있는 문서형태로 테스트 작성하는 것은 어떤 아키텍쳐든 동일하다.A와 B라는 모듈이 있다고 하자. 이 두 모듈을 더했을 때 뭐가 나올까? AB? BA? C? 누구도 예측하기 힘들다. 그래서 우리는 통합 테스트의 필요성이 느껴질 것이다.통합 테스트여러 모듈이 협력하는 기능을 통합적으로 검증하는 테스트일반적으로 작은 범위의 단위테스트만으로는 기능 전체의 신뢰성 보장X풍부한 단위 테스트 & 큰 기능 단위를 검증하는 통합 테스트의 조화가 필요. Spring / JPA 훑어보기 & 기본 엔티티 설계Spring스프링을 애기하면 먼저 라이브러리와 프레임워크의 차이를 묻는다. 라이브러리 같은 경우는 내 코드가 주최가 된다. 즉, 필요한 기능이 있다면 외부에 끌어와서 사용을 하는데 이게 라이브러리다. 반면 프레임워크는 이미 프레임(동작환경)이 있고 내 코드가 주최가 아니고 내 코드는 수동적으로 이 안에 들어가서 역할을 하는데 이게 프레임워크다.스프링을 애기하면 나오는 주요 3가지가 존재한다. IoC, DI, AOP다.- IoC(Inversion of Control): 객체의 생성과 의존성 관리를 프레임워크에 위임하는 개념.- DI(Dependency Injection): 의존성 주입을 통해 객체 간 결합도를 낮추고 확장성과 테스트 용이성을 향상시킴.- AOP(Aspect-Oriented Programming): 횡단 관심사(공통 기능)를 분리하여 코드 중복을 줄이고 모듈성을 개선.ORM객체지향과 RDB 페러다임이 다름.이전에는 개발자가 객체의 데이터를 한땀한땀 매핑하여 DB에 저장 및 조회ORM을 사용함으로써 개발자는 단순 작업을 줄이고 비즈니스 로직에 집중. JPAJava진영의 ORM 기술 표준인터페이스이고 여러 구현체가 있지만 보통 Hibernate를 많이 사용반복적인 CRUD SQL을 생성 및 실행해주고 여러 부가 기능들을 제공편리하지만 쿼리를 직접 작성하지 않기 때문에 어떤식으로 쿼리가 만들어지고 실행되는지 명확하게 이해하고 있어야 함Spring 진영에서는 JPA를 한번 더 추상화한 Spring Data JPA제공QueryDSL과 조합하여 많이 사용 Persistence Layer 테스트요구사항이 다음과 같다고 하자.키오스크 주문을 위한 상품 후보 리스트 조회하기상품의 판매 상태: 판매중, 판매보류, 판매금지판매중, 판매보류인 상태의 상품을 화면에 보여준다.id, 상품번호, 상품타입, 판매상태, 상품이름, 가격 이 요구사항을 바탕으로 우리는 엔티티설계부터해서 컨트롤러까지 즉, Presentation Layer, Business Layer, Persistence Layer까지 전반적으로 한 사이클을 돌면서 코드를 작성해보고 확인까지 진행해보았다. 그럼 이제 repository부분부터 테스트를 해보자.우리는 given-when-then 패턴으로 테스트 코드를 작성했다. 여기서 살펴볼 것은 @SpringBootTest와 @DataJpaTest이다. 이 둘의 비슷하지만 차이점을 살펴보면 @SpringBootTest는 모든 부분의 의존성들을 주입시켜주지만 @DataJpaTest는 JPA관련된 부분만 주입을 시켜준다. 따라서 @DataJpaTest가 더 가볍다. 하지만 우빈님께서는 @SpringBootTest를 선호하신다고 하신다. 그 이유에 대해서는 추후에 말씀주신다고 하셨다.그럼 Persistence Layer 역할에 대해 정리하면 아래와 같다.Data Access 역할비즈니스 가공로직이 포함되어서는 안된다. Data에 대한 CRUD에만 집중한 레이어여야 한다.ex) QueryDSL이나 별도 DAO를 사용하면서 비즈니스 로직이 침투할 가능성이 있을 수 있으니 이 점을 생각하면서 작성해야 할 것 같다. Business Layer 테스트비즈니스 레이어에 대한 역할을 살펴보면 아래와 같다.비즈니스 로직을 구현하는 역할persistence layer와의 상호작용(Data를 읽고 쓰는 행위)을 통해 비즈니스 로직을 전개시킨다.트랜잭션을 보장해야한다. 그래서 우리는 새로운 요구사항을 통해 해당 비즈니스 레이어에 대한 테스트 코드를 작성해보는 시간을 가졌다. 새로운 요구사항은 아래와 같다.요구사항(1)상품번호 리스트를 받아 주문 생성하기주문은 주문상태 주문등록시간을 가진다.주문의 총 금액을 계산한다. 위의 요구사항으로 우리는 주문 엔티티를 설계하고 연관관계를 기존에 만든 상품 엔티티와 다대다 관계를 맺기 위해 중간 엔티티를 설계하고 각각으로 연관관계를 맺어두었다. 그리고 주문생성 로직과 테스트코드를 작성하는 시간을 가졌다.다음으로 우리가 작성한 테스트들을 동시에 돌려보았다. 하지만 실패되는 테스트를 보게되었다. 우리가 작성한 비즈니스 레이어 테스트가 전부 성공하는게 아니라 일부 실패가 되는 경우가 있다. 하지만 이 전에 Persistence Layer에 작성한 테스트를 동시 실행해보면 그것은 괜찮았다. 차이는 @SpringBootTest와 @DataJpaTest 두 어노테이션 차이였다. 두 어노테이션을 타고 들어가서 확인하면 @Transactional 어노테이션 유무 차이였다. 그래서 실패되는 비즈니스 레이어에 트랜잭션 어노테이션을 붙여주면 될 것 같아 보였지만 우빈님께서는 tearDown 메서드를 만드셔서 데이터를 클리닝하는 작업을 해주셨다. 그 이유는 추후에 말씀주신다고 하셨다. 요구사항(2)주문 생성 시 재고 확인 및 개수 차감 후 생성하기재고는 상품번호를 가진다.재고와 관련 있는 상품타입은 병음료, 베이커리다. 새로운 요구사항으로 재고 개념이 도입되었다. 그래서 해당 엔티티를 설계후 개수 차감 로직을 작성하였다. 여기서 위에서 언급한 수동으로 tearDown 메서드로 삭제를 하나하나 해주냐 아니면 @Transactional 어노테이션을 붙여주냐였다. 처음에 우리는 로직을 작성하고 해당 로직을 테스트할때 @Transactional어노테이션을 붙이지 않고 tearDown 메서드를 만들고 실행하였고 결과는 실패하였다. 정상적으로 재고가 감소가 안 된 것이다. 그래서 해당 로그와 쿼리를 보니 update 쿼리가 안 나간것이다. 원래 @Transactional 어노테이션을 붙이면 커밋종료시점에 더티체킹으로 update 쿼리가 발생한다. 하지만 지금은 우리가 수동으로 감소하는 전략을 하였기에 더티체킹 기능이 활성이 안 된 것이다. 🙋🏻 그러면 왜 insert쿼리는 잘 나간거에요?jpa repository를 타고 들어가보면 crud repository를 확인할 수 있다. 해당 구현체를 보면 save 메서드에 @Transactional 어노테이션이 잘 붙어져 있다. 이것은 delete도 마찬가지다.그래서 우리는 추후 살펴볼 것들이 있어 tearDown 메서드는 두고 @Transactional을 product 코드에 적용하기로 했다. 그리로 우빈님께서 이런 경우를 대비해 테스트에는 @Transactional을 붙이고 실질적으로 본 코드에는 안 붙이고 release하는 경우도 있으니 한번 생각하고 써야한다고 말씀을 주셨다.추가적으로 재고감소 로직은 동시성 이슈가 날 수 있는 대표적엔 케이스다. 지금은 키오스크가 1대밖에 없다 가정했지만 2대 이상이라면 동시성 이슈가 터질 것이다. 그래서 optimistic lock / pessimistic lock등을 고민해서 해결을 해야한다. 이 부분도 나중에 한번 더 스스로 공부해봐야겠다.

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

또니

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

[2주차 학습 내용]자료구조와 알고리즘재귀: 어떠한 것을 정의 할 때 자기 자신을 참조하는 것프로그래밍에서 콜스택과 같다.FILO의 특징을 가지고 있다.버블정렬: 앞과 뒤의 값을 비교해서 자리를 비교하는 알고리즘가장 단순하지만 성능이 좋지 않다.O(n^2)의 시간복잡도를 가지고 있다.선택 정렬: 정렬되지 않은 첫번째 값을 시작으로 마지막 원소까지 비교하여 가장 작은 값과 자리를 바꾸는 알고리즘이해와 구현이 간단하지만 버블정렬과 마찬가지로 O(n^2)의 시간복잡도를 가지고 있다. 운영체제SJF, RR, MLFQ, 프로세스 간 통신, 공유자원과 임계구역, 세마포어, 모니터데드락, 데드락 해결, 메모리 종류, 메모리와 주소, 메모리 할당방식 [2주차 회고]처음 재귀에 대해 공부할때 이해하기 힘들었고, 당시에 완벽하게 이해를 하지 못하고 넘어갔었다. 하지만 이번 기회로 정확하게 재귀란 무엇인지 이해하게 되어 알고리즘에 한번 적용해보아야겠다.운영체제는 '이게 정말 무슨말이지..'할 정도로 멍하니 듣다가 끝낸 것 같다..지금은 이런게 있구나 정도로만 알고 넘어간 뒤 다시한번 강의를 들으면서 이해를 하는 것이 필요할 것 같다.알고리즘 강의 링크 👉그림으로 쉽게 배우는 자료구조와 알고리즘 (기본편)운영체제 강의 링크 👉그림으로 쉽게 배우는 운영체제

알고리즘 · 자료구조CS지식인프런워밍업클럽2기

또니

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

[운영체제]FIFO 스케줄링의 장단점이 뭔가요?=> 선입선출의 구조로 단순하고 직관적이라는 장점이 있지만, 한 프로세스가 끝나야 그 다음 프로세스가 실행 되기 때문에 비효율적인 상황이 될 수 있습니다.SJF를 사용하기 여러운 이유가 뭔가요?=> 프로세스가 얼마나 실행될지 예측하기 어렵고, 실행시간이 너무 긴 프로세스는 뒤로 밀려나기 때문에 언제 실행될지 모른다는 단점이 있습니다.RR 스케줄링에서 타임 슬라이스가 아주 작으면 어떤 문제가 발생할까요?=> 컨텍스트 스위칭이 너무 자주 일어나 실행되는 프로세스의 처리량보다 컨텍스트 스위칭을 처리하는 양이 더 커져 오버헤드가 커지는 상황이 발생합니다.운영체제가 MLFQ에서 CPU Bound Process와 I/O Bound Process를 어떻게 구분할까요?=> CPU 스케줄러에 의해 강제로 CPU를 뺐긴다면 CPU Bound Process이고, CPU를 사용하다가 스스로 반납하게 되면 I/O Bound Process입니다.공유자원이란무엇인가요?=> 프로세스들이 공동으로 사용하는 변수, 파일 등을 말합니다.교착상태에 빠질 수 있는 조건은 어떤 것들을 충족해야할까요?=> 상호배제, 비선점, 점유와 대기, 원형 대기가 모두 충족되어야 합니다. [자료구조와 알고리즘]재귀함수에서 기저조건을 만들지 않거나 잘못 설정했을 때 어떤 문제가 발생할 수 있나요?=> 코드가 끝나지 않게 되어 무한반복이 되거나, 잘못 반복이 되어 잘못된 결과가 나올 수 있습니다.0부터 입력 n까지 홀수의 합을 더하는 재귀 함수를 만들어보세요.function sumOdd(n){ if(n <= 0) return 0; if(n %= 2 == 0){ return 0 + sumOdd(n - 1); }else { return n + sumOdd(n - 1); } } console.log(sumOdd(10)) // 25알고리즘 강의 링크 👉그림으로 쉽게 배우는 자료구조와 알고리즘 (기본편)운영체제 강의 링크 👉그림으로 쉽게 배우는 운영체제

알고리즘 · 자료구조CS지식인프런워밍업클럽2기

양성빈

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

이 블로그 글은 박우빈님의 인프런 강의를 참조하여 작성한 글입니다.어느덧 인프런 워밍업 스터디 클럽을 시작한지도 2주째가 시작된다. 그리고 이번주 1주에 대한 회고를 시작해보려고 한다.이번주도 여러가지를 배우고 많은 경험이 된 한 주였다. 그럼 회고를 시작하겠다. 완주 및 우수러너를 위해 오늘도 달려본다.주석의 양면성클린코드 관점에서 주석은 죄악이냐 아니냐 논쟁이 많다.주석이 많다는 것은 그만큼 비즈니스 요구사항을 코드에 잘못 녹였다는 이야기코드를 설명하는 주석을 쓰면 코드가 아니라 주석에 의존한다. 주석에 의존하여 코드를 작성하면 적절하지 않은 추상화 레벨을 갖게 되어 낮은 품질의 코드가 만들어 진다. 🙋🏻 아니 그러면 주석 언제 써요?- 우리가 리팩토링 할때 정말 큰 난관 중 하나가 히스토리를 전혀 알 수 없는 코드다.- 후대에 전해야 할 "의사결정의 히스토리"를 도저히 코드로 표현할 수 없을 때 주석으로 상세히 설명한다.- 주석을 작성할 때 자주 변하는 정보는 최대한 지양해서 작성한다.- 만약 관련 정책이 변하거나 코드가 변경되었다면 주석도 잊지 않고 함께 업데이트 해야한다. 주석이 없는 코드보다 부정확한 주석이 달린 코드가 더 치명적이다.우리가 가진 모든 표현방법을 총동원해 코드에 의도를 녹여내고 그럼에도 불구하고 전달해야할 정보가 남았을때 사용하는게 주석이다.이번 예제 실습은 주석이 달린 gameStatus를 enum으로 변경하고 관련 비즈니스 로직을 MineSweeper가 아니라 GameBoard에 있는게 어울려 그곳으로 변경하였다.변수와 메서드의 나열 순서변수는 사용하는 순서대로 나열한다.인지적 경제성메서드의 순서도 고려해보아야 하는데 객체의 입장에서 생각하자.객체는 협력을 위한 존재이다. 외부세계에 내가 어떤 기능을 제공할 수 있는지를 드러낸다. (정해진 답은 아니지만 우빈님 추천) 공개 메서드들을 상단에 배치하고 나머지를 private 메서드들로 나열한다.공개 메서드들끼리도 기준을 가지고 배치하는 것이 좋다.객체지향을 하다보면 중요한 객체의 경우 메서드가 수십개까지도 늘어날 수 있는데 중요도 순, 종류별로 그룹화하여 배치하면 실수로 비슷한 조직의 메서드를 중복으로 만드는 것을 일관성 있는 로직을 유지할 수 있다.상태변경을 최우선, 그 이후는 판별, 조회로직이 있는 메서드들 순으로 한다.비공개 메서드는 공개 메서드에서 언급한 순서대로 배치한다.공통으로 사용하는 메서드라면 (가장 하단과 같이) 적당한 곳에 배치한다. 이를 통해 우리의 예시 코드도 이와 같이 리팩토링 하는 작업을 해보았다.패키지 나누기패키지는 문맥으로써의 정보를 제공할 수 있다.패키지를 쪼개지 않으면 관리가 어려줘 진다.패키지를 너무 잘게 쪼개도 마찬가지로 관리가 어려워진다.대규모 패키지 변경은 팀원과의 합의를 이룬 시점에 하자.현재 기준으로 본인만 변경하고 있는 부분이라면 괜찮으나 여러 사람이 변경중인 부분이나 공통으로 사용하는 클래스들의 패키지를 한번에 변경하면 추후 브랜츠 충돌이 날 수 있다.따라서 처음 만들때부터 잘 고민해서 패키지를 나누는 것이 좋다.  기능 유지보수하기 (1) - 버그 잡기해당 시간에는 깃발이 전부 꼽았을때 승리조건으로 가는 오류를 고쳐보았다. 이 수정을 통해 우리가 객체지향적으로 작성하여 수정될 곳이 적었지만 만약 이전의 코드였다면 여러군데 고쳐야 할 우려가 있었을 것이다.기능 유지보수하기 (2) - 알고리즘 교체하기 DFS(깊이 우선 탐색) -> 재귀, StackBFS(너비 우선 탐색) -> Queue재귀를 이용한 DFS도 결국 stack이다.스레드마다 생기는 스택영역에는 함수를 호출할 때마다 frame이 쌓인다.frame은 지역변수, 연산을 위한 정보등을 담고 있다.stack영역은 결국 크기가 제한되어 있다.우리가 필요한건 각 Cell의 모든 메서드 정보가 아니다. 각 Cell의 CellPosition만 있다면 원하는 작업을 할 수 있다. 그래서 해당 부분을 통해 우리는 재귀 로직을 stack형태로 변경을 해보았다.IDE의 도움 받기읽기 좋은 코드란 결국 가독성이 좋아야 한다. 이것을 위해 IDE의 큰 도움을 받을 수 있다.코드 포맷 정렬: option + cmd + L | Ctrl + Alt + L코드 품질: SonarLintlint: 잠재적인 문제가 될 수 있는 오류, 버그, 스타일등을 미리 알려주는 코드품질 체크도구포맷규칙: .editorconfig여러사람과의 협업을 염두하면 IDE의 기본 포맷팅에 익숙해지는 것이 좋다.스타일은 혼자 결정하는 것이 아니라 팀 내 합의로 도출되어야 한다.한번 정해지면 절재적인것이 아니라 사용하면서 계속 의견을 듣고 개선/반영하는 것이 좋다. 이런 기능들을 이용하여 우리 예제 프로젝트들도 포맷팅 및 리팩토링을 해보았다. ex) Stack -> Deque연습프로젝트 소개이번에는 새로운 도메인인 '스터디카페 이용 시스템'을 리팩토링하기 전 코드 해석을 하였다. 우빈님께서는 아래와 같은 사항을 중점으로 리팩토링을 해보시라고 하셨다.1. 추상화 레벨 (메서드 추출등)2. 객체로 묶어볼 만한 것은 없는지..3. 객체지향 페러다임에 맞게 객체들이 상호협력하고 있는지4. SRP: 책임에 따라 응집도 있게 객체가 잘 나뉘어져 있는지5. DIP: 의존관계 역전을 적용할만한 곳은 없는지6. 일급 컬렉션그래서 미션을 진행해보고 한번 강의를 학습해야겠다.미션3해당 미션을 하면서 조금은 많은 부분을 느꼈다. 일단 이렇게 클린코드 관점으로 코드를 리팩토링하는 것이 처음이기에 매우 익숙치 않았고 상당히 오래 걸렸다. 일단 나 나름대로 처음에 소개해준데로 리팩토링을 해보았자만 현재 코드에 대해 나름대로 만족을 한다.미션3 깃허브 링크리팩토링 (1) - 추상화 레벨해당 부분에는 예제 프로젝트에서 중복제거 및 메서드 추출 및 객체에 메세지를 보내어 getter방지를 해보았다. 내가 했던 미션과 비교를 해보니 이 부분은 대강 얼추 방향성을 잘 따란것 같다. 나는 여기서 추가적으로 라커 정책을 구현하였는데 이 부분은 내가 잘한 부분인지는 아직도 헷갈린다.리팩토링 (2) - 객체의 책임과 응집도이번 강의에서는 배울 점이 많았다. 나는 해당 설정 관련 부분들을 config에 빼고 해당 config를 getter로 삼는 provider로 넘겨주는 식으로 하였다. 하지만 I/O통합 부분은 진짜 강좌를 보면서 "아! 이것도 있었지.."라는 생각이 들며 조금은 반성이 되었다. 나머지 일급 컬렉션, display()의 책임 분리, Order객체로 분리하여 비즈니스 로직 이관까지는 그래도 비슷하게 갔던것 같다. 나는 거기서 조금 if문 3개로 나눠진 display를 switch문으로 변경까지 조금 읽기 쉬운 코드로 변경해보았다.리팩토링 (3) - 관점의 차이로 달라지는 추상화해당 부분은 나는 DIP 생각 없이 지뢰때 했던것 처럼 초기화 로직과 실행로직을 분리하고 이렇게 생각하니 FileHandler부분도 두개의 메서드를 분리할 수 있지 않을까 싶었고 그렇게 분리를 하였는데 강의에서는 DIP원칙을 적용하여 했었던것이다. 왜 그런지 모르고 그냥 기계처럼 한 것이 조금 반성스럽고 고쳐야할 부분이라 생각이 든다.능동적 읽기복잡하거나 엉망인 코드를 읽고 이해하려 할 때 리팩토링 하면서 읽기공백으로 단락 구분하기메서드와 객체로 추상화 해보기주석으로 이해한 내용 표기하며 읽기우리에게는 언제든 돌아갈 수 있는 git reset --hard가 있다.핵심목표는 우리의 도메인 지식을 늘리는 것 그리고 이전 작성자의 의도를 파악하는 것 이전까지 나는 코드를 눈으로 해석하고 리팩토링 하려는 습관들이 있었다. 하지만 이번 강의를 통해 코드를 분리해보고 주석도 달아보면서 리팩토링하면서 읽어가야겠다는 습관으로 고쳐야겠다는 생각이 들었다.오버 엔지니어링필요한 적정수준보다 더 높은 수준의 엔지니어링ex) 구현체가 하나인 인터페이스인터페이스 형태가 아키텍쳐 이해에 도움을 주거나 근시일내에 구현체가 추가될 가능성이 높다면 OK.구현체를 수정할때마다 인터페이스도 수정해야함.코드 탐색에 영향을 줌 / 어플리케이션이 비대해짐ex) 너무 이른 추상화정보가 숨겨지기 때문에 복잡도가 높아진다.후대 개발자들이 선대의 의도를 파악하기가 어렵다. 지금 이 내용을 학습해보니 이전에 미션3에서 내가 구현한 코드들이 오버엔지니어링이였지 않을까라는 생각을 하면서 반성하게 되었다.은탄환은 없다클린코드도 은탄환은 아니다.실무: 2가지 사이의 줄다리기지속가능한 소프트웨어의 품질 vs 기술부채를 안고 가는 빠른 결과물대부분의 회사는 돈을 벌고 성장해야하고 시장에서 빠르게 살아남는 것이 목표이런 경우에도 클린코드를 추구하지 말라는 것이 아니라 미래시점에 잘 고치도록 할 수 있는 코드센스가 필요하다. 결국은 클린코드의 사고법을 기반으로 결정하는 것모든 기술의 방법론은 적정 기술의 범위 내에서 사용ex) 당장 급하게 배포나가야 하는데 동료에게 style관련된 리뷰를 주고 고치도록 강요하는 사람도구라는 것은 일단 그것을 한계까지 사용할 줄 아는 사람이 그것을 사용하지 말아야 할때도 아는 법이다.적정 수준을 알기 위해 때로는 극단적인 시도도 필요하다. 이것을 보고 미션때 오버 엔지니어링을 해보는것도 좋은 경험이 되었다고 다시 느끼게 되었다.📚 기술부채란?현 시점에서 더 오래 소요될 수 있는 더 나은 접근방식을 사용하는 대신 쉬운(제한된) 솔루션을 채택함으로써 발생되는 추가적인 재작업의 비용을 반영하는 소프트웨어 개발의 한 관점마무리하며드디어 해당 강의가 마무리 되었다. 여기서 가장 핵심은 추상이다. 우리는 또한 추상과 구체를 인식할 수 있다. 김창준님께서 집필하신 '함께자라기'라는 책을 보면 알듯이 추상과 구체를 넘나들어야 한다. 때로는 bottom-up 때로는 top-dowon을 사용하면서 추상적인 시각과 구체적인 시각을 자유롭게 사용해보고 조금 더 읽기 쉽고 좋은 코드를 작성하는 개발자가 되어야 겠다는 생각이 들었다.Day4 공통 피드백내 코드가 예시로 나왔다 우빈님께서 해주신 말씀은 아래와 같았다.1. boolean으로 return하고 있는 메서드에 예외를 발생시키는데 시도는 좋으나 항상 메서드의 사용현황을 파악 후 상황에 맞게 리팩토링을 하는 것이 좋다. 또한 예외 던지는 것은 비싸기에 항상이 아닌 신중하게 하시라고 조언을 주셨다.2. 추출한 메서드의 static 키워드가 존재한다면 인텔리제이 IDE에서 메서드 추출을 하면 자동으로 붙기에 알아서 제거해줘야 한다.3. 상황에 맞게 적절한 수준의 리팩토링이 좋다. 너무 자세히 가면 오버 엔지니어링이 된다.Day7 코드리뷰내가 만든 코드에서 StudyCafeConfigProvider라는 객체를 만들고 사용중이였는데 아래와 같이 이 안에는 전부 static 메서드만 있었다.public class StudyCafeConfigProvider {     private static final StudyCafeConfig CONFIG = new StudyCafeConfig();     public static InputHandler getInputHandler() {         return CONFIG.getInputHandler();     }     public static OutputHandler getOutputHandler() {         return CONFIG.getOutputHandler();     }     public static StudyCafeSeatReadProvider getStudyCafeSeatReadProvider() {         return CONFIG.getStudyCafeSeatReadProvider();     }     public static StudyCafeLockerReadProvider getStudyCafeLockerReadProvider() {         return CONFIG.getStudyCafeLockerReadProvider();     }     public static Map<StudyCafePassType, StudyCafePassType> getStrategyMap() {         return CONFIG.getStrategyMap();     }     public static Map<StudyCafePassType, LockerPolicyType> getLockerPolicyMap() {         return CONFIG.getLockerPolicyMap();     } }이런 경우에는 private constructor를 만드는것이 좋다고 SonarLint에서 알려준다. 하지만 내 인텔리제이에서는 SonarLint를 적용되어 있지만 경고가 따로 뜨지 않았는데 이 부분은 한번 자세히 살펴봐야겠다.자세한 리뷰 및 후기는 추가 포스팅을 하여 정리해봐야겠다.후기이번 주도 금방 지나갔다. 리뷰를 들으면서 많은 고민과 생각이 들었다. 또한 다른 러너분들의 코드를 보면서 신박한 생각과 좋은 점들이 눈에 보이기 시작했다. 우빈님이 주신 피드백과 다른분들의 코드중에 좋은 점들을 채택해서 더 좋은 코드들로 한번 리팩토링을 다시금 해봐야겠다. 다음주부터는 테스트 강의의 시작이다. 테스트도 조금은 걱정이 되지만 열심히 해서 조금 더 성장하는 주가 되었으면 하는걸로 마무리를 지어보겠다.

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

오리너구리

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

인프런 워밍업클럽 2기를 시작하며슬픈이유로 회사를 퇴사하고 면접 준비하고 나를 계속 증명하고 정신없는 나날을 보내다가 인프런 워밍업 클럽 공지를 보았다.개인 포트폴리오도 있어빌리티하게 가꾸고 겸사겸사 IT계의 진정한 조각의 꽃인 플랫폼 디자인 직군에 지원해 보고 싶었는데 작업 동기부여가 필요해서 워밍업 클럽을 신청하게되었다. (도깨비 방망이 하나를 냅다 파고 조각하는걸 좋아하는 강박 성향이 있어서 플랫폼 디자이너 이전부터 너무 해보고 싶은 직무였었다.)  1주차때 배운 것배리어블 등록 (색상, 간격, 타이포그래피, 아이콘, 그림자 그리드) 이전에도 강의를 듣긴 했는데 퇴사하고 오랜만에 복기하려니 또 새로웠다. 그래도 전에는 다시 뒤돌아가고 다시듣고 백버튼을 무한대로 누르면서 보는 엉금엉금 속도였는데 이제는 이해가 훨씬 빠르게 되었었다. 아쉬웠던 점내 개인 프로젝트에 적용해보지 않은 나의 습관반복 복습하는 자세도 중요하지만 개발환경이나 내 서비스에 맞게 고민해보고 베리어블을 짜볼 수 있는 경험으로 이어져야 진정한 내것이 될 것 같았다. 너무 그간 수동적이였던 건 아니였을까? 그러면서도... 맘 한켠으론 모르는데 어캄? 이해될 때까지 반복해보는것도 중요한디? 혼란스러웠다.  다음에 시도해보기포폴용 DS 개인 파일 만들어보기전에 다닌 회사에서 베리어블 나오기 전에 작업한 컴포넌트 라이브러리? 가이드라인? 정도 볼륨의 피그마 작업 파일이 있었는데 해당파일에 베리어블과 토큰 개념을 추가해서 업데이트 해보려한다. 이걸 가지고 플랫폼 디자이너 채용 공고에도 지원을 할 것이다. 경기가 너무어려워서 PD취업도 쉽지 않고 아직도 뭐해 먹고 살지 고민이지만, 절대 포기하지 않고 나만의 무기를 계속 연마해서 좋은 동료들이 있는 회사에 꼭 붙고 말것이다.

UX/UI디자인시스템DS베리어블워밍업클럽볼드님강의2기

ppusda

인프런 워밍업 클럽 2기 - 백엔드 프로젝트(Kotlin, Spring) / 4주차 발자국

⭐ 1주 동안 배운 내용을 정리하고 회고하는 시간을 가져보자. 16~18 일차 - Admin ViewView3주차에 이어서 Admin View를 만들어보게 되었다.이번에도 마찬가지로 중복되는 부분을 fragment와 layout으로 분리하는 작업을 진행했다.그리고 사용자가 직접 업데이트 하는 부분이 있기에, 추가적으로 script-util 파일을 통해 API에 요청을 보내도록 했다. 19 일차 - GCP, Docker암호화배포 이전에 설정 값을 암호화 하기 위해 jasypt를 사용하게 되었다.Jasypt?애플리케이션을 배포할 때 공개되면 안되는 값들이 평문으로 올라가는 것을 막기 위해 암호화할 수 있는 라이브러리이다.아래는 암호화한 DB 비밀번호가 들어있는 설정파일의 일부분이다. datasource: url: jdbc:mysql://mysql:3306/portfolio username: root password: ENC(ZeronFrlX1yD4JW496HshMgc9t1kUrQi) driver-class-name: com.mysql.cj.jdbc.Driver ENC(암호화 내용)으로 내용이 암호화 되었음을 표시해야한다. 배포Docker를 이용해서 빌드 한 이미지를 Docker hub에 올리고 이를 서버에서 내려받아 사용했다.이후 GCP를 이용하여 서버를 생성하고, Docker를 이용해 MySQL과 프로젝트를 빌드 시켰다.마지막으로 도메인을 연결하고, 이를 제출하며 마지막 7번째 미션도 해결 할 수 있었다.결과물은 아래와 같다.Dongguk's Portfolio 20일차 - 서브 미션, 코드 리뷰3주차 때와 일정이 거의 겹쳐 3주차 발자국에 포함시키지 못했던 미션 5는 4주차에서 소개하겠다.각 API마다 3개의 테스트 코드를 작성해야 했기에 열심히 작성해서 테스트를 진행해보았다. 이번에도 관련 내용은 README에 정리했다.https://github.com/ppusda/MML 이후 마지막에는 최종 점검과 코드 리뷰 시간이 진행되었다.https://github.com/ppusda/MML/pull/1많이 배워갈 수 있었던 좋은 시간이 되었던 것 같아서 조언 받은 내용을 정리해보고자 한다. Rest API와 VersioningRest APIAPI를 작성할 때 Restful 하도록 고려를 하는 편이라고 생각했지만, 주의하지 못했던 부분이 있었다.자원을 복수형으로 명시/user ⇒ /usersVersioning사실 지금까지 코드를 작성해보면서 “API에 버저닝이 굳이 필요할까?” 라고 생각해서 배제 했었다.하지만 이번 코드리뷰를 받아보면서 버저닝의 중요성을 알게되었다.API의 기능이나 데이터 구조가 변경될 때, 기존 클라이언트가 정상적으로 작동하도록 하기 위해 버전 관리를 통해 이전 버전을 유지하도록 사용할 수 있다.⇒ 사용자가 원하는 버전을 사용하도록 할 수 있고, 업데이트 시기를 사용자가 정하도록 할 수 있다.이로 인해 호환성과 안정성을 챙기고 사용자 경험을 개선시킬 수 있다는 것을 알게되었다. find 와 get의 차이이 부분에 대해서는 진지하게 고민해 본 적은 없었던 것 같다.간단하게 find는 “DB에서 찾기”, get은 “찾아온 데이터를 가져오기”라고만 생각하고 코드를 작성했었다. 하지만 코치님께서 소개해주신 내용을 통해 좀 더 시선을 달리하게 되었다.How and why to decide between naming methods with "get" and "find" prefixes get~은 실패하지 않으며 짧은 시간으로 요소를 가져올 때 사용되는 단어.find~는 실패할 수 있으며 긴 시간이 소요되어 요소를 찾아낼 때 사용되는 단어. 위 내용을 참고해서 앞으로 메서드 네이밍을 사용할 때 주의해야 할 것 같다. Test code 방향성요즘에 가장 관심이 많이가고 그만큼 잘 모르겠는 내용이 테스트 코드이다.이번에 테스트 코드를 강의를 기반으로 혼자 프로젝트에 작성해다보니까 방향성에 대해 의문이 많이 들었다. “이런 테스트 코드를 어떻게 짜면 좋은건지 모르겠다” 라고 질문 드렸는데, 그 부분에 대해서 커버리지를 최대한으로 채워보면서 감을 익히면 좋을 것 같다고 말씀해주셨다. 추가로 관련해서 좋은 레퍼런스를 추천해주셨다.토스ㅣSLASH 21 - 테스트 커버리지 100% 내용을 들어보고 서브 미션 프로젝트를 고도화 할 때 좀 더 좋은 테스트 코드를 작성하도록 노력해볼까 한다. 총 회고4주차로 스터디가 마무리 되었다.이번 4주차에는 일정이 너무 많고 도저히 시간이 안나기도 했지만, 강의를 보면서 따라 친 부분들이 잘못 입력되어서 동작하지 않는 곳들을 찾아내는데 고생을 좀 하게 되었다.이상하게 로컬 환경에서는 잘되었는데, 배포만 하면 고장이 나서 원인을 찾기가 힘들었지만, 너무 간단한 오타들이어서 허무했다. 강의도 끝나고 더 이상 미션도 없어서 강제성은 사라졌지만 계속해서 나름대로 고도화를 진행해보려고 한다.최종 점검에서 아직 나의 부족한 모습들을 많이 보게 되었지만, 여러모로 자극도 많이 받아서 힘들어도 계속해서 학습을 이어나가려고 한다. 코치님도 너무 친절하셨고 꾸준하기가 쉽지 않아서 많이 몰아들었지만, 어찌저찌 마무리를 하게 되었다.이상의 내용은 개인 블로그에 완전 총 회고로 다시 한 번 작성하겠다. 모두 화이팅! (o゚v゚)ノ

백엔드워밍업클럽백엔드2기Kotlin

또니

[인프런 워밍업 클럽 2기 CS] 특별 미션

회사에서 야근 이슈로 참여하지 못했던 중간 점검을 만회할 수 있는 기회를 주시다니 감사합니다🥰 특별 미션)  실수로 워밍업 클럽 출석을 빼먹었는데 우연히 데이터를 수정할 수 있는 권한이 주어졌습니다. 러너분의 이름(name)과 출석수(count)가 저장된 배열에서 여러분(나)의 데이터를 퀵정렬을 이용해 오름차순 정렬하고 가장 첫 번째 데이터인 여러분의 출석수를 변경하도록 코드를 작성해주세요. (퀵정렬 구현 부분도 변경)function quickSort (arr, left, right) { if (left < right) { let index = divide(arr, left, right); quickSort(arr, left, index - 1); quickSort(arr, index + 1, right); } } function divide(arr, left, right) { let rightCnt= arr[right].count; let leftIndex = left - 1; for (let i = left; i < right; i++) { if (arr[i].count <= rightCnt) { leftIndex++; [arr[leftIndex], arr[i]] = [arr[i], arr[leftIndex]]; } } [arr[leftIndex + 1], arr[right]] = [arr[right], arr[leftIndex + 1]]; return leftIndex + 1; } let user1 = { name: "홍길동", count: 5 }; let user2 = { name: "임꺽정", count: 4 }; let user3 = { name: "이순신", count: 3 }; let user4 = { name: "나", count: 1 }; let user5 = { name: "짱구", count: 5 }; let arr = [user1, user2, user3, user4, user5] console.log("===== 정렬 전 ====="); console.log(arr); quickSort(arr, 0, arr.length - 1); arr[0].count = 5 console.log("===== 정렬 후 ====="); console.log(arr); [예상 결과] ===== 정렬 전 ===== [ { name: '홍길동', count: 5 }, { name: '임꺽정', count: 4 }, { name: '이순신', count: 3 }, { name: '나', count: 1 }, { name: '짱구', count: 5 } ] ===== 정렬 후 ===== [ { name: '나', count: 5 }, { name: '이순신', count: 3 }, { name: '임꺽정', count: 4 }, { name: '홍길동', count: 5 }, { name: '짱구', count: 5 } ] 

알고리즘 · 자료구조CS지식인프런워밍업클럽2기

ppusda

인프런 워밍업 클럽 2기 - 백엔드 프로젝트(Kotlin, Spring) / 3주차 발자국

⭐ 1주 동안 배운 내용을 정리하고 회고하는 시간을 가져보자. 11 ~ 12 일차 - Controller, Test, ViewTest이전과 이어서 Controller를 개발하고 이에 대한 Test를 작성하게 되었다.아래는 작성한 테스트 코드의 일부분이다.@DisplayName("[API 컨트롤러 테스트]") @SpringBootTest // Spring boot를 실제로 띄운 다음에 테스트가 진행 됨 @AutoConfigureMockMvc // MockMvc 관련 설정 세팅 class PresentationApiControllerTest( @Autowired private val mockMvc: MockMvc ) { // 생략 private fun performGet(uri: String): MvcResult { return mockMvc .perform(MockMvcRequestBuilders.get(uri)) .andDo(MockMvcResultHandlers.print()) .andReturn() } } @SpringBootTestSpring Boot 애플리케이션을 테스트 할 때 사용되는 어노테이션이다.실제 애플리케이션 환경과 유사한 환경을 구성하여 테스트를 진행할 수 있다.@AutoConfigureMockMvcSpringMVC를 모의로 테스트 할 때 사용되는 어노테이션이다.MockMvc 객체가 자동으로 구성하고 테스트 환경을 유사하게 구성할 수 있다.MockMvc는 실제 서버를 실행하지 않고도 컨트롤러의 요청 및 응답을 테스트 할 수 있도록 한다.여기서 SpringBootTest와 AutoConfigureMockMvc를 같이 사용하는 것에 모순을 느끼게 되었고, 좀 더 내용을 찾아보게 되었다.@WebMvcTestMVC 레이어를 테스트하는데 사용되는 어노테이션이다.특정 컨트롤러와 그에 관련된 컴포넌트들만 주입받아 특정 컨트롤러의 동작을 집중적으로 테스트 할 수 있다.MockMvc를 자동으로 설정하고 주입하여 요청 및 응답을 테스트 할 수 있도록 한다.기본적으로 Service, Repository를 제외하기에 테스트가 가볍고 빠르게 진행될 수 있다. ⇒ 필요하다면 Mock 객체를 통해 주입할 수 있다.결론적으로 말하자면 아래와 같다.💡 Contorller를 집중적으로 테스트하기 위해서는 @SpringBootTest, @AutoConfigureMockMvc 를 사용하는 것 보다 @WebMvcTest를 사용하는 것이 Controller 단위 테스트 패턴에 적합하다. 그렇다고 @SpringBootTest를 사용하면 안된다는 것은 아니다.실제로 통합 테스트를 작성할 때 (=Controller, Service, Repository 등 여러 컴포넌트가 함께 작동할 때)는 SpringBootTest를 사용하여 실제로 적용될 설정이나 복잡한 시나리오가 정상적으로 작동되는지 확인할 때 사용할 수 있다. ViewThymeleaf를 활용해서 포트폴리오 페이지를 만들어 보게되었다.강사님 처럼 고양이 사진을 넣어보고 싶었지만, 어울리는 사진을 넣기가 힘들기에 가지고 있던 다른 사진으로 대체해보았다.기존 코드에서 중복되는 부분을 fragment와 layout으로 분리하였고, 이를 이용하여 더 깔끔한 코드를 만들 수 있었다. 13 ~ 15 일차 - Admin Controller, ServiceKotlin13 ~ 15일차에 접어들면서 대부분의 Kotlin 문법에 대해서는 꽤 익숙해진 것 같다.3 ~ 5일차에는 변수 선언과 함수 선언 그리고 문자열 작성에 대한 차이점을 다뤄봤었다.이번에는 강의에서 만나봤던 차이점 중 간편하다고 느꼈던 차이점에 대해서 정리해보고자 한다. 먼저, for 문이 간편하게 바뀌었다는 생각을 많이 하게 되었다.변수 선언같은 부분도 사라지고, .. 을 이용해 1에서 10까지의 범위를 지정할 수 있었다.물론, until과 같이 이전 값 까지 증가와 같은 기능과 step()을 이용하여 증가 값을 설정할 수도 있다.for (i in 1..10) // Kotlin for (int i = 1; i <= 10; i++) // Java  두번째로 @RequiredArgsConstructor를 사용하지 않아도 되는 부분이 매우 편했다.Kotlin은 class 생성 시 기본 생성자를 매우 쉽게 작성할 수 있고, 이를 프로퍼티로 생성 해준다. 여기서의 프로퍼티는 자바에서의 필드 뿐만 아니라 getter, setter를 포함한다고 생각하면 된다.이에 대한 자세한 내용은 아래 블로그를 참고하면 도움이 될 것이라고 생각한다.[Java/Kotlin] 필드(Field)와 프로퍼티(Property)는 무슨 차이가 있을까? 이때, val로 매개변수를 선언하게되면 Java 로 생각하자면 불변 필드와 해당 필드에 대한 생성자까지 만들어지게 된다.@Service class AdminAchievementService( private val achievementRepository: AchievementRepository ) @Service public class AdminAchievementService { private final AchievementRepository achievementRepository; public AdminAchievementService(AchievementRepository achievementRepository) { this.achievementRepository = achievementRepository; } // 생략 } 그렇기에 Java에서 생성자 주입을 통해 의존성을 주입 할 수 있게 되며 별도의 @RequiredArgsConstructor 어노테이션을 사용하지 않아도 된다. 마지막으로 그외에도 다양한 편의 기능들이다.val pageAttributes = mutableMapOf<String, Any>( Pair("menuName", "Resume"), Pair("pageName", table.name), Pair("editable", true), Pair("deletable", false), Pair("hasDetails", false) ) // Kotlin에서 Map에 데이터를 넣어줄 때 Pair를 사용할 수 있음 val id = line.slice(0..endIndex).toLong() // Long 타입으로 변환 Pair와 같이 Map에 데이터를 더 편하게 넣을 수 있도록 Key-Value 형식으로 값을 설정할 수 있었고,String의 경우도 단순히 toLong()과 같은 기능으로 변환을 쉽게 할 수 있었다. 이런 것들이 별 것 아닌 거 같아보여도 실제로 쌓이다 보면 꽤나 피로한 요소들이어서 정말 좋다고 느꼈던 것 같다.아직 모르는 부분도 분명히 많을 것이지만 Kotlin을 통해서 만족감을 느낄 수 있었다. 퍼사드 패턴이 과연 유리한가?다음으로 정리할 내용은 퍼사드 패턴에 대해서다.퍼사드 패턴(Facade Pattern)은 구조 패턴의 한 종류로 복잡한 서브 클래스들의 공통적인 기능을 정의하는 상위 수준의 인터페이스를 제공하는 패턴이다. 이는 사실 8 ~ 10일차에서 Service, Repository 부분에서 소개했던 한 번에 의존관계를 주입받을 수 있는 Repository 를 생성했다는 내용에서 사용 된 패턴이다.사용할 때는 사실 모르고 사용했지만, Admin 부분에 대한 강의에서는 퍼사드 패턴을 사용하지 않고 필요한 컴포넌트들만 주입받아 사용하며 강사님께서 “퍼사드 패턴과 이런 방식 중에 뭐가 더 유리한지 생각해보면 좋을 것 같다”고 말씀해주셨다. 기존에 코드를 작성할 때는 디자인 패턴에 대해서 모르기도 했었지만 항상 필요한 것만 불러와서 써도 괜찮다고 생각하고 있었다.하지만, 실제로 퍼사드 패턴을 사용하면서 느낀 점은 “컴포넌트를 묶어 사용할 수 있다면 코드가 많이 줄겠다” 였다.실제로 Presentation 부분에서는 컴포넌트를 묶음으로써 생성자 부분에 작성하게 된 코드를 줄일 수 있었다. 하지만, 반대로 생각해보면 묶을 필요가 없다면 굳이 사용할 필요가 없는 패턴이기도 하다.실제로 Admin 부분을 개발하면서는 각 도메인 부분으로 폴더를 나눠 서비스 로직을 작성했으며, 각 서비스 단에서 필요한 리포지토리만 불러와 사용하였다. 결론적으로 상황에 따라 유리할 수도 있고, 아닐 수도 있다.학습하다 보면 항상 결론은 위와 같이 나오는 것 같은데 그만큼 상황에 맞는 구조와 코드를 잘 적용시키는게 중요하다는 생각을 하게되었다. 서브 미션이번 3주차에는 미션 4를 수행하게 되었다.미션 4는 조회 API를 만들고 이에 대한 테스트 코드를 작성하는 것이 내용이었고 열심히 작성해서 제출하였다.이후 미션 내용을 README에도 정리해보았다.https://github.com/ppusda/MML서브 미션을 진행하면서도 약간의 배운 점이 생겨서 이 또한 정리해보고자 한다. TargetEntity와 MappedBymappedBy의 경우는 많이 사용해봤지만, TargetEntity의 경우는 사용한 적이 없어 어떤 차이가 있는지 궁금하게되었다.targetEntity관계의 대상 엔티티를 명시적으로 지정할 때 사용된다. (관계 대상을 명시적으로 지정)주로 @OneToMany, @ManyToMany와 같은 어노테이션에서 사용하며, 관계의 상대 엔티티 클래스의 이름을 지정한다.mappedBy관계의 주체와 종속성을 정의합니다. (관계의 주체를 설정함)주로 양방향 관계에서 사용되며, 관계의 주체가 되는 쪽에서 어떤 필드가 관계를 관리하는지를 지정한다. 총 회고3주차에는 드디어 화면을 직접 개발해보면서 좀 더 포트폴리오에 다가가고 있다는 생각이 들었다.미션을 따라서 진행하면서 좀 더 나만의 포트폴리오 처럼 꾸밀 수 있는 방법은 뭐가 있을까에 대해서도 생각해보려고 한다. 개발적으로도 성장하고 있는 것이 느껴지기도 하지만 그와 동시에 많이 멀었다는 생각도 계속하게 된다.특히 강사님의 코드를 보며 학습하다보니까 구조나 코드가 정말 정갈하다는 생각을 하게되었다.위에서 정리했던 Kotlin의 특성이나 디자인 패턴을 정말 잘 적용한다는 생각이 들었고, 앞으로 나도 그렇게 할 수 있는 개발자가 되고 싶다는 생각을 하게 되었다. Kotlin에 대해서도 많이 익숙해진 것 같다.Kotlin이 Java의 상위호환이라는 말을 많이 들었는데, 이전 경험이 있어서 크게 기대는 하지 않고 학습을 진행했다.하지만 정말 편한 점이 많이 있었고, 더 공부해서 코루틴 같은 개념도 적용해보고 싶다고 생각했다. 앞으로도 계속 개발자로 공부할 수 있도록 노력해야겠다.모두 화이팅! (o゚v゚)ノ

백엔드워밍업클럽백엔드2기Kotlin

또니

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

[운영체제]while(true){ wait(1); // 1초 멈춤 bool isActivated = checkSkillActivated(); // 체크 }이 방식은 폴링방식입니다. 1초마다 체크하기 때문에 성능에 좋지 않습니다.이를 해결하기 위한 방식으로 어떤 걸 이용해야 할까요?=> 인터럽트 방식, 스킬이 사용 되었을 경우 응답을 받는 방식으로 이용한다.프로그램과 프로세스가 어떻게 다른가요?=> 프로그램은 .exe와 같은 실행 파일을 의미하고, 이 .exe와 같은 실행 파일을 실행 했을 때 메모리에 올라가 실행 중인 프로그램 이다.멀티프로그래밍과 멀티프로세싱이 어떻게 다른가요?=> 멀티프로그래밍은 메모리에 여러개의 여러 개의 프로세스가 올라가는 것이고, 멀티 프로세싱은 CPU가 여러개의 프로세스를 처리하는 것이다.운영체제는 프로세스를 관리하기 위해서 어떤 것을 사용하나요?=> 운영체제는 PCB에 담긴 프로세스의 정보를 사용하여 프로세스를 관리한다. 프로세스마다 PCB가 생성되고, 프로세스가 종료되면 PCB도 제거 된다. 이 PCB는 자료구조에서 배웠던 연결리스트로 구성되어 있다. 컨텍스트 스위칭이란 뭔가요?=> A 프로그램이 실행되고 있는 상태에서 B 프로그램이 실행 되도록 하는 것을 말한다. 이때 A 프로그램이 멈춘 시점에서 다시 시작 될 수 있도록 PCB A에 A 프로그램의 상태 값을 저장한 뒤, B 프로그램을 실행하기 위해 PCB B에 있는 이전 상태 값으로 CPU 레지스터 값을 설정한다.[자료구조와 알고리즘]여러분은 교실의 학생 정보를 저장하고 열람할 수 있는 관리 프로그램을 개발하려고 합니다. 이 때 여러분이라면 학생의 정보를 저장하기 위한 자료구조를 어떤 걸 선택하실 건가요? 이유를 함께 적어주세요.=> 해시테이블, 학생은 학생 고유의 학번을 가지고 있기 때문에 학번을 Key로 하는 해시 테이블을 사용할 것입니다.해시테이블은 동적으로 크기를 변화시키는데 유연하여 전학을 오고 갈 수 있는 학생의 정보를 자유롭게 삽입 및 삭제가 가능합니다. 또한, O(1)의 시간복잡도를 가지기 때문에 빠르게 학생의 정보를 검색할 수 있기 때문에 해시테이블을 선택하였습니다.여러분은 고객의 주문을 받는 프로그램을 개발하려고 합니다. 주문은 들어온 순서대로 처리됩니다. 이 때 여러분이라면 어떤 자료구조를 선택하실 건가요? 이유를 함께 적어주세요.=> 큐(Queue), 큐는 선입선출로 먼저 들어온 값이 먼저 나가는 특징을 가지고 있습니다. 주문이 들어온 순서대로 처리되는 프로그램을 개발하기 위해선 큐를 선택하는 것이 적합한 자료구조라고 생각합니다.알고리즘 강의 링크 👉그림으로 쉽게 배우는 자료구조와 알고리즘 (기본편)운영체제 강의 링크 👉그림으로 쉽게 배우는 운영체제

알고리즘 · 자료구조CS지식인프런워밍업클럽2기

ppusda

인프런 워밍업 클럽 2기 - 백엔드 프로젝트(Kotlin, Spring) / 2주차 발자국

⭐ 1주 동안 배운 내용을 정리하고 회고하는 시간을 가져보자. 6 ~ 7일차 - Repository, TestFetchType과 N+1 문제강의에서 FetchType에 따른 쿼리 작동 과정을 보여주셨고 이 때 발생할 수 있는 N+1 문제에 대해서 언급이 되었다.N+1 문제는 JPA를 사용하여 Entity를 조회할 때 발생할 수 있는 문제로 아래와 같이 부모 엔티티를 조회할 때, 연관 되어있는 자식 엔티티들의 수 N 만큼의 쿼리가 발생하여 성능에 지장을 줄 수 있는 문제다. 지연로딩을 사용했을 때는 각 엔티티를 실제 사용할 때 마다 쿼리가 발생하였고, 즉시로딩으로 변경하자 모든 엔티티의 정보를 한꺼번에 수집하여 두 경우 모두 N+1 문제가 발생함을 볼 수 있었다.이를 해결하기 위해 JPQL에서 Fetch Join 쿼리를 작성하고 application.yml 을 수정하게 되었다. Fetch Join과 Fetch SizeJPA에서 쿼리를 직접 작성하기 위해서는 JPQL을 사용할 수 있다.아래는 강의에서 작성했던 쿼리 부분이다.@Query("select e from Experience e left join fetch e.details where e.isActive = :isActive") fun findAllByIsActive(isActive: Boolean): List<Experience> Fetch Join을 사용하여 연관관계를 한번에 조회할 수 있었고, 단 한번의 쿼리로 줄어든 것을 볼 수 있다.하지만 이 경우에도 @~ToMany의 관계를 갖는 자식 엔티티가 여러 개인 경우에는 적용할 수 없다는 한계가 있다.이는 MultipleBagFetchException 이 발생하기 때문인데, 그 이유는 다수의 자식 엔티티를 Fetch Join하게 될 경우에 중복이 발생하고 일관성이 떨어지게 된다.그렇기에 JPA에서 이를 방지하기 위해 MultipleBagFetchException 를 통해 두 개 이상의 자식 엔티티를 Fetch Join 하는 것을 막아두었다. 이를 해결하기 위해 Fetch Size를 조정하여 해결할 수 있다.spring: jpa: properties: hibernate: default_batch_fetch_size: 10 기존의 문제점은 자식 엔티티가 여러 개일 경우 하나의 Fetch Join만 사용가능하며, 그로 인해 N개의 쿼리가 더 발생한다는 점이었다.default_batch_fetch_size 를 조정하여 되면 부모 엔티티의 Key를 이용하여 in 절을 통해 조정한 default_batch_fetch_size 만큼씩 자식 엔티티를 조회할 수 있다.Test6~7일차에는 이러한 내용들을 테스트 해볼 수 있는 Repository 테스트 코드를 작성하게 되었다.아래 내용은 강의에서 작성한 코드의 일부분이다.@DataJpaTest @TestInstance(TestInstance.Lifecycle.PER_CLASS) // 클래스 간 독립적으로 실행 됨. class ExperienceRepositoryTest( @Autowired val experienceRepository: ExperienceRepository ) { @DataJpaTestJPA 관련 테스트를 위한 설정을 제공하는 어노테이션이다.그렇기에 데이터에 접근할 수 있는 레이어인 리포지토리 테스트 시 많이 사용된다.내장 데이터베이스를 설정하고, @Entity 및 @Repository 어노테이션이 부여된 클래스들을 통해 테스트 환경을 구성하는 역할을 한다.@TestInstance테스트 인스턴스의 라이프사이클을 지정하기 위해 사용된다.기본적으로 JUnit 5는 각 @Test 메서드마다 새로운 테스트 인스턴스를 생성하게 되어있다.이는 테스트 환경을 어떻게 구성할 것이느냐에 따라 달라지겠고, 상황에 맞춰 사용하면 될 것 같다. 8 ~ 10일차 - DTO, Service, TestDTOKotlin에서는 Java의 Record처럼 data class를 통해 DTO를 선언해 줄 수 있었다.추가적인 생성자를 선언하기 위해서는 constructor 를 이용하여 만들어 줄 수 있었다.map, filter와 같은 컬렉션 함수를 적용할 때 람다식에서 이름을 지정해주지 않아도 it으로 사용할 수 있다.data class ProjectDTO( // 생략 val details: List<ProjectDetailDTO>, val skills: List<SkillDTO>? ) { constructor(project: Project) : this( // 생략 details = project.details.filter { it.isActive }.map { ProjectDetailDTO(it) }, skills = project.skills.map { it.skill }.filter { it.isActive }.map { SkillDTO(it) } ) } Service, Repository도메인에서 관리해야할 Repository가 많아짐에 따라 한 번에 의존관계를 주입받을 수 있는 Repository를 생성했다.각각 필요한 부분만 주입받게 되면 후에 관리하기가 힘들어 지는 상황을 예방할 수 있다.추가적으로 각 리포지토리의 기능들을 래핑하여 캡슐화 하는 형태의 코드를 작성하여 Service 단에서 사용하기 유용하도록 코드를 작성하였다.@Repository class PresentationRepository( // Presentation 에서 필요한 리포지토리들을 한 번에 주입받아서 활용하기 위함. // A, B, C 형태로 따로따로 주입받으면 후에 관리하기가 힘들기 때문 private val achievementRepository: AchievementRepository, // 생략 ) { fun getActiveAchievements(): List<Achievement> { return achievementRepository.findAllByIsActive(true) } // 생략 } Test - Mockito8~10일차에는 Service에 구현한 기능들에 대해서 테스트 코드를 작성하게 되었다.아래 내용은 강의에서 작성한 코드의 일부분이다.@ExtendWith(MockitoExtension::class) // Mockito Extension 추가 class PresentationServiceTest { @InjectMocks // Mock을 주입받을 대상, 테스트를 할 대상 lateinit var presentationService: PresentationService // Mock을 만든 이후 초기화를 진행하기 위해 lateinit @Mock lateinit var presentationRepository: PresentationRepository } @ExtendWith테스트 확장을 지원하는 어노테이션으로 Mock 객체의 생성 및 초기화를 자동으로 처리하게 해주는 역할을 해준다.@InjectMocksMockito에서 테스트 대상이 되는 클래스에 인스턴스를 생성하고, @Mock 이 사용된 필드를 찾아 객체를 자동으로 주입하기 위해 사용된다.위에서는 테스트할 대상인 PresentationService의 인스턴스를 생성하며, PresentationRepository 에 Mock 객체를 주입하기 위한 용도로 사용된다.@MockMockito에서 Mock 객체를 생성할 때 사용한다.Mock 객체는 모의 객체로 실제 객체의 동작을 흉내낼 수 있다.아래는 강의에서 사용된 Mock 객체가 실제 객체의 동작을 흉내낸 부분이다.Mockito.`when`(presentationRepository.getActiveIntroductions()) .thenReturn(activeIntroductions) when에서 정의한 내용을 시도했을 때, activeIntroductions 의 내용을 반환 하도록 Mocking을 한 것이다.presentationRepository가 실제 데이터베이스와 상호작용이 발생하지 않도록 동작을 했다고 속이는 것이며, 이러한 동작을 통해 테스트를 독립적이고 일관되게 유지할 수 있다. 서브 미션2주차의 서브 미션에는 API 설계가 예정되어 있었다.이를 위해 RESTful 하도록 API를 설계하도록 노력해봤고 결과물은 아래 리포지토리에서 볼 수 있다.https://github.com/ppusda/MML 총 회고이번 2주차는 쉬는 날 겹쳐있어 진도가 많이 나가질 못했다.하지만 의외로 많은 걸 배울 수 있었다.단순히 Kotlin으로 Spring을 접근하는 방법 뿐만 아니라 약간의 복습과 거들어 N+1 문제, Test code와 같이 아직 부족한 부분에 대해서 좀 더 학습할 수 있었다.특히 Test code에 대한 부분은 조금 공부해보니 흥미가 더 생겨서 향후에 Mockito 동작 과정에 대해서 자세하게 뜯어볼 의향도 생겼다. 앞으로도 부족한 부분을 채워나가면서 학습해나가야겠다.모두 화이팅! (o゚v゚)ノ 참고https://jojoldu.tistory.com/457

백엔드워밍업클럽백엔드2기Kotlin

ppusda

인프런 워밍업 클럽 2기 - 백엔드 프로젝트(Kotlin, Spring) / 1주차 발자국

⭐ 1주 동안 배운 내용을 정리하고 회고하는 시간을 가져보자. 복습한다고 생각하고 간단하게 요약하며 정리해보자. ╰(°▽°)╯1일차 - 웹 기본 개념 이해하기웹 서비스의 구성 요소클라이언트 [요청하는 주체] ↔ 서버 [응답하는 주체] ↔ 데이터베이스 [데이터 집합]클라이언트는 요청하는 주체이며, 사용자 혹은 고객이라고도 표현한다.서버는 응답하는 주체이며, 요청받은 결과를 클라이언트 측으로 응답한다.데이터베이스는 데이터의 집합이며 이를 관리하는 DBMS를 일반적으로 DB라고 부른다. 브라우저에 주소를 입력하면 벌어지는 일클라이언트가 브라우저에 https://www.google.com 을 입력하면 어떻게 될까?클라이언트가 보낸 주소를 DNS 서버에서 IP로 변환하여 알려준다.클라이언트는 해당 IP 주소로 서버에 요청을 하며, 서버는 요청 데이터를 처리한다.처리 완료된 응답 데이터를 다시 클라이언트 측에 전달한다. DNS? (Domain Name System)DNS는 사용자가 흔히 보는 www.google.com과 같은 도메인 이름을 IP로 변환하는 시스템이다.DNS 서버는 이러한 변환 역할을 대신 수행해주는 서버이며, KT, SKT, LG, Google 등이 이러한 서버를 제공한다. 웹 프레임워크Framework, 프레임워크?프레임워크는 공통적으로 요구되는 기능들을 보다 편리하게 만들 수 있도록 해주는 뼈대, 구조이다.제어의 주도권을 프레임워크가 가지고 있으며, 틀 안에서 주어진 것을 활용해야한다. Library, 라이브러리?라이브러리는 활용 가능한 도구들의 집합으로 제어의 주도권을 사용자가 가지고 있으며 정해진 틀 없이 사용자가 원하는 것을 만들 수 있다. Spring FrameworkMVC 패턴 (Model-View-Controller)소프트웨어 아키텍쳐 디자인 패턴으로 Model, View, Controller로 각 역할을 분담하여 결합도를 낮추고 유지보수를 용이하게 할 수 있다.Model - 데이터 처리View - 보여지는 화면 처리Controller - 클라이언트 요청 처리 레이어드 아키텍처 (Controller-Service-Repository)가장 대중적인 소프트웨어 아키텍처로 Controller, Service, Repository로 구분하여 사용한다.Controller - 클라이언트 요청 처리Service - 비즈니스 로직 (핵심 로직) 처리Repository - 데이터베이스 접근 처리 Spring Bean과 의존성 주입Spring Bean은 스프링에서 관리되는 객체를 뜻한다.이는 스프링 컨테이너가 직접 관리하기에 제어의 역전(Inversion of Control; IOC)라고 부르며 스프링에서 의존성을 주입해주어 객체를 사용할 수 있다.생성자 주입, 수정자 주입, 필드 주입의 방법이 있지만, 런타임 시 수정자를 통해 의존성이 바뀌거나 의존하는 Bean을 누락했을 시 컴파일 단에서 오류를 잡아낼 수 있기 때문에 생성자 주입을 추천한다.생성자 주입@Service class PresentationService (private val presentationRepository: PresentationRepository) { ... } 수정자 주입private lateinit var presentationRepository: PresentationRepository @Autowired fun setPresentationRepository(presentationRepository: PresentationRepository) { this.presentationRepository = presentationRepository } 필드 주입@Autowired private lateinit var presentationRepository: PresentationRepository HTTP와 REST APIHTTP (Hyper Text Transfer Protocol) 는 서버와 클라이언트 간 어떻게 데이터를 교환할지를 정해놓은 통신 규약이다.HTTP 요청 메서드GET - 읽기 작업을 처리할 때 사용됨POST - 쓰기 작업(생성)을 처리할 때 사용됨PUT (전체 수정) / PATCH (부분 수정) - 쓰기 작업(업데이트)를 처리할 때 사용 됨DELETE - 삭제 작업을 처리할 때 사용 됨HTTP 상태 코드2xx : 정상 처리3xx : 리다이렉션 - 페이지 이동이 이루어져야 함4xx : Bad Request - 클라이언트 측 요청 오류5xx : Internal Server Error - 서버 측 오류REST API클라이언트와 서버 간 인터넷을 통해 정보를 안전하게 교환하기 위해 사용하는 규칙이다.RESTful 하게 API를 작성하려면 URL만으로 어떤 자원에 대해 어떻게 처리할 건지 파악할 수 있어야 한다.POST /members ⇒ O, Post는 생성을 처리할 때 사용 / member 생성하기 위한 요청임을 알 수 있다.POST /createNewMember ⇒ X, RESTful 하지 않음 2일차 - 데이터베이스 기본 개념데이터베이스1일차에 소개했던 것 처럼 데이터의 집합이다.이를 관리하는 툴을 DBMS (Database Management System)이라고 부른다. RDBMS, 관계형 데이터베이스행과 열로 이루어진 표의 형태로 저장되는 데이터베이스하나의 행은 데이터, 열은 각 데이터의 특징이라고 할 수 있으며 이것들이 모여 하나의 테이블(표)이 된다.각 테이블을 조인하여 정보 간의 관계나 링크를 설정할 수 있는 기능이 있으며, 이를 통해 여러 데이터 간의 관계를 설정할 수 있기에 관계형 데이터베이스라고 부른다.⇒ Oracle, MySQL, PostgreSQL 등이 이에 해당된다. NoSQL, 비관계형 데이터베이스관계형 데이터베이스를 제외한 모든 종류의 데이터베이스를 비관계형 데이터베이스로 분류한다.⇒ MongoDB, Redis 등이 이에 해당된다. JPAJPA (Java Persistence API)는 자바 진영 ORM 기술의 표준이다.ORM (Object Relational Mapping)은 객체 관계를 매핑해주는 기술로 객체지향 프로그래밍의 객체와 데이터베이스를 매핑해주는 역할을 한다.장점특정 DB에 대한 의존성을 줄일 수 있음쿼리를 직접 작성하지 않아도 됨데이터에 객체지향적인 관점에서 접근이 가능함단점ORM 만으로는 한계가 있기에, 복잡한 쿼리의 경우 네이티브 쿼리를 작성해야 함JPA에 대한 충분한 학습이 이루어진 후 사용해야 함. 영속성 컨텍스트JPA에서 Entity를 관리하는 저장공간이다.애플리케이션과 데이터베이스 사이에서 Entity를 보관하는 가상 데이터베이스 역할을 한다.아래에선 이 영속성 컨텍스트의 3가지의 특징을 소개하려고 한다.1차 캐시영속성 컨텍스트 내부의 캐시를 1차 캐시라고 부른다.조회한 결과를 캐시 공간에서 먼저 찾아보고 쿼리를 수행 할지 결정한다.더티 체킹영속성 컨텍스트 내에서 Entity의 변화가 감지됬을 경우 이를 데이터베이스에 자동으로 적용하는 기능을 더티 체킹 또는 변경 감지라고 부른다.최초로 데이터를 조회할 때의 스냅샷을 보관해두고 이를 트랜잭션 종료 시점과 비교하여 변경된 내용을 적용하는 것이다.쓰기 지연쓰기 작업을 즉시 수행하지 않고, 영속성 컨텍스트 내에 모아두었다가 트랜잭션이 종료될 때 한 번에 수행한다. 트랜잭션트랜잭션은 데이터베이스에 적용할 여러 작업을 하나로 묶어주는 논리적 단위이다.커밋, Commit : 트랜잭션으로 묶인 모든 작업을 데이터베이스에 영구히 반영하는 작업롤백, Rollback : 트랜잭션으로 묶인 모든 작업을 원상복구 하는 작업 3일차 ~ 5일차 (실습)이번 실습 내용에서는 기존에 알고 있던 내용은 제외하고 실습을 진행하면서 알게 된 Kotlin 문법에 대해서 조금 정리해볼까 한다.@Entity class Achievement( // 여기가 생성자 title: String, description: String, achievedDate: LocalDate?, // null 허용 (=일 수도 있다.) / 반대로 !!는 null이 아니다를 표현함 host: String, isActive: Boolean ) : BaseEntity() { // BaseEntity 상속 // 생략 var isActive: Boolean = isActive } 위는 실습 중에 작성한 Entity의 일부이다.Java와는 다르게 Class명 옆에서 생성자를 정의할 수 있고, 변수명: 타입 과 같은 구조를 가지고 있다.타 클래스 상속을 위해서 : BaseEntity()와 같이 사용한 부분을 볼 수 있다.변수를 선언할 때는 var 또는 val을 쓴다.var ⇒ 읽기/쓰기가 가능한 일반 변수val ⇒ 읽기만 가능한 final 변수 nullable을 표현할 수 있다.? ⇒ null 일 수도 있다fun getEndYearMonth(): String { if (endYear == null || endMonth == null) { return "Present" } return "${endYear}.${endMonth}" } 이어서 함수 부분이다.Java와는 다르게 메서드를 정의할 때 fun을 통해 선언하며, String을 반환할 때 프론트에서 사용하던 것 처럼 ${} 사이에 변수를 넣어 처리를 할 수 있었다. 번외 - 서브 미션 과제워밍업 클럽 2기 - 백엔드(Kotlin, Spring) 과정에서는 서브 미션을 수행하도록 과제가 주어진다.현재 기획한 내용은 음악 플레이리스트를 만들 수 있는 미니 프로젝트를 기획하고 테이블 설계까지 완료 하였다.https://github.com/ppusda/MML 단순하게 요즘 듣는 음악 리스트를 공유하기 위한 프로젝트로 기획하게 되었으며, 설계한 테이블은 아래와 같다.User 별로 플레이리스트를 생성하여 음악 목록을 만들 수 있게 해두었고, 목록을 관리하기 위해 각 테이블을 분리하였다.미션 내용이 단순히 CRUD 까지 밖에 없어서 임의로 데이터를 추가하거나, 향후 시간이 난다면 실제 데이터를 불러와서 이용할 수 있게 해볼까 한다. 총 회고오랜만에 기초부터 복습하는 느낌이 들어 면접 준비한다는 느낌으로 중요한 내용만 추려서 정리해보았다.아직 1주차라서 많은 내용을 다뤄보지는 못한 것 같고, 앞으로 실습 면에서 Kotlin 문법을 기억 속에서 되찾으며 여러모로 부족한 부분을 찾아가며 배워보면서 즐겨 볼 생각이다.  모두 화이팅! (o゚v゚)ノ

백엔드워밍업클럽백엔드2기Kotlin

서상연

인프런 워밍업 클럽스터디 2기 FE - 1주차 발자국

강의변수선언방법: var, let, constvar: 중복선언 및 재할당이 가능하다. 예전부터 사용함let: 중복선언은 할수 없고 재할당만 가능하다. 주로 일반 변수 선언 시 사용한다.const: 중복선언 및 재할당을 할 수 없다. 주로 상수 선언 시 사용한다. 유효범위(scope)var: 함수레벨(function-level scope)let, const: 블럭레벨(block-level scope)let, const는 블록안에서만 접근할 수 있음 hoistingvar: 선언되기 전 변수를 먼저 호출하면 undefined로 초기화 되어 표시되고 함수의 경우에는 위로 끌어올려 정상적으로 실행됨let, const: 값이 선언되기 전 호출하면 초기화 오류를 발생, 함수도 실행되지 않음. 초기화 전까지 TDZ(Temporal Dead Zone)이라하여 일시적인 비활성 상태임타입원시타입: Boolean, String, Number, null, undefined, Symbol => Call Stack에 값이 저장참조타입: Function, Object, Array, Class => Heap메모리에 저장자바스크립트 동적 타입이다. thismethod: 해당 객체를 가리킨다.함수: window 객체를 가리킨다.constructor 함수: 빈 객체를 가리킨다.Event LoopClosure다른 함수 내부에 정의된 함수를 리턴하여 외부 함수가 실행된 후에도 외부 함수 내 변수나 함수에 액세스 할 수 있다.구조분해할당배열이나 객체의 속성을 해체하여 개별 변수에 담을 수 있게 하는 Javascript 표현식전개연산자 특정 객체나 배열의 값을 다른 객체, 배열로 복제하거나 옮길 때 사용.

프론트엔드FE인프런워밍업클럽2기

마블

워밍업 클럽 2기 BE 1주차 발자국

1주차 배운 내용 요약클린코드의 중요성 알아가기가독성 -> 글이 잘 읽히는 것이 중요하다. 나 뿐만 아닌 다름 사람이 코드를 읽었을 때 얼마나 잘 이해할 수 있을까?회사에서 일을 할 때 코드를 읽는 것이 대부분유지보수성 -> 추상이란? 추상에 대해서 생각해보기추상이란 무엇일까?구체화 된 어떤 것들을 중에서 중요한 것만 추출하여 파악하는 것.어떤 일면만을 추상화하고, 다른 측면은 버린다.컴퓨터 측면에서 추상화8 byte -> 1bit, 4bit -> int 자료형추상화 레벨 - 고수준 언어, 저수준 언어고수준 언어는 레벨이 높다저수준은 언어는 레벨이 낮다.적절한 추상화는 복잡한 데이터와 로직을 단순화 한다.잘못된 추상화는 Side-effect를 야기시킨다. 그러기 때문에 추상화를 잘 알고 사용해야 한다.이름을 잘 지어야 한다.이름짓기단수 복수 구분하기 이름 줄이지 않기은어/방언 사용하지 않기좋은 코드를 보고 습득하기메서드와 추상화메서드 내부는 구체화된 내용메서드의 시그니쳐(반환타입, 메서드명, 파라미터)는 추상화된 레벨메서드 내부의 추상화 레벨을 잘 확인한다. -> 더 구체화 된 레벨이 있을 경우 메서드로 추출하여 레벨을 맞춘다.메서드명, 반환 값, 파라미터를 잘 확인한다.구체화 된 내용들을 적절하게 담기 이름void 대신 충분히 반환할 만한 값이 있는지 고민하기파라미터 타임, 개수, 순서를 통해 의미를 전달할 수 있다.매직 넘버, 매직 스트링의미를 갖고 있으나, 상수로 추출되지 않는 숫자와 문자열 등 -> 상수 추출로 이름을 짓고 의미를 부여한다가독성, 유지보수성 증가논리 사고의 흐름Early Returnreturn 문을 사용하여 else 사용을 줄인다. 사고의 depth 줄이기1. 중첩 if, for중첩된 반복문 또는 조건문을 없앨 수 있도록 구체화된 내용을 메서드로 추출하는 등 추상화하여 중첩을 줄인다.무조건 1depth로 만드는 게 아닌, 추상화를 통한 사고 과정의 depth임을 알아야 한다.2. 사용할 변수는 가깝게 선언변수는 사용하는 곳과 가깝지 않으면 잊어버린다.3. 공백 라인도 의미를 가진다.4. 부정어 줄이기부정어는 생각을 한번 더 거치게 한다.반대를 뜻하는 이름으로 바꾸기메서드 이름에 부정어 넣기5. 해피케이스와 예외 처리예외 발생 가능성 낮추기검증이 필요한 부분은 외부 데이터가 대부분이다사용자 입력, 객체 생성자, 외부 서버의 요청 등의도한 예외와 의도하지 않은 예외를 구분한다.사용자 예외와, 개발자 확인 예외NullPointerException 방지return null 사용 자제Optional 사용 고민Optional은 비싼 객체임으로 사용할 때 고민해야 한다.파라미터로 사용하는 객체는 아니다.Optional로 받은 반환 값은 빨리 해소한다. Optional을 해소하는 방법분기문을 만드는 isPresent()-get() 대신 풍부한 API 사용orElseGet, orelseThrow, ifPresent, ifPresentOrElseorElse(), orElseGet(), orElseThrow()의 차이 숙지orElse() : 항상 실행, 확정된 값일 때 사용orElseGet() : null인 겨우 실행, 값을 제공하는 동작(supplier) 정의orElseThrow() : null인 경우 에러 객체 throw 객체 지향객체 설계비공개 필드 (데이터), 비공개 로직(코드)공개 메서드 선언부를 통해 외부 세계와 소통 → 각 메서드의 기능은 객체의 책임을 드러내는 창구객체의 책임이 나뉨에 따라 객체 간 협력이 발생 주의점1개의 관심사로 명확하게 책임이 정의되었는지 확인 생성자, 정적 팩토리 메서드에서 유효성 검증이 가능하다. setter 사용 자제 getter 사용 자제 필드의 수는 적을수록 좋다.도메인 지식은 만드는 것이 아니라 발견하는 것이다.  상속과 조합상속보다 조합을 사용하자상속은 부모와 자식의 결합도를 높인다.상속을 통한 코드의 중복 제거가 주는 이점보다, 중복이 생기더라도 유연한 구조 설계가 주는 이점이 더 크다.Value Object도메인의 어떤 개념을 추상화하여 표현한 값 객체값으로취급하기 위해서, 불변성, 동등성, 유효성 검증 등을 보장해야 한다. 불변성 : final 필드, setter 금지동등성 : 서로 다른 인스턴스여도 내부의 값이 같으면 같은 값 객체로 취급한다. equals() & hashCode() 재정의가 필요유효성 검증 : 객체가 생성되는 시점에 값에 대한 유효성을 보장일급 컬렉션 - 일급 함수다른 요소에게 사용 가능한 모든 연산을 지원하는 요소변수, 파라미터, 함수 리턴 값으로 사용컬렉션만 유일하게 필드로 갖는 객체  getter 생성시 새로운 컬렉션으로 반환해야 한다.EnumEnum은 상수의 집합이며, 상수와 관련된 로직을 담을 수 있는 공간이다.특정 도메인 개념에 대해 그 종류와 기능을 명시적으로 표현해줄 수 있다.다형성 활용하기if문 줄이기어떤 조건을 만족하면, 그 조건에 해당하는 행위를 수행한다.변하는 것 → 조건, 행위변하지 않는 것 → 조건을 만족하는 가?, 행위를 수행한다.DAY2 미션 - 추상과 구체아기에게 우유를 따르라고 했을 때 아기는 제대로 우유를 따르지 못한다는 그런 내용이 생각이 떠올랐던 미션이었다. 컴퓨터적 사고에 대한 내용인데 아기는 우유를 따르라고 했을 때컵을 가져와라우유를 가져와라우유팩 뚜껑을 열어라우유팩을 들어라우유를 컵에 따라라이런 구체화 된 내용을 말하지 않으면 할 수 없다는 내용이다. 이렇듯 컴퓨터적 사고는 모듈을 개발할 때 모든 논리 과정을 생각하지 않으면 만들 수 없다. 그런데 우리의 뇌는 이런 모든 구체화 된 내용을 기억할 수 없기 때문에 추상화하지 않으면 기억하기 힘들다.일상 생활에서 자연스럽게 사용하고 있었지만, 이것을 다시 개발에 적용하는 것이 쉽진 않은 것 같다. 미션은 최근에 일어났던 일로 하긴 했지만 일을 할 때 코드가 하나도 추상화되어있지 않아 읽기 힘들고 기억하기가 힘들었는데 이번에 강의를 들으면서 배웠던 내용으로 추상화하려고 노력하니 많이 발전된 모습을 보일 수 있어서 좋았다. DAY4 미션 - SOLID 정의자바와 스프링을 하면서 너무 많이 들었던 내용이었다. 또한 면접을 볼 때도 엄청 외우고 다녔었는데 다시 보니 리마인드 되고 미션을 하면서 다시 내가 재 정의를 하려니 쉽지 않았지만 새롭게 배울 수 있었다. 학습은 타인에게 설명할 수 있는 단계 까지이다. 나도 이렇게 항상 생각하고 학습해왔기 때문에 이번에도 내가 타인에게 설명하는 것을 생각하며 SOLID를 다시 정의했다.1주차 회고최근에 책을 읽는 독서법을 바꾸려고 노력하고 있다. 전에는 빨리 읽으려고 노력했던 반면 요새는 책 내용 중 인상 깊었던 것들은 실천하려고 노력한다. 그렇지 않으면 읽었던 내용들을 다 잊어버린다. 그 좋은 내용들을 잊기 싫었다. 강의 내용도 그랬다. 사실 읽었던 책에 나온 내용들이긴 하지만 책은 이해하기 쉽지 않았다. 그런데 강의는 그것을 잘 이해할 수 있도록 강사님이 잘 설명해 주시기도 했고, 직접 해볼 수 있는 실습이 있어서 강의 내용을 이해하기 더 수월했다. 이론도 중요하지만 이론을 적용할 실습이 동반되지 않으면 말짱 도루묵이다. 그런면에서 얻을 수 있는 것이 많아서 좋았다.그리고 책에서 배웠던 내용을 리마인드 한다고 생각하면서 이번 1주차를 보냈다. 강의 내용도 좋고 중간 중간 미션과 회고를 쓰게 하는 것도 좋았다. 시간이 지남에 따라 해이해지는 정신을 잘 잡아주는 커리큘럼 구성이 좋았다.마지막으로 하나 반성을 하자면, 시간 투자를 많이 못했다. 강의를 듣고 공부하는 데에 시간을 많이 못쓰고.. 강의가 밀리기도 했다. 다행이 휴일이 많아서 따라왔지만, 다음 주부터는 이렇게 하다간 힘들 거라는 생각이 들었다. 시간을 많이 투자하고 관련된 책들도 다시 읽고, 미션도 열심히 수행해야겠다고 반성했다.  

백엔드발자국워밍업클럽2기1주차

HYERIN JO

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

Liked, 스터디에 참여하며 좋았던 점은?JavaScript에 대해서 복습하는 시간을 가질 수 있었다.미션을 수행하면서 JavaScript 라이브러리, 프레임워크를 사용하지 않고 tailwindCSS를 적용하는 법을 배울 수 있어서 좋았다. 배운걸 실제로 적용해봐야지 머릿 속에 각인되고 더 잘 이해가 되는 거 같다.Learned, 스터디에서 배운 점은?강의에서 배운 점?호이스팅JavaScript에서 호이스팅은 코드가 실행되기 전에 변수 및 함수 선언(이름)이 로컬 범위(유효 범위)의 맨 위로 들어올려지거나 끌어올려지는 경우를 설명합니다.DOM, Document Object Model돔은 메모리에 웹 페이지 문서 구조를 트리 구조로 표현해서 웹 브라우저가 HTML 페이지를 인식하게 해줍니다.웹 페이지를 이루는 요소들을 자바스크립트가 이용할 수 있게끔 브라우저가 트리구조로 만든 객체 모델을 의미합니다.CRP, Critical Rendering PathDOM tree 생성: 렌더 엔진이 문서를 읽어들여서 그것들을 파싱하고 어떤 내용을 페이지에 렌더링할지 경정Render tree 생성: 브라우저가 DOM과 CSSOM을 결합하는 곳이며, 이 프로세스는 화면에 보이는 모든 콘텐츠와 스타일 정보를 모두 포함하는 최종 렌더링 트리를 출력함. 화면에 표시되는 모든 노드의 콘텐츠 및 스타일 정보를 포함함.Layout(reflow): 브라우저가 페이지에 표시되는 각 요소의 크기와 위치를 계산하는 단계Paint: 실제 화면에 그리기Event Bubbling이벤트 버블링이란 깊게 중첩된 이벤트가 발생했을 때, 이벤트가 위로 (bubble up) 전달 되는 것을 의미합니다.Event Capturing이벤트 캡처링이란 이벤트 버블링과 다르게 제일 상단에 있는 요소에서 아래로 이벤트가 내려오는 것을 말합니다.Event Delegation이벤트 위임은 하위 요소의 이벤트를 상위 요소에 위임하는 것입니다.this 키워드메소드에서 this를 사용할 경우? 해당 객체를 가리킨다.const artist = { name: 'Minnie', sing() { console.log('sing this', this); // {name: 'Minnie', sing: f sing()} } } 함수에서 this를 사용할 경우? window 객체를 가리킨다.function eatHamburger() { console.log(this); // window 객체 } constructor 함수에서 this 사용할 경우? 빈 객체를 가리킨다.function Artist(name) { this.name = name; console.log(this); // {} } const minnie = new Artist('Minnie'); 콜백함수에서 this를 사용할 경우? (콜백함수가 일반함수일 경우) window 객체를 가리킨다.const artist = { name: 'Minnie', nums: [1, 2, 3], print() { this.nums.forEach(function(num){ console.log(`name: ${this.name}, num: ${num}`); // name: undefined, num: 1 }); } }; 화살표 함수에서 this를 사용할 경우? 상위 스코프의 this를 가리킨다. Lexical this라고 부른다.const artist = { name: 'Minnie', nums: [1, 2, 3], print() { this.nums.forEach((num) => { console.log(this); // {name: 'Minnie', nums: Array(3)} }); } }; Event Loop이벤트 루프는 Call Stack(호출 스택)과 Callback Queue(콜백 큐)를 계속해서 확인하며, Call Stack이 비어 있을 때 콜백 큐에 대기 중인 콜백 함수들을 FIFO(First In, First Out) 방식으로 Call Stack에 넣어 비동기 코드를 실행합니다. 이는 비동기 함수들이 완료된 후에도 Call Stack에 있는 동기 코드가 모두 처리될 때까지 대기하다가 실행되는 구조를 따릅니다.클로저다른 함수 내부에 정의된 함수가 있는 경우 외부 함수가 실행을 완료하고 해당 변수가 해당 함수 외부에서 더 이상 액세스할 수 없는 경우에도 해당 내부 함수는 외부 함수의 변수 및 범위에 액세스할 수 있습니다.미션을 하면서 배운 점?미션 1. 음식 메뉴 앱github repository: https://github.com/hyer0705/inflearn-warmingup-club-2/tree/main/javascript/food-menu-app메뉴 데이터는 아래와 같은 구조로 정의합니다:{ category: 'breakfast' | 'lunch' | 'shakes' | 'dinner', food: string, cost: number, desc: string, img: string } 각 메뉴는 menus 변수에 배열 형태로 저장됩니다.사용자가 음식 카테고리를 선택하면, Array.prototype.filter() 메서드를 사용해 menus에서 선택한 카테고리에 맞는 음식들을 필터링합니다.필터링된 음식 데이터를 기반으로, document.createElement(), element.innerHTML, element.innerText 등의 DOM API를 사용해 화면에 표시합니다.미션 2. 가위 바위 보 앱github repository: https://github.com/hyer0705/inflearn-warmingup-club-2/tree/main/javascript/rock-paper-scissors-appplayData 변수에 총 플레이 횟수, 플레이어 승리 횟수, 컴퓨터 승리 횟수를 저장합니다.const playData = { totalPlayCnt: 10, playerWin: 0, computerWin: 0 } 사용자가 가위, 바위, 보 버튼을 클릭하면, 컴퓨터는 Math.random() 메서드를 사용해 랜덤으로 가위, 바위, 보 중 하나를 선택합니다.버튼 클릭 시 플레이 횟수가 줄어들며, 결과는 playData에 저장됩니다.버튼 클릭시 해당 라운드의 결과를 DOM 조작 API를 사용하여 화면에 표현해줍니다.10회 라운드가 끝나면 게임이 종료되고, 최종 결과가 화면에 표시됩니다."다시 시작" 버튼을 클릭하면 playData가 초기화되어 게임을 다시 시작할 수 있습니다.Lacked, 스터디에 참여하면서 부족했던 점은?개인적인 사정으로 1주차 진도표의 절반만 진행했다.Longed For, 앞으로 개선하고 싶은 점은?다음주에는 커리큘럼에 따라갈 수 있도록 열심히 강의를 듣고 미션을 수행해야지! 그러기 위해 빨간날과 주말을 적극적으로 활용해야 겠다.참고자료강의 출처: 따라하며 배우는 자바스크립트 A-Z, John AhnEvent Bubbling Image: https://www.freecodecamp.org/news/event-bubbling-in-javascript/?source=post_page-----4209bf40575c--------------------------------Event Capturing Image: https://www.javascripttutorial.net/javascript-dom/javascript-events/Event Delegation Image: https://dmitripavlutin.com/javascript-event-delEvent Loop Image: https://medium.com/@burak.bburuk/what-is-the-event-loop-in-javascript-and-why-is-it-essential-to-understand-b11af520a28b

프론트엔드워밍업클럽발자국1주차인프런워밍업클럽워밍업클럽스터디2기프론트엔드

길잃은코끼리

[워밍업 클럽 스터디 2기 - 클린 코드, 테스트코드] 1주차 발자국

강의 수강 강의 내용 요약1주차는 섹션1~섹션5 까지 강의를 수강하였다.섹션2(추상)구체적인 실체에서 중요한 정보는 가려내어 남기고, 덜 중요한 정보는 생략하여 버린다.어느 정도냐 에 따라 추상화 레벨이 생긴다적절한 추상화는 해당 도메인의 문맥 안에서, 정말 중요한 핵심 개념만 남겨서 표현하는 것섹션3(논리, 사고의 흐름)인지적 경제성 : 최소한의 정보로 최대 효율을 내보자 => 낮은 추상화레벨 -> 잘 읽히도록early return : else 사용을 지양하여 일찍 return 할 수 있다면 return 하자중첩 반복문, 조건문을 추상화를 통해 사고의 depth를 줄이자공백 라인을 잘 활용하여 의미 단위로 나누자부정어구를 쓰지 않아도 되는 상황인지 체크하고 부정의 의미를 담은 다른 단어가 있는지, 부정어구로 메서드 명을 구성하자사람은 happy case의 물두하는 경향이 있다 => 예외처리를 꼼꼼하게 하는 개발자가 되자항상 NullPointExecption을 방지하는 방향으로 경각심을 가지자 섹션4(객체 지향 패러다임)객체는 데이터와 코드의 조합이다. 공통된 관심사들을 분리시켜 객체로 만들어 유지 보수성을 올린다객체의 책임이 나뉨에 따라 객체간 협력이 발생한다SRP(단일 책임 원칙) : 하나의 클래스는 단 한가지의 책임만을 가져야 한다OCP(개방 패쇄 원칙) : 기존 코드의 변경없이 시스템의 기능을 확장할 수 있어야 한다.LSP(리스코프 치환 원칙) : 상속 구조에서 부모 클래스의 인스턴스를 자식 클래스의 인스턴스로 치환 할 수 있어야 한다.ISP(인터페이스 분리 원칙) : 인터페이스를 잘게 쪼개서 사용하지 않는 기능이 없도록 구현하자DIP(의존성 역전 원칙) : 의존성의 역방향(고수준, 저수준 모듈이 모두 추상화에 의존하는것) 인터페이스만 알고 있는 상태로 구현하자섹션5(객체 지향 적용하기)상속보단 조합을 사용하자(인터페이스를 활용)도메인의 어떤 개념을 추상화하여 표현한 값 객체(VO)를 사용하여 의미를 부여하고 추상화한다일급 컬렉션 VO와 비슷하게 컬렉션을 포장하면서, 컬렉션만을 유일하게 필드로 가지는 객체를 사용하여 의미를 부여할수 있음상수들의 집합인 enum은 상수와 관련된 로직을 담을 수 있는 공간을 제공해준다.변하는 것과 변하지 않는 것을 분리하고 다형성을 구현한다  일주일 간 회고일단 인프런 워밍업 스터디를 지원한 이유는 나는 기존에 이 두 강의를 듣고 있었다. 하지만 그냥 강의를 듣고 맹목적으로 코드를 이해하려하지 않고 따라치기만 했던 것 같았고 그 결과 내 머리속에 내용이 없었다. 그래서 이번 기회에 확실히 다져보자 라는 생각으로 지원을 하였다. 미션을 수행하고 공부를 하다보니 처음 수강을 했을 때는 필요성에 대해 잘 이해하지 못했으나 비로소 왜 필요한지 이곳에는 이렇게 사용하는 것이 맞을지 고민을 하게 되었고 조금은 발전 한 것 같아 좋았다.하지만 아쉬운 점도 있었다. 시간을 규모있게 사용하지 못한 것 같다. 강의가 전반적으로 길고 너무 많은 정보가 쏟아지는 지라 긴 시간동안 집중을 할 수 없었고, 그래서 한 번 보고 나중에 보고를 반복 하다 보니 생각 보다 많은 시간이 걸렸다. 이제 부터 학교 시험기간에 돌입을 한다. 점점 힘들어질것이다. 포기 하지 않고 시간을 규모있게 써서 완주 하고 싶다 미션미션 해결 과정(인프런 워밍업 스터디 클럽2기 백엔드(클린코드, 테스트 코드)🍀 Day4 미션 | Sung Jae's Blog (byuntil.github.io)위 블로그에 작성을 해놓았다. 미션 해결에 대한 회고정말 간단한 미션이었고, 그렇게 난이도 자체도 높지 않은 미션이었다. 하지만 고민해본 부분들은 상당히 많았다. 정말 이런 간단한 문제조차도 이렇게 고민 해야 하는 부분이 많은데 나중에 실무에서나 아니면 교육기관이나 프로젝트를 할 때 내가 정말 잘 해낼 수 있을지 덜컥 겁부터 난다.겁이 난다고 이 상태로 있을 것이 아니라 꾸준히 노력을 한다면 충분히 해 내리라는 자신이 있다.

백엔드인프런워밍업클럽2기클린코드

채널톡 아이콘