게시글
질문&답변
잡 이름이 겹치지 않는데 왜 이럴까요...?
아..!! 제가 Job 이름에서 오타를 내고 있어서 스프링이 찾질 못하고 있었던 것이었네요 해결했습니다!.
- 0
- 2
- 395
고민있어요
브금이 진짜 신의 한 수네요.
- 1
- 1
- 216
고민있어요
질문은 아니구요 아재 개그 감사합니다.
- 5
- 1
- 270
질문&답변
h2 실행관련 질문있습니다.
굳이 아이텀이 아니어도 기본 터미널에서 하셔도됩니다.
- 0
- 2
- 358
질문&답변
vue cli 설치 에러
질문 글에 담진 못했지만 제가 여태까지 수강했던 코딩 강의 중에 가장 몰입도가 높은 강의를 제공해주셔서 감사합니다! 열심히 공부하겠습니다. 이번 주에 기초 강의 마치고 복습 한번 하고 이번 달안에 웹팩 강의까지 달려보겠습니다~!
- 1
- 3
- 322
질문&답변
아나콘다가 아닌 구글 코랩으로 진행해도 되는 지 여쭙고 싶습니다.
오히려 답변 읽다보니 제가 너무 익숙한 도구만 쓰려고 하는 것 같은 느낌도 들어서 반성하게 되었습니다 ㅠㅠ ㅋㅋㅋ 마지막에 말씀 주신 것처럼 둘다 해보겠습니다! 중간고사 기간이 끝나는대로 진행하려고 합니다! 감사합니다!
- 0
- 2
- 2.3K
블로그
전체 152024. 10. 27.
0
[워밍업 클럽 BE 2기 - 클린코드, 테스트코드] 4주차 발자국
4주차 발자국 드디어 이번 워밍업 클럽의 마지막 날입니다. 0기와 2기에 참여했었고 서로 다른 주제였는데 다음 워밍업 클럽 주제가 또 기다려지네요. 개인적으로는 코틀린을 기다리고 있습니다. 이번 주차에 포함된 진도는 아래와 같습니다.Presentation LayerMock을 마주하는 자세더 나은 테스트를 작성하기 위한 구체적 조언학습 테스트 | RestDocs가장 의미있다고 여겨졌고 개인적으로 많이 배운 주제는 Day 17의 더 나은 테스트를 작성하기 위한 구체적 조언 파트였는데요. 제가 개인적으로 실수가 많은 부분이 테스트 환경의 독립성을 보장하는 것과 테스트 간의 독립성을 보장하는 것을 놓쳤었는데요. 우빈님의 조언을 얻고 이 부분을 더 신경써서 테스트 코드를 작성할 수 있겠다는 자신감을 얻었습니다. 또 몰랐던 꿀팁을 하나 얻었었는데요! 저는 테스트 픽스처 클린징을 할 때 그냥 deleteAll을 사용했는데 deleteAllInBatch를 사용해야 하는 이유에 대해서 알 수 있어서 좋았습니다. 평소 놓쳤던 부분이었는데 좀 더 시간 효율적인 테스트를 작성할 수 있게 되었고 앞으로 사내에서 JPA 프로젝트에서 운영 소스를 작성할 때도 조금 더 신경을 쓸 수 있을 것 같습니다. 이외에도 테스트를 좀 더 효율적으로 수행할 수 있는 여러 꿀팁들을 얻을 수 있어서 좋았고요. 테스트 코드가 아직까지는 누군가에겐 귀찮은 문제, 누군가에겐 팀원들을 설득해야하는 문제로서 남아있는데 더 많은 사람들이 우빈님의 강의를 듣고 테스트 코드 작성의 필요성을 느끼고 공감했으면 좋겠습니다.
백엔드
・
클린코드
・
테스트코드
・
워밍업클럽
2024. 10. 23.
0
[인프런-워밍업클럽 BE 2기] Day18 과제
1. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이를 한번 정리해 봅시다. 모두 JUnit, Spring 테스트 환경에서 사용된다. 각각의 어노테이션들은 그 목적과 사용 방식이 조금은 다르다. @Mock가짜 클래스 객체를 생성한다. 이 어노테이션에 의해 모킹된 객체는 실제 객체의 메소드 호출에 대해 빈 응답을 준다.외부 의존성을 최소화 해줄 수 있어서 단위 테스트를 작성할 때 유용하다. 실제 객체의 메소드를 호출하지 않으니당연히 실체 객체를 생성하는 것도 아니다. @MockBeanSpringBoot에서 제공하는 어노테이션이고 Spring 애플리케이션의 컨텍스트에서 관리하는 빈을 모킹한다.@Mock은 스프링 컨텍스트와 관련이 없지만 @MockBean은 스프링 컨텍스트와 관련이 있다. 특정 빈을 모킹된 객체로대체할 때 사용된다. 주로 통합 테스트에서 다른 빈과의 의존성을 모킹할 때 유용하다. @Spy스파이 객체는 실제 객체의 메소드 호출을 그대로 유지한다. 특정 메소드를 모킹할 수 있는데 일부 메소드는 실제로 호출되게하고일부 메소드는 모킹할 수 있다. @SpyBean@MockBean과 마찬가지로 스프링 애플리케이션 컨텍스트에서 관리하는 빈을 스파이한다. @InjectMocksInject라는 말에서 알 수 있듯이 의존성 주입을 도와주는 어노테이션이다. @Mock이나 @Spy를 명시한 클래스들을@InjectMocks라는 어노테이션이 달린 대상 클래스에 의존성을 주입해준다. 주로 단위테스트에서 사용된다. "@BeforeEach void setUp() { 1-1. 사용자1 생성에 필요한 내용 준비 1-2. 사용자1 생성 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 3-6. 사용자1의 게시물 생성 } @DisplayName(""사용자가 댓글을 작성할 수 있다."") @Test void writeComment() { // given 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then 검증 } @DisplayName(""사용자가 댓글을 수정할 수 있다."") @Test void updateComment() { // given 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then 검증 } @DisplayName(""자신이 작성한 댓글이 아니면 수정할 수 없다."") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 }"
백엔드
・
백엔드
・
워밍업클럽
・
클린코드
・
테스트
2024. 10. 20.
0
[인프런 워밍업 스터디 클럽 2기] 클린코드, 테스트코드 백엔드 3주차 발자국
토요일에 백엔드 3주차 진도를 모두 진행했습니다.클린코드에 이어 테스트 코드 역시 애플리케이션 개발 과정에서 매우 중요한 과정 중 하나로 저도 생각하고 있습니다.사실 이미 이전에 전부 수강을 다 했던 강의라서 다시 이 강의에서 배운 것들 중에 적용하지 못한 것은 없는지를 중점적으로보았습니다. 이번 주차에는 레이어드 아키텍처의 큰 축인 Presentation, Service, Repository 계층 테스트 코드를 작성했습니다.강의를 다시 보면서 우빈님께서 테스트 코드의 @DisplayName을 짓는 법이나 BDD에 기반해서 테스트 과정을 잘 나누고 구분하시는 것 같다는 느낌을 다시 받았습니다. 회사에 다시 돌아갔을 때 다시 한번 고칠 부분을 찾아볼 수 있는 계기가 될 것 같습니다. 강의를 수강하면서 저를 고민에 빠지게한 것은 우빈님께서는 중간에 비즈니스 로직과 테스트 코드간에 계속해서 스위칭을 하시면서 레드-그린-리팩토링 과정을 잘 거치고 계신데, 제가 아직 TDD에 익숙하지 못한 것이 이러한 전환을 하면서 생기는 복잡함을 이겨내지 못하고 있는 것 같은데 연습이 조금 더 필요한 것 같습니다.
백엔드
・
워밍업클럽
・
클린코드
・
테스트코드
2024. 10. 13.
0
[워밍업 클럽 2기 BE - 클린코드&테스트] 2주차 발자국
이번 주차에는 다음과 같은 내용을 수강했습니다. 코드 다듬기클린코드 리팩토링 실습 기억하기 좋은 조언들 1주차와는 달리 스터디카페 이용권을 예시로 진행을 했는데요. 코드 다듬기코드 다듬기에서는 주석의 양면성이 가장 인상 깊었습니다. 주석은 클린 코드에서 가장 많은 논란이 있는 주제인데요. 최근에 개인적으로 느끼기에는 주석을 사용하는 걸 무조건적으로 죄악시하는 풍조가 있다고 느꼈고, 오히려 주석을 달지 않아서 문제가 생기는 경우가 많았습니다. 개인적으로 주석을 무조건적으로 지양하기보다는 과연 내가 주석이 필요 없을 정도로 남이 보기에 쉽게 이해할 수 있는 코드를 작성했는지를 먼저 스스로에게 되묻는 자세가 필요하다고 생각합니다. 결국 내가 짠 코드도 누군가가 보기에는 어려울 수도 있고 꽤나 코드의 클린함이라는게 자의적인 판단이 많이 들어갈 수 있는 영역이라고 생각하기 때문입니다. 변수나 메서드의 나열 순서 파트에서도 좋은 팁을 얻었습니다. 늘 private 메서드를 따로 빼고나서 걱정이었는데 우빈님께서 사용하시는 상태의 변경 / 판별 / 값 조회 순서를 따르면 좋을 것 같다는 생각을 했습니다. 리팩토링 연습리팩토링 실습 편에서는 지뢰찾기에서 배웠던 것들을 스터디카페 이용권을 발급하는 프로그램을 리팩토링했는데요. 우빈님께서 접근하는 방식 자체가 굉장히 좋았습니다. 처음엔 중복을 제거하는 관점에서 리팩토링을 수행하고, 일급 컬렉션을 적용할 수 있는 부분을 찾고, 객체의 책임을 분리하고, 새로운 도메인 개념을 도출해내는 단계적인 절차를 밟아가면서 리팩토링을 하는 법을 배울 수 있었습니다. 저는 이전에 이러한 명확한 관점 없이 리팩토링을 수행했던 경험이 있던지라 하나의 커밋에 너무 여러 수정과정이 섞여서 정확히 무얼 했는지 스스로도 알아보기 힘들었는데, 새로운 접근법을 얻어간다는 느낌을 받아 좋았습니다. 기억하면 좋은 조언들기억하면 좋은 조언들에서는 오버 엔지니어링을 경계하자는 챕터가 가장 인상 깊었습니다. 사실 얼마전 만든 백오피스 프로그램에서 너무 이르게 추상화한 것 때문에 오히려 새로운 기능을 구현하는 것보다 기존 코드를 고치는데 시간이 너무 많이 들었던 경험이 있습니다. 단순한 문제를 괜히 복잡하게 풀어보려는 욕심이 앞섰기 때문에 발생한 문제였는데, 구체적인 구현체들을 미리 만든다음에 그 구체들로부터 추상화할 수 있는 부분을 뽑아내어 추상화를 하는 것이 더 낫다는 것을 다시 한번 깨달았습니다. 금주에는 과제도 있었고 지뢰찾기에서 배운 것을 적용도 해보는 시간이었는데 개인적으로 코드를 작성하는 시간에 건강 이슈로 인해서 스스로 고민하고 코드를 작성하는 과정이 빈약했습니다. 그래서 과제도 사실 거의 제 생각은 없은 채로 제출했는데 좀 부끄러웠습니다. 최근에는 많이 좋아져서 다시 심신을 가다듬고 테스트 코드 주차에는 이를 만회해보도록 노력해야겠다는 생각을 했습니다.
2024. 10. 05.
0
[워밍업 클럽 2기 BE - 클린코드&테스트] 1주차 발자국
이번 주는 클린한 코드를 작성하는 방법에 대해서 쭉 배웠습니다.수강하면서 가장 느꼈던 것은 클린 코드는 단순히 '나 이렇게 코드 깔끔하게 짠다'라는 것을 자랑하기 위함이 아닌내가 아닌 함께 일하는 동료를 위한, 이타적인 행위임을 느꼈습니다. 학습 내용 요약 Day 2 - 추상과 구체추상과 구체 시간에는 다시 한번 추상화를 잘하는 것이 클린한 코드의 시작점임을 깨달았습니다.강사님께서 파블로 피카소가 한 말을 말씀하신 것이 인상 깊었는데요. 추상은 항상 구체적인 실재에서 시작해야 한다.사실 얼마전에 팀에서 개발하던 프로젝트가 지나치게 '이른' 추상화 때문에 모든 팀원이 고생한 적이 있습니다.외부 서버와 통신하는 클라이언트를 공통화 했는데, 너무 섣부른 나머지 추가적인 요구사항에 전혀 대응을 할 수없었습니다. 앞으로 나올 구체적인 실재들을 간과한 추상화가 문제였기 때문입니다. 최근의 경험과 더불어서저 문장을 보고 구체와 추상간의 Context Switching을 잘 해야겠다고 생각이 들었습니다. Day 3 - 논리, 사고의 흐름 | 객체 지향 패러다임Day 3의 주제들은 사실 미리 알고 있었던 내용입니다. 저도 입사하고나서 다른 팀원들에게 적극적으로권유하고 있는 방법입니다. 논리, 사고의 흐름이라는 섹션은 딱 하나의 주제를 관통합니다."읽는 사람으로 하여금 덜 고생하게 하자"우리의 뇌를 메모리에 비유하여 읽는 사람으로 하여금 이 자원을 덜 쓰도록 하는 것이 좋은 코드라는 가르침을얻었고 Early Return이나 Depth 줄이기(else 지양), 공백에 의미 부여하기, 부정어를 가급적이면 사용하지 않기처럼 실제로 글쓰기나 말하기에서도 중요한 것들을 코드에 녹이는 방법을 배웠습니다. Day 4 - SOLIDDay 4는 객체 지향의 Core라고 할 수 있는 SOLID입니다. 지뢰찾기 게임을 이 원칙에 맞춰서 리팩토링 해나아갔는데요. 제가 이해한 SOLID는 서로 많이 연관되어 있습니다. 하나의 톱니바퀴 여러개를 맞물려야하는 느낌이었는데요. 이 원칙을 지키는데에 있어서 가장 중요한 것은 도메인 지식을 잘 이해하고 있는 것이 중요하다고 생각합니다. 그래야 필요한 인터페이스는 뭐가 있고 그 인터페이스의 명세는 어떻게 되어야 하며, 객체 간 책임분리를 통한 올바른 설계를 완성할 수 있는 것 같습니다. 개인적으로 단순히 기획서의 디스크립션만 보고 급급하게기능을 개발했던 지난 날을 반성하게 되었습니다. Day 5 - 객체 지향 적용하기Day 5에서 배운 것들 중에서는 상속과 조합, 일급 컬렉션이 가장 기억에 남았습니다. 사실 상속보다는 조합을지향하라는 문구를 본 적은 있는데 실제로 적용을 해본 적은 없었거든요. 이번에 좋은 레퍼런스를 얻었고단순한 상속보다는 약간은 더 복잡하고 코드 양이 늘어나지만 변경에 유연한 조합을 추후에 사내 프로젝트에서적용해보고 싶다는 생각이 들었습니다. 또한 일급 컬렉션의 효용성과 불변성에 대해서 다시 중요성을 깨달았습니다. 개인적으로 칭찬하는 점은 강의를 들으면서 알고 있는 내용도 있었고 몰랐던 내용도 있었는데요.알고 있는 내용에 대해서 강의를 들을 땐 '이렇게 소스 코드를 정리하실 거 같은데?' 라는 생각이 들때쯤제 예상이 맞았던 적이 많았습니다. 이전에 배웠던 것들을 그래도 잘 머릿속에 담아두고 있구나 라는 생각이들었구요. 아쉬웠던 점은 강의에서 배웠던 점들을 적용시키는데 있어서 그 적용 범위를 확장하지 못하고 있는 것 같습니다. 아무래도 경험 부족이 원인인 것 같은데 이 부분은 시간이 해결해주리라 믿고 있겠습니다 ㅠㅠ 발자국 끝!
백엔드
・
백엔드
・
클린코드
・
테스트코드
・
워밍업클럽
2024. 10. 03.
0
[워밍업 클럽 2기 BE 클린코드 & 테스트코드] BE 2기
첫 번째 미션 : 아래 코드를 읽기 좋은 코드로 변경하기아래의 코드는 물론 기능 구현상에서 오작동을 일으키는 코드는 아니겠지만 이번 섹션에서 배운 내용을 토대로 읽는 사람으로하여금 과부하까진 아니더라도 부하를 겪을 수 있습니다. 아래의 코드는 그럼 어떤 문제를 가지고 있을까요?public boolean validateOrder(Order order) { if (order.getItems().size() == 0) { log.info("주문 항목이 없습니다."); return false; } else { if (order.getTotalPrice() > 0) { if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } else { return true; } } else if (!(order.getTotalPrice() > 0)) { log.info("올바르지 않은 총 가격입니다."); return false; } } return true; }첫 번째는 캡슐화가 잘 지켜지지 않고 있습니다. 객체의 값을 지속적으로 getter 메서드를 가져오면서 확인하고 있습니다.이는 TDA(Tell, Don't Ask) 원칙을 지켜지지 않고 있고 객체가 그 자체의 역할을 하게끔 만들지 않았습니다. 두 번째는 읽는 사람으로 하여금 머리를 많이 쓰게 하고 있습니다. 머리를 많이 쓰게 한다는 것은 다음과 같은 이유에서 입니다.모든 조건문이 한 호흡에 이어져 있다.공백으로 각 작업간의 STEP을 구분하지 않았다.Depth가 깊다.부정 연산자 사용으로 인해서 조건을 한 번 더 이해해야 한다.이를 리팩토링 한다면 어떻게 할 수 있을까요? public boolean validateOrder(Order order) { // 주문 항목 확인 if (order.hasNoItems()) { log.info("주문 항목이 없습니다."); return false; } // 총 가격 확인 if (order.isTotalPriceInvalid()) { log.info("올바르지 않은 총 가격입니다."); return false; } // 사용자 정보 확인 if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } return true; } 리팩토링한 코드는 위와 같습니다. Order 객체 스스로 판단할 수 있는 메서드로 조건문을 처리하여 TDA 원칙을 따랐습니다.공백을 둚으로서 각 작업의 STEP을 구분했습니다.3-Depth 까지 타고 들어가야하는 코드를 전부 1-Depth 이내에 처리했습니다.부정 연산자를 사용하기보단 더 의미있는 이름의 메소드를 만들어 직관적으로 조건문을 판단할 수 있도록 했습니다.과제를 수행하면서 느꼈던 것은 좋은 코드란 좋은 글을 작성하는 것과 마찬가지라는 느낌이었습니다. 좋은 글을 쓰는 첫 출발점은 단문 쓰기를 통해 호흡을 짧게하여 읽는 사람으로 하여금 부하를 느끼지 않게 하는 것이 중요했습니다. 문장의 마침표가 문장의 시작으로부터 너무 멀리 있게되면 이는 읽는 사람을 배려하지 않은 글쓰기이기 때문입니다. 클린 코드는 나만의 만족을 위한 것이 아니라 이타적인 마음을 다시 한번 갖게 되는 좋은 원칙인 것 같습니다. 두 번째 미션 : SOLID를 자신의 언어로 정리하기 SRP : Single Responsibility Principle단일 책임 원칙은 클래스 혹은 메서드, 함수는 한 가지 책임만 가져야 한다는 것입니다. 자동차를 예로 들어볼까요? 자동차 클래스를 작성한다면, 우리는 이 원칙을 지키기 위해 엔진, 연료, 네비게이션, 에어컨 조절, 음악 재생과 관련된 변수와 메서드를 전부 넣어놓으면 안됩니다. 자동차는 그저 여러 가지 요소의 조립이 끝난 채로 존재해야합니다. 그래서 우리는 엔진, 연료 시스템, 네비게이션, 오디오 클래스를 별도로 분리하고 그에 맞는 기능들을 작성해야 합니다. OCP - Open/Closed PrincipleOCP는 소프트웨어는 구성에 있어서 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다는 원칙입니다. 솔직히 많은 사람들이 이 이야기를 처음에 들었을 때 의구심을 품습니다. '어떻게 확장을 하는데 수정을 안할 수가 있어?' 라고요. 하지만 적어도 소프트웨어 세상에서는 가능합니다. 앞서 말했던 SRP를 지킨다면 말이죠. 만약 자동차 클래스에 오디오 관련 기능들을 전부 다 작성했다면 어떻게 되었을까요? 우리의 자동차에는 보스의 것도, 뱅앤올룹슨의 것도, 하만 카돈의 것도 들어갈 수 있습니다. 하지만 자동차 클래스에 오디오 관련 코드를 전부 작성했다면 자동차 클래스는 늘어나는 오디오 업체의 코드를 계속해서 생산해내야 합니다. 그러나 이전에 별도의 객체로 만들고 추상화까지 더했다면? 확장에 있어서 기존 코드를 수정하는 일은 없을 것이고 우리는 단순히 '추가'만 하면 될 것입니다. LSP - Liskov Substitution Principle리스코프 치환 원칙은 자식이 언제든지 부모를 대체할 수 있어야 한다는 원칙입니다. 다시 차량의 오디오 기능을 생각해봅시다. 오디오 인터페이스가 있고 오디오 인터페이스에 명세되어 있는 기능은 볼륨 켜키, 볼륨 끄기 입니다. 하지만 어느 한 회사의 특정 제품 클래스는 볼륨 켜키 기능이나 볼륨 끄기 기능이 기대한대로 동작하지 않는다면 어떻게 될까요? 예를 들어서 볼륨 끄기를 1씩 끄는게 아니라 한번에 0으로 만들어버린다거나 말이죠. 이렇게 되면 프로그램이 균일하게 동작하지 않을 것이고 서로가 서로를 완벽하게 대체할 수 없을 것입니다. 따라서 인터페이스를 준수하는 것이 LSP가 전달하고자 하는 메세지입니다. ISP - Interface Segregation PrincipleISP는 클라이언트가 사용하지 않는 인터페이스에 의존하지 않도록 하는 것입니다. 모든 자동차들은 구매할 때 고객이 원하는 옵션을 가지고 있습니다. 하지만 내 자동차에 내가 고르지 않은 옵션을 동작하는 버튼이 자리만 차지하고 있다면 어떻게 될까요? 이는 운전자에게 혼동을 줄 수 있고 불필요한 공간 낭비를 발생시킬 수 있습니다. 코드에서는 어떤가요? 특정 클래스가 구현하지 않아도 되는 부분을 구현해야할 것처럼 개발자에게 혼동을 줄 수 있고 이는 장애를 유발하거나 불필요한 용량 차지로 이어질 수 있습니다. 인터페이스는 가능한 범용적이 아닌 세부적으로 분리해야한다는 것이 ISP가 전하고자 하는 메세지입니다. DIP - Dependency Inversion PrincipleDIP는 고수준 모듈은 저수준 모듈에 의존해서는 안되고, 고수준 모듈과 저수준 모듈 모두 추상화에 의존해야 한다는 원칙입니다.이 역시 말이 어렵습니다. 저도 처음에 OCP 다음으로 어려웠던 것 같습니다. 하지만 위에서 자동차 예시로 다 말씀을 드렸습니다.자동차 클래스는 여러 인터페이스의 조합으로 이뤄져야 한다고 했습니다. 자동차 클래스는 가솔링 엔진, 전기 엔진과 같은 구체 클래스에 의존해서는 안됩니다. Engine 인터페이스가 있고 이를 구현한 가솔린 엔진과 전기 엔진이 있어야 합니다. 오디오 역시 오디오라는 인터페이스만 있을 뿐, 이를 구현한 각 제조사의 오디오가 있을 뿐이죠. 자동차 클래스는 따라서 어떤 특정 엔진이나 특정 오디오의 정보는 알 수 없습니다. 그저 인터페이스만 갖고 있을 뿐입니다.
백엔드
・
워밍업클럽
・
백엔드