블로그

볼드 UX

[인프런 워밍업 스터디 1기 디자인] 오리엔테이션 준비하기

 안녕하세요! 지식공유자 볼드입니다. 최근에 인프런 워밍업 스터디 클럽 1기에서 프로덕트 디자인 코치로 참여하게 되었어요.준비 과정이 꽤 새로웠고, 많은 것을 배우는 시간이었습니다. 오늘은 제가 어떻게 러너분들과 첫 만남을 위해 준비를 하였는지 알려드리고자 해요.   첫 만남을 미리 계획하다저는 4주 전부터는 0기 코치님들이 남겨둔 자료들을 보며 어떻게 하면 더 좋은 오리엔테이션을 만들 수 있을지 고민했어요. 구조부터 차근차근 짜고, 내용을 채워 넣어서 빠르게 프레젠테이션을 완성했습니다. 첫만남인 만큼 어떻게 하면 더 재미있고, 참여자들과 적극적으로 소통할 수 있을까 고민을 많이 했어요. 그래서 피그잼을 사용한 워크샵 형태로 진행하기로 결정하고, 세 가지 큰 원칙을 세웠습니다:많은 정보를 빠르게 명확하게 전달하기최대한 재미있고 인터랙티브하게 이야기가 살아있는 컨셉 유지하기 다행히 ‘러너’라는 주제가 이미 있어서 그걸로 컨셉을 잡았고, 다음과 같은 여정으로 구성해 보았어요.🚀 출발: 워밍업 클럽을 시작하게 된 이유🗺 코스: 워밍업 클럽의 미션들🎯 도착: 워밍업 클럽을 마치고 받게 되는 혜택들    OT 시작 전에는 새 직장에서 바쁠 것 같아서 미리 인프런 담당자 셰리님과 자료를 공유하고 점검하는 시간을 가졌어요.그리고 막상 OT 주간이 되니, 예상대로 정신 없었습니다. OT 당일에는 반차를 내고, 오전에 교회에서 성경공부를 마치고 집에 돌아와 커피 한 잔 마시며 마지막 준비를 했죠.    러너 분들과 드디어 만나다영국시간으로 12시에 시작했어요.(한국 시간으로는 오후 8시), 제가 먼저 짧게 발표를 먼저 진행하고 러너 분들은 질문에 따라 각자 글을 작성하셨어요.  작성 후에는 서로의 글을 보며 하트를 남기는 시간을 가졌는데, 이게 생각보다 더 재미있었던 것 같아요.  미리 준비한 탭으로 미션 정보를 빠르게 효과적으로 보여드리고, 원래 OT 전까지 블로그 글을 쓰지 못했는데 셰리님의 빠른 대처로 발자국 미션 시연을 성공적으로 마칠 수 있었어요.  OT 끝나고 난후워크샵이 끝난 후, 참가자분들의 피드백을 부탁드렸어요. 피드백을 보고 나니 제가 준비한 만큼 결과도 좋았다는 생각이 들더군요.(아래는 제가 몇개 선정한 감사한 피드백!)  2기에도 제가 참여할지는 아직 모르겠지만 2기에도 오리엔테이션 준비 경험을 살리거나 또 다른 코치님들이 사용할 수 있도록 이 피그잼 보드를 템플릿화하면 좋을 것 같아요. 또한, 이 방식을 다른 온라인 강의에서도 활용할 수 있을 것 같아요. (필요하신 분들은 알려주세요. 무료 나눔해드릴게요!) 마지막으로 인프런 워밍업 클럽 이전에 제가 진행한 인증샷 스터디에서 수강생과 교류가 있으면 좋을 것 같다는 의견이 있었어요. 처음엔 이걸 어떻게 개선해야할지 막막했는데, 인프런 워밍업 클럽을 참여하면서 이 문제를 해결할 수 있었어요. 그리고 셰리님을 포함한 인프런 팀이 없었다면 이 모든 게 불가능했을 거예요. 정말 감사드립니다! 인프런팀 만세! 앞으로 남은 세 번의 특강, 워크샵을 어떻게 준비할지 계획 중인데, 라이브 튜토리얼과 프레젠테이션을 어떻게 잘 조합할지, 함께 만들어가는 워크샵 과정이 어떨지 기대되네요. 인프런 워밍업 클럽 1기에 참여하신 모든 러너분들 다같이 파이팅해요 🔥     

UX/UI워밍업클럽디자인시스템피그마

워밍업 클럽 그리고 그 이후 테스트코드와 클린코드 나의 생각

4주간의 스터디… 그리고 그 이후 나는 도대체 무엇을 하고 있을까? 지금 현재 내가 배운 내용 그리고 그 전과 그 이후과 얼마나 달라졌을까 비교하며, 회고를 하고 다시 한 번 마음을 다잡아보려한다.클린코드의 적용이 부분은 개인적으로 원래 잘하고 있던 부분이였다고 생각한다.추상화의 고민, 관심사를 어떻게하면 공통으로 분리할까 나를 위한 읽기 쉬운 코드를 어떻게 만들까?물론 이러한 영향을 준 것은 회사내 동료들의 아름다운 코드들과 아름답지 못한 코드들이고, 그 방법론은 클린코드, 리팩토링 등등 고전적인 책들과 다양한 읽기좋은 코드에 관련된 서적을 읽으면서 내 나름의 규칙을 만들기 시작했다.한 달이 지난 지금 내가 잘했던 그 부분은 유지하되, 새로운 법칙이 생겼다.나만의 용어 사전사실 제일 못하는게 이름 짓는 부분이다.아직도 못한다.하지만, 이러한 이름을 더 효과적으로 짓기 위해서, 강사님이 말씀해주신 풀에서 꺼내서 쓰는 용어사전을 차츰차츰 나름 정리하기 시작했다.이러한 용어들은 잘 정리된 오픈소스들에서 찾아보려고 노력을 많이 하였다.과감한 오버로딩오버로딩에 대해 사실 병적으로 싫어하던 시절이 있었다.파라미터에 따라 그 메서드 이름이 참 보기 어려워서 장황한 메서드를 만든적도 있다.public User createUserByNameAndYearAndAge(String name, int year, int age); public User createUserByName(String name); 하지만, 문득 자바 Lists 인터페이스를 보게되었고 중요한것은 오버로딩하나로 가독성만 확보되면 된다는 부분이었다.주석 사용논쟁이 가장 많은 부분 중 하나로서, 주석을 사용하는가? 사용하지않는가? 라는 부분이다.나는 후자에 가까운 개발자로서, 잘 설계된 코드는 주석보다 높은 가치를 한다고 믿었다…그런데, 사실 잘 설계된 코드란 것은 그 때 내가 그렇게 믿는 것 뿐이지, 후대에 내가 다시보면 이해 못하는 코드가 많다.결국 이러한 부분에 대한 이해를 돕는데는 주석을 적절히 활용하거나, 애초에 간결한 메서드 이름을 짓는 방법 밖에 없다.테스트 코드테스트 코드는 정말로 이 스터디의 전과 후과 눈에 띄게 달라졌다고 해도 과언이 아니다.이전의 테스트 코드는 사실 동료와의 테스트 코드에 대한 고민, 그리고 클린코드를 읽고 테스트코드의 필요성과 리팩토링등 다양한 실무에 부딪히면서 나의 필요에 따라서 테스트 코드를 작성했다면, 강의 이후는 테스트코드를 하나의 테스트 도구로서 활용을 제대로 하고 테스트코드의 장점과 강점에 대해서 나름대로 정확하게 이해를 하게 되었다.물론, 회사에서 내가 이렇게 테스트코드를 적극 도입하고 도입한 테스트코드에 대해 공유하며 나의 테스트코드에 대한 철학을 좀 더 고도화 시키는 부분들이 도움이 되었다.TDD대부분의 개발자들 (5년미만의 개발자들)은 TDD에 대해 환상을 가지고 있다.TDD에 대한 환상을 가지고 있다면, 일단 한 번 도전해 보는 것을 추천한다.물론 TDD를 위해 기존 잘 돌아가는 프로젝트를 아예 끄집어서 뒤엎는 것 보다.사내에 도움이 될만한 프로덕트를 만들면서 TDD를 적용하는 것을 추천한다.참고로 나는 TDD를 위해 백오피스를 했다 😃내가 생각하는 TDD (테스트 코드)TDD를 도입했는데, 내 생산속도가 느려졌어 라는 이야기를 종종 듣는다.TDD가 아닌 테스트코드도 마찬가지다.일단, 강사님이 말씀해주신 부분 중 하나 모든 영역을 테스트 커버하려고 하지않아도 된다. 라는 이야기를 세션 도중에 하셨다.또한, 테스트 코드를 사용하면서 하나의 철학이 생겼다.나의 테스트 코드는 ‘실용주의 테스트 코드’ 라는 철학으로 정의할 수 있다.물론, 저 책에서 영감을 받은 것은 아니고… 그냥 단순한 나의 원칙이다.실용주의 테스트 코드를 위한 나의 원칙테스트 커버리지에 매몰되지 말자주니어 개발자들은 이러한 커버리지에 매몰되는 경우가 상당히 많이 있다. ”테스트 코드 95% 커버리지” 물론 좋다고 생각한다. 근데, 95%의 커버리지를 채우는 시간보다. 차라리 로직에 대해서 완성도를 높이거나, 그 시간을 어느정도 분배하는게 맞다고 생각한다. 물론, 혼자서 하는 프로젝트에 대해서는 95%든 100%든 자기 만족이기에 상관없다고 생각들지만, 비즈니스 프로덕트에 커버리지에 매몰되는 것 보다. DDD에서 어떤 영역에 테스트 코드를 주로 작성했고, 왜 그 영역에 테스트 코드를 작성했는지에 대한 고민과 철학을 녹여내는게 중요하다.테스트 코드는 유지보수가 필요하다테스트 코드에 대해 관심을 가지게 해주는 동료와 고민했던 부분은 테스트 코드를 과연 유지보수를 적게 설계 하려면 어떻게 해야할까 라는 이야기를 많이 했었다. 사실 이러한 부분들 때문에, 테스트 코드를 작성할 때마다 ‘어짜피 이거 곧 깨질텐데…’ 라는 생각을 하게 되었다. 중요한 것은 깨지는게 맞는거 같다. 깨지면 고치면되고, 깨진다는 것은 그에 대한 사이드 이펙트들도 확인 할 수 있다는 점이다. 코드는 생물학과 마찬가지로 끝 없이 진화하고 테스트 코드는 그에 대한 가설이다. 가설은 어떠한 부분을 검증하기 위해 깨어질 수도 있고 새로 정의되어질 수도 있다. 컴퓨터는 공학적인 측면도 강하지만 과학적인 측면도 강하다.테스트코드는 가설이다테스트코드는 가설이기 때문에, 실제로 가설을 세우기 위해서는 이 가설이 맞는지에 대한 전반적인 이해가 필요하다. 예를 들어 내가 진화론이라는 가설을 새울 떼 유전진화학에 대한 학문에 대한 이해가 피상적으로 있는 상태에서는 가능할까? 사실, 불가능에 가깝다. 좋은 테스트 코드란 테스트 코드를 작성하기 위한 그 도메인에 대한 전반적인 이해도를 요구하고 수반한다. 실용주의적인 테스트 코드는 테스트 코드를 통해 도메인에 대한 지식도 높이는데 기여한다라는 생각에 기반한다.성장끝으로 이번 세션 이후로 나의 성장이 많이 되었다는 것도 느끼지만 회사에서 코드가 깔끔할 뿐만 아니라 테스트 코드까지 합리적인 이유와 검증가능한 코드다 라는 이야기를 들었다.그리고, 최근 1000줄 가까이 되는 레거시의 가독성을 확보하고, 그에 대한 테스트 코드로 검증하는 과정을 걸치면서 코드의 현대화도 많이 이루어냈다.레거시라는 것은 개인적으로 이렇게 정의하려고한다.‘가장 중요하고 필요한 기능이지만, 그 누구도 고치려고 하지 않은 미지의 영역’바꿔말하면 가장 중요하기에 나만 알아야하는게 아닌 모두가 알아야하고 모두가 아는 비용을 줄이기 위해서, 고민을 한다면 그리고 이게 합리적 이유라면 클린코드와 테스트코드 도입하지 않을 이유가 없지 않을까?

백엔드테스트코드클린코드인프런워밍업클럽

10

우빈님의 세심한 코드 리뷰 - 인프런 워밍업 클럽 3기 백엔드 코드 ✨

👣 발자국 책갈피인프런 워밍업 클럽 3기 백엔드 코드 발자국 1주차인프런 워밍업 클럽 3기 백엔드 코드 발자국 2주차인프런 워밍업 클럽 3기 백엔드 코드 발자국 3주차인프런 워밍업 클럽 3기 백엔드 코드 발자국 4주차✅미션PR 책갈피[미션 Day 2] 추상과 구체 예시 작성[미션 Day 4] 리팩토링 & SOLID 원칙[미션 Day 7] 리팩토링 연습[미션 Day 11] 단위테스트 작성[미션 Day 16] 레이어드 아키텍처 특징 및 테스트 작성법[미션 Day 18] Mock 어노테이션 종류 및 차이점 & BDD 패턴 매치🙊 시작이 반이다... 벌써 중간점검 ?인프런 워밍업 클럽이 시작한지 2주가 지났다.. 앞으로 남은 발자국이 2개 뿐이다.. 👣이번주에는 중간점검으로 온라인 라이브가 진행 되었다. 온라인 라이브에 대한 내용은 다음과 같다.미션 Day 4 에 대한 공통 피드백Q&A에 대한 답변미션 Day 7 코드리뷰 진행각 세션은 놀라울 정도의 세심한 우빈님의 피드백 덕분에 많은 인사이트를 얻게 되어 좋은 시간이었다. 나도 첫번째로 코드리뷰를 신청하고 라이브 마지막에 코드리뷰를 받았는데 너무 좋은 경험이었다. 💪(커피를 좋아하시기로 유명한 우빈님께 Q&A 세션 도중 저가 커피 브랜드 중 어디 브랜드가 제일 맛있냐는 질문이 나왔는데.. 드셔 보신 적이 없다고 답변해 주신 부분이 인상적이었다.. ㅋㅋ 😁)✨ 우빈님의 세심한 코드 리뷰위에서 이야기했듯이 코드리뷰를 첫번째로 신청해서 우빈님께 온라인 라이브 시간에 코드리뷰를 받았다.해당 미션은 "스터디 카페" 프로그램을 리팩토링하는 미션이였는데.. 작년 4분기에 강의를 수강했을 당시에 3번이나 진행하였다.첫 번째 리팩토링, 강의를 듣기 전에 리팩토링두 번째 리팩토링, 강의를 수강하며 리팩토링세 번째 리팩토링, 강의를 수강 후 정리하며 다시 리팩토링이번이 네 번째 리팩토링이였는데 할 때마다 왜 새로운 것인지.. 🥲그래도 손이 기억이라도 한 듯 나름 순조롭게(?) 미션을 진행하게 되었고, 추가적으로 리팩토링을 진행하였고 해당 부분을 리뷰를 받고 싶어 신청하게 되었다.(우빈님께서 4번이라는 부분에 놀라셨는지(?).. 디스코드 스레드에 댓글을 남겨주셨다! 🤣)다시 돌아와서.. 코드리뷰 받은 내용은 아래와 같다.1⃣ 중요 도메인 StudyCafePassType의 구조화 🔗 Github PR 링크StudyCafePassType 구조화 리팩토링 ♻ 리팩토링 코드public enum StudyCafePassType implements PassTypeSelectable, PassTypeFormatter { // 📝 인터페이스 구조화 HOURLY("시간 단위 이용권") { // 📝 사용자 입력에 대한 구조화 @Override public boolean selected(String userInput) { return "1".equals(userInput); } // 📝 사용자 출력 포맷에 대한 구조화 @Override public String format(StudyCafePass pass) { return String.format("%s시간권 - %d원", pass.getDuration(), pass.getPrice()); } } } ✏ 우빈님 리뷰Q. 클래스 내부에서 사용자 입력값 및 출력값에 사용하는 인터페이스를 구현함으로써 오버 엔지니어링이 된 것 같은 느낌이 드네요.. 🤦‍♂️ A. 저도 그렇게 생각해요.. ㅋㅋㅋㅋ 오버 엔지니어링이기보다 PassType은 중요한 도메인 모델인데, Input에서만 의미를 가지는 사용자 선택지가 침투하고 있다. 사용자 선택 방법이 "a", "b", "c"로 바뀐다면? 단순히 입력 방식을 바꿨을 뿐인데 무료 도메인 모델이 수정되어야 하는 엄청난 사태가 발생한다. 항상 구조화를 하는 것이 정답은 아니다. Output format도 마찬가지이다. 책임이 우선이다. 적절한 책임의 분배가 객체의 결합도를 낮추고 응집도를 높이는 것이다.  🤔 돌아보기단순히, OCP를 적용하기 위해 접근해서 리팩토링 했었는데..적절한 객체 책임 분리를 하지 못했으며, 중요한 도메인 모델을 수정하는 엄청 큰 사이드 이펙트가 일어날 수 있다는 점을 간과 했다는 것이다.다음부터는 구조화를 남발하지 않고 책임에 집중해서 리팩토링 해야겠다..2⃣ 이용권을 읽는 부분과 읽은 부분의 개념을 추출하여 객체 분리 🔗 Github PR 링크ReadLockerPasses 객체 분리 ♻ 리팩토링 코드public class ReadLockerPasses { // 📝 LockerPasses를 해석하는 객체 분리 private final List<StudyCafeLockerPass> passes; private ReadLockerPasses(List<StudyCafeLockerPass> passes) { this.passes = passes; } // 📝 lines을 해석하여 List<StudyCafeLockerPass> 객체를 만들어준다. public static ReadLockerPasses ofLines(List<String> lines) { List<StudyCafeLockerPass> passes = lines.stream() .map(ReadLockerPasses::ofLine) .toList(); return new ReadLockerPasses(passes); } private static StudyCafeLockerPass ofLine(String line) { String[] values = line.split(CSV_SPLITTER); // ⭐️ CSV라는 방식에 종속적 StudyCafePassType studyCafePassType = StudyCafePassType.valueOf(values[0]); int duration = Integer.parseInt(values[1]); int price = Integer.parseInt(values[2]); return StudyCafeLockerPass.of(studyCafePassType, duration, price); } // 📝 StudyCafeLockerPasses를 생성해준다. public StudyCafeLockerPasses toPasses() { return StudyCafeLockerPasses.of(passes); } } ✏ 우빈님 리뷰Q. 일급 컬렉션을 적용하기 위해 toPasses() 메서드를 생성했는데 Read~라는 네이밍을 가진 클래스에 많은 책임이 부여된 것 같아 네이밍이 모호한 것 같습니다. 좋은 방법이 있을까요..? 🧐 A. 많은 책임이라고 생각하신 이유가 있을까요? "ReadLockerPasses는 어디선가 읽은 lines를 가지고 StudyCafeLockerPasses를 만들어준다"의 책임으로 보여서, 어색하지 않으며 테스트 코드 작성도 가능하다. 그와 별개로 CSV라는 방식에 종속되어있다. CSV형식이 다른 방식으로 바뀌었을 때 같이 바뀌어야 하는 부분이 CSV_SPLITTER 부분이다. 의도한 것 이라면 상관없다.  🤔 돌아보기Read라는 클래스명을 가지고 있어 StudyCafeLockerPasses를 생성해주는 메서드가 존재해 많은 책임이 있다고 생각했는데..우빈님 리뷰 이후에 다시 보니.. 그렇게 어색한가 싶기도 하다.. ㅎㅎ해당 클래스의 작성 당시 CSV 방식을 의존하려는 의도는 없었다. 단순히 읽은 부분의 개념을 추출한 것인데.. 위의 클래스는 CSV_SPLITTER상수가 사용되어 의도하지 않게 CSV라는 방식에 종속적이게 된 것이다.CSV라는 방식이 변경되면 객체 로직이 바뀌어야 한다.객체 구현 시, 종속성에 대해서 방어적으로 접근할 필요가 있어보인다.3⃣ ProvideException 커스텀 예외🔗 Github PR 링크ProvideException 커스텀 예외 ♻ 리팩토링 코드// 📝 이용권을 가져오는 과정에서 생긴 에러의 커스텀 예외 클래스 생성 public class ProvideException extends RuntimeException { public ProvideException(String message) { super(message); } } public class StudyCafePassMachine { public void run() { try { outputHandler.showPassOrderSummary(order); } catch (AppException e) { outputHandler.showSimpleMessage(e.getMessage()); } catch (ProvideException e) { // 📝 커스텀 예외 catch outputHandler.showSimpleMessage("이용권을 제공받을 수 없습니다."); } catch (Exception e) { outputHandler.showSimpleMessage("알 수 없는 오류가 발생했습니다."); } } } ✏ 우빈님 리뷰Q. AppException 성격이랑 다른 것 같다고 생각되어 Provider 인터페이스에서 발생하는 예외 클래스 ProvideException를 별도로 생성하였습니다. A. 혹시 어떻게 다르다고 생각셨나요?? AppException의 의도는, 프로그램에서 발생할 수 있는 대부분의 애플리케이션 상황을 정의하는 최상위 예외 클래스이다. 만약 ProvideException을 별도로 표기하여 더 구체적인 상황을 나타내고 싶으면, AppException을 상속받아서 구성해야 한다. 그렇지 않으면 커스텀 예외 클래스가 늘어남에 따라 catch절도 같이 늘어날 것이다. 추가적으로, "이용권을 제공받을 수 없습니다."라는 메시지가 사용자 친화적이지 않다.  🤔 돌아보기리팩토링 당시, 초기 이용권을 가져와야만 프로그램이 실행된다는 관점에서 ProvideException의 커스텀 예외 클래스를 작성하였다.하지만 이용권을 가져오는 부분은 프로그램 내부에서 필요한 시점마다 호출하고 있어우빈님 리뷰대로 AppException 클래스를 상속받아서 작성하는 것이 더 나은 설계 같다.예외 메세지도 사용자 관점에서는 친화적이지 않은 것이 분명하다.내가 키오스크 시스템을 사용하다가 저런 메세지를 마주한다면... 화가 날 것 이다... 😡프로그램의 의도를 정확히 파악할 필요가 있어보인다. 또한 예외 메세지도 누가 보는지에 따라 고민해보는 습관을 길러야겠다.이렇게, 요청한 3개의 리뷰와 2개의 추가 리뷰를 받아 보았다..고작 3일 만에 7명이나 리뷰를 해주셨는데 세심하고 또 세심했다... 퀄리티가 상당했다.. ✨이번 온라인 라이브를 통해 우빈님에 대한 팬심과 존경심이 더욱 커졌다....! 📈리뷰해주신 내용으로 다시 리팩토링을 함으로써 한층 더 Readable Code에 대한 성장을 경험할 수 있었다. 🚀💡 자기만의 언어로 강의 키워드 정리하기 섹션 6. 코드 다듬기좋은 주석 - 주석의 양면성주석이 많다는 것 : 추상화가 덜 되고 가독성이 좋지 않은 코드 (코드 품질 저하 📉)주석이 필요한 경우 : 히스토리를 알 수 없을 경우, 주석으로 상세히 설명변수와 메서드 나열 순서변수 : 사용하는 순서대로 위치한다. (인지적 경제성 / 뇌 메모리 줄이기)객체의 공개/비공개 메서드 : 공개 메서드를 상단에 위치하고, 비공개 메서드 하단에 위치한다. 공개 메서드 중에서도 중요도의 순서에 따라 배치한다.공개 메서드 : 객체의 상태를 변경 하는 부분이 가장 상단에 위치하도록 - 상태 변경 >>> 판별 >= 조회비공개 메서드 : 출현한 순서대로패키지 나누기여러 파일들의 네임 스페이스를 관리하기 때문에 적당한 수준으로 잘 나누어야 한다.대규모 패키지 변경은 팀원과의 합의 필요 -> 추후 conflict가 생길 수 있다.기능 유지보수하기정렬 단축키, linting, style - sonarlint, editorconfig섹션 7. 리팩토링 연습메서드 추출로 추상화 레벨 맞추기Optionalreturn null / Optional 파라미터 사용은 안티패턴이다.객체에 메시지 보내기객체를 존중하고 메시지를 보내자.객체의 책임과 응집도⭐️ 추상화 관점의 차이 - FileHandler구현에 초점을 맞춘 추상화 VS 도메인 개념에 초점을 맞춘 추상화File을 read하는 부분의 로직들은 전부 FileHandler에 들어갈 것이다. 잘못된 객체 응집일 수도 있다..방법에 초점을 맞춘 설계 방식이 아닌 어떤 데이터를 가져오는 가에 대한 초점을 맞추는 것이 좋다.섹션 8. 기억하면 좋은 조언들능동적 읽기가지고 있는 리팩토링 기법들을 총동원해서 읽자. -> 리팩토링하면서 읽기눈으로만 보는 수동적 읽기는 권장하지 않는다.도메인 지식을 늘리기 위해서 능동적 읽기가 필요하다. (작성자의 의도 파악)오버 엔지니어링필요한 적정 수준보다 더 높은 수준의 엔지니어링예시 1. 구현체가 하나인 인터페이스구현체가 수정할 때마다 인터페이스도 수정해야 함코드 탐색의 어려움예시 2. 너무 이른 추상화정보가 숨겨지기 때문에 복잡도가 높아진다.후대 개발자들이 선대의 의도를 파악하기가 어렵다.은탄환은 없다클린 코드도 은탄환이 아니다.실무에서의 줄다리기지속 가능한 소프트웨어 품질 VS 기술 부채를 안고 가는 빠른 결과물 -> 클린 코드를 대비한 코드 센스가 필요하다.모든 기술과 방법론은 적정 기술의 범위 내에서 사용되어야 한다.항상 정답인 기술은 없다.한계까지 연습해보고, 적정 수준, 적정 시점을 깨닫는 것이 필요하다.섹션 3. 단위 테스트단위 테스트작은 코드(클래스 또는 메서드) 단위를 독립적으로 검증하는 테스트 -> 가장 기본이 되는 테스트검증 속도가 빠르고, 안정적수동 테스트, 자동화 테스트 -> 인지 필요사람이 검증하는 수동 테스트 -> sout으로 출력하고 눈으로 직접 확인기계가 검증하는 자동화 테스트Junit5, AssertJJunit5 : 단위 테스트를 위한 테스트 프레임워크AssertJ : 테스트 코드 작성을 원할하게 돕는 테스트 라이브러리 - 풍부한 API 메서드 체이닝 지원해피 케이스, 예외 케이스 -> 테스트 케이스 세분화예외 케이스 : 암묵적 혹은 드러나지 않은 요구사항에서 발견경계값 테스트범위, 구간, 날짜 경계값들로 테스트를 해야한다.테스트하기 쉬운/어려운 영역 (순수함수)테스트 하기 어려운 영역을 구분하고 분리하기외부로 분리할수록 테스트 가능한 코드는 많아진다.테스트하기 어려운 영역관측할 때마다 다른 값에 의존하는 코드 : 현재 날짜/시간, 랜덤 값, 전역 변수/함수, 사용자 입력외부 셰계에 영향을 주는 코드 : 표준 출력, 메시지 발송, 데이터베이스에 기록하기순수 함수 - 테스트하기 쉬운 영역같은 입력에는 항상 같은 결과외부 세상과 단절된 형태lombok@Data, @Setter, @AllArgsConstructor 지양양방향 연관관계 시 @ToString 순환 참조 문제섹션 4. TDD: Test Driven DevelopmentTDD 테스트 주도 개발 (Test Driven Development)로, 프로덕션 코드보다 테스트 코드를 먼저 작성하여 테스트가 구현 과정을 주도하도록 하는 방법론선 기능 구현, 테스트 작성의 문제점 (일반적인 개발) - 구현순서 : 기능 -> 테스트테스트 자체의 누락 가능성해피 케이스만 검증할 가능성잘못된 구현을 다소 늦게 발견할 가능성선 테스트 작성, 기능 구현 (TDD) - 구현순서 : 테스트 -> 기능복잡도(유연하며 유지보수가 쉬운)가 낮은 테스트 가능한 코드로 구현할 수 있게 한다.테스트가 힘든 코드를 위한 코드 작성이 가능예를 들면 LocalDateTime.now()의 경우 외부세계로 분리해서 테스트를 하기 편한 코드를 작성할 수 있다.프로덕션 코드를 작성한 후 테스트 코드를 작성하기 귀찮을수도..쉽게 발견하기 어려운 엣지 케이스를 놓치지 않게 해준다.구현에 대한 빠른 피드백을 받을 수 있다.과감한 리팩토링이 가능해진다.테스트 코드가 보장TDD의 관점이전의 관점 : 테스트는 구현부 검증을 위한 보조 수단변화된 관점 : 테스트와 상호 작용하며 발전하는 구현부레드 - 그린 - 리팩토링Red : 실패하는 테스트 작성Green : 테스트 통과 하는 최소한의 코딩Refactor : 구현 코드 개선 테스트 통과 유지애자일 방법론 vs 폭포수 방법론애자일 방법론 https://agilemanifesto.org/iso/ko/manifesto.html반복적 개발(Iterative Development): 짧은 개발 주기(스프린트)를 반복하며 지속적으로 개선.유연성: 요구사항 변경을 수용할 수 있도록 유동적으로 진행.고객 참여: 개발 과정에서 지속적인 피드백을 반영하여 사용자 중심 개발 가능.자율적인 팀 구성: 개발팀이 자체적으로 의사 결정을 하며, 빠르게 문제를 해결함.폭포수 방법론단계적 개발: 요구 분석 → 설계 → 구현 → 테스트 → 배포 → 유지보수 순서로 진행됨.문서 중심: 각 단계마다 문서화가 철저하게 이루어짐.선형 구조: 이전 단계가 완료되어야 다음 단계로 넘어갈 수 있음.변경이 어려움: 초기에 요구사항을 확정하면 이후 변경이 어렵고 비용이 많이 듦.익스트림 프로그래밍XP(Extreme Programming, 익스트림 프로그래밍)는 애자일 방법론 중 하나로, 빠른 개발 주기와 지속적인 피드백을 중심으로 하는 소프트웨어 개발 방법론이다. 고객의 요구사항 변화에 빠르게 대응할 수 있도록 짧은 개발 반복 주기(Iteration)와 강한 협업 문화를 강조한다.스크럼, 칸반스크럼애자일 프레임워크로, 일정한 스프린트 동안 작업을 계획하고 진행하는 반복적이고 점진적인 개발 방식이다. 짧은 개발 스프린트를 통해 빠르게 결과물을 만들고 지속적으로 개선하는 것이 핵심이다.1⃣ 백로그 작성 – 제품 백로그에 모든 요구사항을 정리2⃣ 스프린트 계획 – 스프린트 기간 동안 수행할 작업 선정3⃣ 스프린트 진행 – 개발 진행 및 매일 스탠드업 미팅4⃣ 스프린트 리뷰 – 개발 완료된 기능을 검토5⃣ 회고(Retrospective) – 개선점을 찾고 다음 스프린트에 반영칸반Workflow와 가시성을 중심으로 한 애자일 프레임워크로, 지속적인 개선과 작업량 관리를 중점적으로 다룬다. 작업을 시각적으로 표현하여 현재 진행 상황을 쉽게 파악할 수 있도록 합니다.1⃣ Backlog: 해야 할 작업을 모아둠2⃣ To Do: 현재 진행할 작업3⃣ In Progress: 진행 중인 작업4⃣ Review/Test: 리뷰나 테스트가 필요한 작업5⃣ Done: 완료된 작업섹션 5. 테스트는 []다.테스트 코드는 문서다.프로덕션 기능을 설명해주는 것이 테스트 코드 문서다.다양한 테스트 케이스를 통해 프로덕션 코드를 이해하는 시각과 관점을 보완할 수 있다.고민했던 내용(테스트 코드)을 팀 자산(소스 코드)으로 공유할 수 있다.@DisplayName - 도메인 정책, 용어를 사용한 명확한 문장메서드명만으로 어떤 것을 검증하고자 하는 의도 파악이 어려움Junit5에 추가한 어노테이션이다.문장 형태로 섬세하게 테스트 검증에 대한 내용을 어노테이션안에 작성한다.섬세한 DisplayName특정 시간 이전에 주문을 생성하면 실패한다. ❌영업 시작 시간 이전에는 주문을 생성할 수 없다. ✅도메인 용어를 사용하여 추상화된 내용을 담기 -> 메서드 자체의 관점 보다 도메인 정책 관점 (특정 시간 -> 영업 시작 시간 ✅)테스트의 현상을 중점으로 기술하지 말 것 (~실패한다 ❌)Given / When / Then - 주어진 환경, 행동, 상태 변화Given : 시나리오 진행에 필요한 모든 준비 과정When : 시나리오 행동 진행Then : 시나리오 진행에 대한 결과 명시, 검증TDD vs BDDBDDTDD에서 파생된 개발 방법시나리오 기반한 테스트 케이스 자체에 집중하여 테스트한다.Junit vs SpockSpock은 Groovy언어로 BDD 패턴을 적용해서 테스트 코드를 작성할 수 있다.언어가 사고를 제한한다.명확하지 못한 테스트 코드는 사고를 제한할 수 있다.문서로서의 테스트를 신경 쓸 필요가 있다. 🏃 돌아보며..미션과 발자국을 정신없이 진행하다 보니 벌써 남은 인프런 워밍업 클럽도 2주밖에 남지 않았다. 처음에 OT 라이브 당시 러너가 120명 정도였는데, 이번 중간 점검 라이브 때는 60명 정도로 줄어들었다.강의 내용 자체는 어렵지 않지만.. 2개의 강의(14시간 + 12시간)를 한 달만에 들으면서 미션과 발자국을 진행하는 건 쉽지 않아 보인다.. 나는 미리 강의를 수강해서 다행이다라는 생각이 든다.. 😅하지만, 쉽지 않은 만큼 성실히 참여한다면 단기간 내 성장하는 데 큰 도움이 될 것이다.그리고 이번 주에 코드리뷰를 신청하기 잘했다는 생각이 들었다. 🍀 위에서도 여러 번 언급했지만 우빈님의 세심한 리뷰 탓(?)에내가 미션을 수행하는 데 있어 우빈님보다 세심하게 집착 했었나..? 반성하게 된다... 😭 마지막 주차 온라인 라이브에서도 테스트 코드에 대한 코드리뷰가 진행된다고 한다.기회가 된다면 또 한 번 코드리뷰를 받아 단골 손님이 되고 싶다. 😂2주를 걸쳐, 읽기 좋은 코드의 스터디 과정은 이번주로 막을 내렸다.다음 주차부터는 테스트 코드에 대해 본격적으로 스터디하는 과정이 진행된다.남은 2주도 화이팅하며 좋은 성장을 이루길 기대해 본다. 🔥 끝으로, 3월 중순이 되니 이제 슬슬 봄 내음이 나는 것 같다.. 🌸얼어붙은 개발 시장에도 봄이 찾아왔으면 좋겠다.. 🧊 발자국 2주차 끄읕 ! [출처]인프런 워밍업 클럽 : https://www.inflearn.com/course/offline/warmup-club-3-be-code강의 : 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

백엔드인프런워밍업클럽백엔드3기발자국박우빈클린코드읽기좋은코드

10 6개월 전
sein

[워밍업 클럽 4기 - 백엔드] 마지막 발자국

마지막 회고[Day 16] Presentation Layer(2)여섯 번째 섹션 중에서 제일 재밌게 학습한 날이 아닌가 싶다. 백엔드 개발자가 아니다보니 혼자 간단한 프로젝트를 만들어보고자.. 챗GPT를 스승삼아 개발했었는데 챗GPT가 항상 그렇듯 한 번에 완벽한 대답을 내주진 않는다. 챗 GPT가 HTTP 응답 메세지를 구조화하라고 알려줬지만, 정확한 답변은 주지 못한 상태에서 혼자 이것저것 찾아보다가 흉내만 내도록 구현했던 것 같은데 이번 챕터에서 ApiResponse를 마주하다니! 뜻밖의 이득이었다. 또한 Exception 처리도 @ControllerAdvice도 나름 혼자 사용해봤는데 만족할만한 결과물이 나오지 않았다. 사실 어떻게 하는지 개념이 잡히지가 않고, 눈으로 관련 코드를 본 적도 없어서 제대로 잘 적용할 수가 없었는데 이번 강의가 마치 나에게는 완벽한 정답처럼 다가왔다. 그래서 이번 강의는 엄청나게 눈을 반짝이면서 봤다.그 외에 제일 기억에 남았던 건 spring-validation이다. Reqeust Dto에서는 해당 필드의 타입이 유효한 값인가를 검증하게하고, 그 외에 도메인과 관련된 유효성 검사들은 좀 더 안쪽 내부에서 진행해야 된다, 즉 책임을 분리해야 한다는 지식이었다. [Day 17] Mock을 마주하는 자세Mock을 처음 접해봤는데 제대로 된 개념이 잡혀있지 않아 Mock과 Stub을 정확히 구분하고, 언제 써야하고, 어떻게 써야하는지 감이 잡히지 않았다. 조금 더 공부해봐야할 것 같은 주제다.그리고 Classicist와 Mockist 얘기를 듣고 나도 내 기준을 생각해 봤는데 Classicist가 맞는 것 같다고 결론을 내렸다. 완벽한 프로그램은 없는 것처럼 완벽한 Mocking도 없을 것이다. 그래서 Mocking 위주로 대부분의 테스트로 짠 프로그램이 진짜 객체를 마주했을때 과연 완벽하게 동작할 수 있을 것인가?를 생각해보면 아닐 확률이 더 크다고 생각한다.아무튼 Mock에 대한 건 좀 더 공부해보자. [Day 18] 더 나은 테스트를 작성하기 위한 구체적 조언되게 많은 주제들을 짤막하게 다루었다. 집중력이 그리 좋지 않은 나로서는 좋은 챕터였다. 그리고 꿀팁과 실무적인 관점을 배울 수 있었다. 이번 강의 전에 테스트 코드를 직접 짜보는 미션을 진행했었는데 직접 코드를 짰었을때 어려운 부분이나 '이게 맞나' 싶은 부분을 긁어주는 강의었다. 여러 개의 타입을 가진 Enum에 관련된 테스트를 진행했는데 한 가지 타입만 테스트하면 안 될 것 같아서.. 타입 검사하는 한 테스트에 모든 타입에 대한 given, when, then을 적었었는데 @ParameterizedTest라는 좋은,, 방법이 있어서 다음에는 고민만 하지말고 더 나은 대안을 찾을 수 있도록 구글에 한 번 검색해보자고 생각했다. 약간 부끄 [Day 19] 학습 테스트 | REST Docs테스트를 학습용으로 쓰다니! 내 입장에서는 놀라운 발상이었다. 앞으로 궁금한 라이브러리들은 마음놓고 테스트하면서 공부할 수 있게 됐다!REST Docs는 처음해봤다. 예전에 한 번 써본건 Swagger였는데 Swagger 쓰다가 REST Docs를 쓰니까 약간 어색하면서, UI가 뭔가 부족한거같으면서, 어렵다는 느낌을 받았다. 그래도 Swagger는 프로덕션 코드에 직접적으로 추가해줘야하는 코드들이 많았던 걸로 기억하는데 REST Docs는 테스트 코드 기반으로 만들어진다니 더 깔끔한 관리가 될 것 같다고 생각했따. [Day 20] 중간 점검마지막 중간 점검이다! 너무 아쉬워. 테스트 코드를 본격적으로 공부해본게 처음이라서 혹시나 내 질문이 이상한 질문일까봐, 너무 쉬울까봐 하지 말까했는데 내가 올리기 전까지 아무도 질문을 안올려서 나라도 일단 냅다 올리자 하고 올렸다. 용기내서 올린 질문은 나에게 100배의 좋은 지식으로 돌아왔다. 다음에는 더 용기가 생긴다면 코드 리뷰도 한 번 받아보고 싶다고 생각했다.다른 분들의 코드리뷰를 보면서 도대체 어떻게 저렇게 생각하고 저렇게 구현하지?라는 생각을 많이했다. 나도 우리 회사에서 나름 잘하는 사람 중에 하난데 여기 오니까 우물 안 개구리라 생각됐다. 더 많이 공부하고 나보다 더 잘난 사람들을 많이 접해야 내가 성장하는 것 같다.  마지막 회고워밍업 클럽은 되게 충동적으로 신청했다. 0기를 수료했었는데도 신청한 이유는 0기와는 전혀 다른 주제여서 뭔가싶어 쓰윽 봤는데 여태 한번도 배우지 않았던 주제지만 궁금은 했었던 주제여서 할인 코드도 주는 김에 신청했던 것 같다. 되게 가벼운 마음으로 신청했지만 무거운 뇌를 갖고 돌아가는 강의다. 추상화도 이렇게 본격적으로 코드에 녹여 본 것도 처음이고 테스트 코드도 작성은 해봤지만 그저 강의의 일부정도라 깊게 배우진 않았다. 게다가 내가 직접 내 머리로 생각해서 작성했던 건 아예 처음이었다. 처음인만큼 난이도가 초급이지만 나에게는 중급 정도의 난이도였으며, 솔직히 워밍업 클럽이 아니었다면 도중에 듣고 탈주했을 것만 같았다. 매일매일 힘내라고 말씀해주시면서 공지사항에 메세지를 보내주신 박우빈님 덕에 완주할 수 있었던 것 같다. 언젠가 백엔드로 직무 전환에 성공한다면 이번에 획득한 지식들을 가지고 실무에 적용해볼 수 있는 날이 왔으면 좋겠다. 그럼 우빈님한테 배웠다고 자랑해야지 ㅎㅎ다들 고생많으셨고 감사합니다!

백엔드워밍업클럽백엔드박우빈클린코드테스트코드

sein

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

3주차 회고[Day 11] 미션Day 11일에는 테스트 코드를 직접 작성해보는 미션을 진행했다. Readable 강의에서 지뢰찾기와 스터디 카페에 대한 테스트 코드를 3개 이상의 서로 다른 클래스 & 총 7개 이상의 테스트를 작성하는 미션이었다. 객체지향으로 리팩토링 했었던 지난 미션보다는 시간이 적게 걸렸지만, 이번 미션도 여전히 생각할 거리가 너무 많았다.고민을 많이 했던 부분은 전체적으로 테스트를 작성할 수 있는 시간이 물리적으로 부족했기 때문에 선택과 집중을 해서 정말 테스트가 필요할만한 부분에 적용해보고 싶어 어떤 클래스를 선정할지 생각을 많이했다.또, 단위 테스트 위주로 할지 7개만 작성하니까 통합 테스트 격으로 할지도 많이 고민했는데 테스트를 작성하는 실력이 그리 뛰어나진 않아 처음부터 천천히 하기로해서 단위 테스트 위주로 짰던거 같다.이번 미션도 역시 재밌었다! [Day 12] Persistence Layer이번 챕터에서는 전체적인 레이어드 아키텍처 Presentation, Business, Persistence Layer들에 대한 간략한 설명과 통합 테스트의 정의, 그리고 앞으로 개발할 프로젝트의 설계에 대해 배웠다. 강의를 들으면서 느낀 건 강의가 정말 초보자 위주로 짜여져 있다는 것이다(positive). Library와 Framework의 차이점, spring의 대표적인 기술, ORM 등에 대한 설명들을 테스트 강의에서 들을 줄은 몰랐는데 초보자는 아무래도 반복학습이 중요하다보니 이런 기초적인 것들을 하나씩 짚어주셔서 개념을 다시 바로 한 번 더 잡기에 좋았다. 제일 기억에 남는 건 테스트를 작성할 때 클래스 레벨에 @SpringBootTest와 @DataJpaTest 어노테이션이다.SpringBootTest스프링 부트 컨텍스트를 로드한다.웹 환경, 서비스, 레포지토리, 컴포넌트 등 모든 Bean을 실제처럼 사용할 수 있다.DataJpaTestSpringBootTest에서 JPA 관련 컴포넌트만 로드 되게끔 경량화슬라이스 테스트로 빠르게 JPA 레이어만 검증할 때 사용된다.@Service나 @Controller등의 Bean이 로드되지 않는다. [Day 13-14] Business Layer이번 섹션에서는 비즈니스 로직이 메인인 Business Layer에 대해 알아보고, 코드를 구현했다.비즈니스 레이어는 비즈니스 로직을 구현하는 레이어고, Persistence와의 상호작용을 통해 비즈니스 로직을 전개시키며, 트랜잭션을 보장(원자성)해야 한다. 이번 코드 구현에서는 고객이 주문을 할 수 있는 Order, Stock의 전반적인 부분을 개발했다. 코드를 구현하면서 드는 의문점은 여태 다른 강의를 들을 때 상품의 재고 관련한 데이터는 Product에 필드로 관리했는데 이 강의에서는 별도의 엔티티로 따로 빼준게 의아했다. 혼자 생각해봤는데 Stock의 데이터는 최대 품절, 아니면 재고 현황(숫자)만 보여주면 될 것 같았기 때문이다. 그래서 질문을 냅다 올리려다 다른 사람이 비슷한 질문을 한게 있나 찾아봤는데 있어서 읽어봤더니 아하!하게 되었다.관련 질문 : stock을 entity로 분류하는 이유 [Day 15] Presentation Layer(1)이번 섹션에서는 마지막 레이어인 Presentation layer를 구현하고 테스트했다. Presentation Layer는 외부 세계의 요청을 가장 먼저 받아들이는 계층이며, 받은 파라미터에 대해 최소한의 검증을 수행해야한다. 추가적인 요구사항에 대한 테스트를 작성하고 개발을 하면서 @Transaction에 readOnly란 속성에 대해 배웠다.대부분의 서비스는 CRUD 중에 읽기인 'R' 비중이 매우 높다. 그래서 Read와 CUD(command) DB를 슬레이브(R) / 마스터(CUD)로 분리해서 장애를 격리하는 방식을 추천한다고 하셨다.코드 상에서는 일단 클래스 레벨에 무조건 @Transactional을 주는게 아니라 전체적으로 readOnly = true 속성을 먹게끔 작성하고, CUD 작업이 있는 메서드에만 따로 @Transactional을 붙여주는게 성능 상으로도 더 좋다고 말씀해주셨다.@Transactional(readOnly = true) public class service { @Transaction public void save {} } 3주차 회고초보자 입장에서는 TDD로 테스트부터 개발까지 모든 과정을 함께 참여할 수 있어서 나에게 더 좋은 경험으로 다가온 강의였다. 시간은 좀 길었지만 그만큼 얻는 것도 많아 아주 유익했다. 다음에는 강의 없이 혼자서 간단한 프로젝트를 TDD 기반으로 만들어보고싶다! 이번주도 열공😄 출처인프런_워밍업_클럽_4기_BEPractical Testing: 실용적인 테스트 가이드

백엔드워밍업클럽백엔드박우빈테스트

sein

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

2주차 회고[Day 6] 리팩토링: 코드 다듬기이번 챕터에서 제일 기억에 남는 건 '주석'이었다. 주석 사용 법은 배웠지만 좋은 주석은 처음 알게된 개념이라 도움이 많이 됐다. 실무에서도 개발하기 급급해서 기존에 있던 주석까지 신경쓰지 않았었는데 주석과 코드는 한 몸이라 생각하고 앞으로 꼼꼼히 봐야겠다고 생각했다.그리고 키워드 정리 시간에 지뢰찾기에 앞으로 추가해볼 수 있는 기능들을 몇몇개 말해주셨는데 내 힘으로 기능들을 추가해보는 시간을 가져도 좋을 것 같다. [Day 7] 클린코드 리팩토링 실습(미션)이번 챕터는 온전히 미션을 위한 날이었다. studycafe 패키지에 작성된 코드를 읽어보고, 추상화 해보는 미션을 진행했다.고작 조각 코드인 몇 줄 짜리가 아니라 더 어렵긴 했지만 더 생각할 수 있었던 것들이 많아서 좋았다.코드를 다 읽어보고 난 후에 여태 배운 추상화 기법들이 머릿속을 스쳐지나갔다. 이 부분에서 뭘 하면 좋을 것 같은데?! 정도의 생각이 들었다. 다만, 구현으로 실천하기가 매우 어려웠다. 생각과 구현 능력이 절실히 필요하다고 생각했다. 시간 상의 문제로 완벽히 추상화를 하진 못했지만 그래도 백지에서 추상화를 진행해본적이 처음이라 어렵지만 재밌었던 시간이었다. 추후 중간 점검 때 코드 리뷰에서 정말 많은 것을 얻었다. 각자의 실력도 다르지만 각자의 생각도 다르고, 관점도 달랐다. 그래서 배운 게 두 배, 아니 세 배 더 많아진 것 같다! [Day 8] 리팩토링 연습 | 기억하면 좋은 조언들studyCafe를 처음부터 끝까지 우빈님과 함께 진행했다. 순전히 내 뇌로는 닿을 수 없는 부분까지 닿을 수 있었던 거 같았다. 이래서 '나를 이끌어 줄 상사가 중요하구나'를 느꼈다.추상화도 어렵지만 오버 리팩토링이 너무 어려운 것 같다. 오버 리팩토링이 되는 시점을 정확히 캐치할 수 없다보니 그냥 둥둥 뇌 속에 떠도는 구름 같은 개념을 보는 것 같다. 우빈님이 말씀하신대로 오버 리팩토링은 경험에 의해서만 얻을 수 있다고하니 추상화를 많이 도전해보는 것이 중요하다고 느꼈다.실무에서도 추상화를 많이 접할 수 있으면 더 좋았을 것 같은데 그러지 못한 환경에 조금 갈증을 느끼며 오늘도 이직 단단히 다짐한다. Readable Code : 읽기 좋은 코드를 작성하는 사고법 강의가 막을 내렸다. 혼자서 도전했으면 어려움에 어지럼증을 느껴 끝까지 완주하지 못했을 것 같은 강의었다. 워밍업 클럽 덕분에 포기하지 않고 한 강의를 완강할 수 있어서 참으로 감사함을 느낀다.  [Day 9] 단위 테스트 | TDD | 테스트는 []다새로운 Practical Testing 테스트 강의를 시작했다!이번 챕터에서는 기본적인 테스트에 대해서 알게 되었고, TDD, BDD에 대해 얘기 나누었다. TDD는 말로만 들어봤었는데 강의에서 TDD 방식으로 코드를 짜나간다고 하시니 약간 생각지도 못한 이득 본 것 같아 엄지를 들었다.  강의를 계속 들으면서 느끼는 점은 코딩 실력도 중요하지만 언어 능력이 중요하다는 걸 엄청나게 많이 깨닫는다. 코딩은 사람이 컴퓨터에게 하는 언어라 컴퓨터가 못 알아 들으면 에러도 내주고 테스트 통과도 시켜주는데 사람이 하는 언어는 내가 뱉은 말을 정말 다양하게 해석할 수 있는 여지가 있어 정확하고 확실한 언어로 내 생각과 코드를 전달해야 정말 실력 있는 개발자인 것 같다.앞으로 그런 개발자가 되도록 노력하자!  출처인프런_워밍업_클럽_4기_BEReadable Code: 읽기 좋은 코드를 작성하는 사고법Practical Testing: 실용적인 테스트 가이드

백엔드워밍업클럽백엔드박우빈클린코드테스트

sein

[워밍업 클럽 4기 - 백엔드] 1주차 발자국

1주차 회고[Day 2] 추상과 구체이번 챕터에서 가장 와 닿았던 키워드는 '읽기'다. 사실 코딩을 하면서 '읽기 좋은 코드'를 작성하기 보다는 별 생각 없이 '원하는 요구사항에 맞춰 개발하면 됐지'라는 생각이 커서 내 코드를 읽을 후손들은 생각지도 못한 채 개발을 했었다. 그렇다보니 강의를 듣는 내내 처음 해보는 생각들이라 시간이 많이 더뎌졌다.추상화 레벨 파트를 들으면서 메서드를 이렇게 잘게 쪼개본 적이 없어서 많이 당황스러웠다. 여태 라인 수에 따라 돈을 내는 것도 아닌데 전체적인 라인 수를 줄이려고 노력했지 메서드를 잘게 쪼개는 형식으로 개발한 건 처음이었다.이론적인 공부도 중요하지만, 코드를 가독성 좋게 잘 짜는 사람의 코드를 경험하고, 이해하고 작성해보는 시간이 개발자에게 엄청난 경험을 안겨주는 것을 실감했다. [Day 2] 미션미션 링크처음 만난 미션은 어려웠다(1번 제외). 추상과 구체를 스스로 생각해본 적이 없었기 때문이다. 흔히 아는 붕어빵, 자동차, 동물 이런 예시들을 듣고, 적용하기만 해봤지 추상과 구체를 자세하게, 특히 레벨 별로 나눠서 생각해 본 적은 정말 없어서 꽤 오랫동안 생각에 잠겼다.내용을 적어 내려가면서 '이게 맞나?'싶었다. 왜냐면 내가 나름의 추상 레벨로 구분 해 놓은 것들이 사실 파고들면 파고들 수록 더 깊게 구체화 시킬 수 있었기 때문이다. 어떻게 나눠야 적정 레벨로 나눌 수 있는지가 참 애매했던 것 같다. 정답은 없는 것 같다고 결론 내렸다. 다만, 이 능력을 키워갈 수는 있을 것 같다. 처음 시작이 어렵지 앞으로 추상과 구체를 레벨 별로 잘 나누어보는 연습을 해야겠다. [Day 3] 논리 사고의 흐름 | 객체 지향 패러다임나에게는 이 챕터가 제일 곤욕이었다. 재직자라 수업을 들을 수 있는 시간은 한정적인데다 다음 날에 미션까지 있어 마음이 너무 조급했다. 퇴근하고 듣는 수업은 눈이 감기기 일쑤였다. 그래서 복습이 매우매우 필요한 챕터라고 생각한다.그래도 기억 나는 것들을 적어보자면 '평소에 내가 생각하지 못했던 것들'이었다. 나는 대단한 개발자가 아니다. 그래서 스스로 'Early return'이나 'depth 줄이기' 등과 같은 내용을 생각하지 못한다. 이번 챕터에서 가장 많이 배웠다고 해도 무리가 없다.객체 지향 패러다임도 많이 배웠다. 단순히 이론만이 아닌 리팩토링하는 실습까지 같이해서 많이 배운 것 같다. 물론 혼자 스스로 적용해보기엔 아직 무리지만. 객체 지향 패러다임에서는 'getter'와 'setter'를 자제하란 내용이 신기했다. Setter의 지양은 너무 많이 알려져있는 내용이라 그러려니 했지만 Getter의 경우는 처음 듣는 얘기었다. Entity를 생성할 때 Lombok으로 @Getter를 만들고 보는 내 입장에선 배울 게 정말 많았다.이번 챕터는 배워서 바로 쓰기에는 조금 어려운 내용이지 않았나 싶다. 앞으로 배운 내용들을 복습하고, 새로운 곳에 적용해보는 연습이 필요할 것 같다. [Day 4] SOLID그 유명한 SOLID에 대해 공부했다. 내용들은 워낙 유명하니 굳이 적진 않겠다. SOLID는 유명하지만 코드에 적용하기는 매우 어려운 내용이다. 각종 블로그에서 보이는 짤막한 코드 조각을 보면 이걸 어떻게 실무에 적용할지 약간 까마득해진다. 우빈님 강의에서는 짧지 않는 코드를 SOLID의 각 내용에 맞춰 점진적으로 리팩토링하니까 더 이해가 잘 됐던 것 같다. 물론 초보가 따라가기엔 어려웠지만 내가 그리 갈망하던 초급 -> 중급으로 넘어갈 수 있는 실력을 좀 갈고 닦은 느낌이 들었다. [Day 4] 미션미션 링크이번 미션도 시간이 오래 걸렸다. 실제로 리팩토링하는 부분이 있어서 많은 고민을 했던 것 같다. 솔직히 다른 분들의 코드를 참고하기도 ㅎ 했다. 뭐.. 그러면서 실력이 느는 것 아닐까?!(뻔뻔) 그래도 양심적으로 조그만 부분만 참고했다. 제시된 메서드만 간단하게 리팩토링해보기엔 내 실력을 믿고 검증할 수가 없어서 코드가 돌아가게끔 최소한으로 class들을 만들고 실행시켜봤더니 마음이 한결 편해졌다.어려웠긴 했지만 코딩을 직접적으로 하는 미션이 너무 재밌어서 시간 가는 줄 모르고 했다.이런 미션이 또 나왔으면 좋겠다. [Day 5] 객체 지향 적용하기나는 '상속' 밖에 몰랐고, '상속'이 객체 지향의 꽃인 줄 알았다. 근데 실무에서는 잘 쓰지 않는다니! 또 충격을 받았다. 충격을 5일째 받으니 머리가 어질어질.. 요즘엔 '상속'보다는 '조합'을 더 많이 쓴다고 한다. 어쩐지 내가 '상속'으로 개발했을 때 조금이라도 변경이 생기면 머리가 아프더라..! 이런 가려운 부분을 잘 긁어주셔서 참으로 감사했다. 종합적인 회고그저 배운게 많았던 한 주였다. 복습이 필요함을 느꼈고, 내가 많이 부족하다는 것도 느꼈다. 이 강의를 통해 좀 더 나은 개발자가 되길 소망한다. 화이팅! 출처인프런_워밍업_클럽_4기_BEReadable Code: 읽기 좋은 코드를 작성하는 사고법

백엔드워밍업클럽backend박우빈

인프런 워밍업 클럽::네트워킹 데이

12월 13일 워밍업 클럽 수료자들을 대상으로 하는 네트워킹을 갔다왔다.주요 세션은 두 가지 내용이지만, 공통 관심사는 커리어였다.사실 우리가 공부하는 이유는 커리어 때문인걸까? 고민이 상당히 되었다.물론, 나의 인정이 커리어에서도 나오기는 하지만 더 나은 개발자 그리고 영향을 주는 개발자가 되고 싶어서 끊임없이 공부를 한다.네트워킹을 하면서 느낀 것은 여러가지가 있지만, 가장 크게 하나였다."더 잘하자" 이제 부터 간단하게 네트워킹 데이의 좋은 점과 아쉬운 점을 적어보려고 한다.좋은 점밥이 너무 맛있다...?? 솔직하게 편식이 너무 심한편인데 닭강정이 너무 맛있었다.근데, 네트워킹 데이말고 전에 워밍업클럽 수료식 때는 맥주가 있었는데...ㅋㅋㅋ하지만, 전반적으로 인프런 직원분들이 고생을 하고 준비하신게 보여서 감사했다.강의 내용이 알찼다.준비와 구성이 훌륭했다.스피치의 전달력과 그에 대한 화법들이 상당히 좋았다.특히나 모두가 관심있어할 만한 주제를 한 번에 꿰뚫는 관통력은 매우 좋았었다.1부 네트워킹 세션같은 직군끼리 모여서 서로 이야기를 할 수 있다는게 좋았다.같은 직군이다 보니 서로 공통 관심사를 관통시켜 이야기를 하고, 다양한 주제를 서로 나눠가지면서 이야기를 할 수 있었다.또한, 인프런 직원분들도 군데 군데 있어서, 하나의 공통관심사를 꿰뚫게 만드는 점도 좋았다. 아쉬운 점1. 사진을 안찍는다...직원들의 고군분투에도 ㅠㅠ 사진을 안찍어주시는 분들이 많았다물론 나도~~ ㅋㅋ사실 같이 간 동료들하고 사진을 찍고 싶었는데, 아무도 안찍으려했다..속상 😢2. 시작 -> 끝? 무슨 모임이든 끝이 있기 마련이지만, 갑자기 어... 끝? 그런 느낌이 강했다.시작에 대한 부분은 명확했지만, 끝은 너무 약간 엄... 대관시간때문인거는 아는데, 몇 분전에 끝을 고지해주고 토픽에 대한 마무리를 하면서 네트워킹을 마무리 하는게 좋았는데 그게 아쉬웠다...또한, 고생한 직원들과 그런 시간도 조금 있으면 좋겠는데 갑자기 서둘러서 나가는 분위기라 아쉬웠다!3. 2부 네트워킹 세션 일단, 당연하게 어떤 네트워킹도 항상 만족을 주는 것을 불가능하지만 2부 네트워킹 세션은 돌아보니 실망이 있었다.특히나 우리팀은 백엔드 전원에 한 명만 취준생인 프론트 개발자가 있었는데, 이것은 사실 인프랩 주최측의 잘못이라기 보다는... 그냥 뭐 ㅋㅋㅋ 네트워킹 하려는 사람들이 잘못인거 같다.배려가 없었다.공통 관심 주제를 캐치하고 다 같이 이야기를 해야하는데, 너무 의욕적으로 자신이 궁금한 주제만 이야기하는 시간이되어서 몇몇은 소위 말하는 꿔다 놓은 보릿자루가 되었다...결론다음에 갈거야? 라고 물어봤을 때 대답은 가야지! 라는 대답이다.뭐든 좋은거 아쉬운거 다 있지만, 결국 한 단계 도약하는 기회와 내가 원하는 이상향과 현재 위치를 가늠해 볼 수 있는 좋은 기회였다.뭐... 그리고 평소 말이 많은 성격이라 궁금한 것들도 다 어느정도 해소했고 ㅋㅋ끝으로는 상 받았다~~!! (저는 나호진이 아니에용 ㅠㅠ... 발음이 안좋다 내가 ㅠㅠㅠ)

네트워킹워밍업클럽인프런

빠타박스

[인프런 워밍업 클럽 2기 - CS] 지난 3주간의 여정 속에서 - 완주 후기

처음 이걸 왜 들었을까?이 과정을 듣기 2일쯤 됬던가. 벤처 게임회사에 면접을 보았다.그 회사의 면접은 그냥 말아먹었다.그 이유는 역시 기초 지식이다.  공부한지 어연 5년이 다된간다. 이쯤되면 게임개발이라는 것을 포기할만도 했다...어떻게 해야할까 하는 찰나에 인프런에 들어와 여느때 처럼 그냥 공부를 하고자 한숨을 내쉬며 들어왔는데바로 보이는... CS 이게 무슨일이지 하면서 한번 볼까? 무료라고?아.. 근데 아니였다... 기본적으로 할인을 해주나 로드맵에 있는 수강내역을 구매해야만 참가가 가능했다.나는 좀 아쉬웠다.. 가뜩이나 백수 5년째 거금을 들이기가 선뜻 겁이 났다... 그렇게 많은 돈은 아닐 수 있었지만... 나에게는 식비와 공과금을 충당해야만 하는 비용이였기 때문이다.하지만 면접에서 탈탈 털린 나로써는 CS지식이 시급했다... 나에겐 여러 장애물이 있었다...자격증 시험이였다... 항상 내 발목을 묶는 장애물이였다.이 과정을 진행하면서 실기일이 얼마 남지 않은 상태였다... 그럼에도 불구하고 CS 지식을 터득하자. 하지만 가볍게 보고 다음에 다시 보도록 하자는 마인드였다.(내가 반복하는 걸 싫어하다 보니까... 이게 참 문제다... )그렇게 그냥 열심히 했다...그냥 할 수 있는 만큼...  공부는 어떻게 해야 하죠? 난 솔직히 아직도 개발 공부란 것을 어떻게 해야할 지 모르겠다...그냥 받아적고 천천히 느리게 한다. 하나 볼때 최대한 이해하려고 다 적는다.하지만 남는게 별로 없다...반복학습이 생명인 것을 알겠다..ADHD를 겪고 있던 나로써 반복학습은 정말 지겨웠다.. 그래도 반드시 해내자 라는 마인드로 임했다...그렇게 공부한 것들을 필기하고 요약하려고 하였지만 쉽지 않았고, 최대한 가볍게 이해하려고 했다. 가장 어려웠던건 알고리즘 부분이였다... javascript로 하다보니 C++로 변환하려니까. 뭔가 비슷은 한데 헷갈리는 부분이 많았다... 안되던 것도 있었고,,,... 쉽지 않았다... 정처기 얼마 남지 않았는데 계속 붙들고 있는 경우도 발생했다그게 1주차 때이다. 그냥 무작정 하라는 대로 하였다. 최대한 깊어보이면서 간결하게다른 사람들이 쓴 것도 보았으면 좋았겠지만. 쓰고 바로 정보처리기사 공부를 해야만 했다. 18일 금요일 모든 과정이 종료 되었고, 이제 수료식만을 남겨둔채 나는 정보처리기사 공부를 집중했다.10월 20일 일요일 정보처리기사 D-Day...,..실기는 매우 어려웠었고 조졌다.... 그렇게 돌아와 낙심에 빠졌다... 그리 며칠 가지 않아서하.. CS 관련해서 심화적으로 봐야만 한다는 것을 어떻게 할까 하다가.최대한 쿠폰을 사용해서.. 보고 싶은데 해서 결국 구매를 강행했다..아직 보진 않았다. 왜냐하면 이전꺼도 다시한번 봐야만한다.다시 반복학습을 해야만 하니까. 이 과정이 끝나고 정말 운수 좋은날인가... 아는 분을 통해 일자리를 얻게 되었다...처음에는 어리둥절했다... 뭔지도 모르고 뭘 시킬지도 모르는데... 게임개발만 3년 정도를 팠다....언리얼엔진....갔더니 대표님이 언리얼엔진에 대한 이전 문제 때문에 나를 궁금해 하셨고 그일을 나에게 맡기셨다..부담스럽기도 하고 기회다 하며 재밌겠다 하며 그 기회를 붙잡았다...11월 4일 부로 출근하게 되었다. 그래서 언리얼엔진 심화 및 기초에 대한 내용을 공부하고 있어서 해당 자료구조를 못보고 있었다.  수료식그렇게 11월 1일(금)원래대로면 오프라인에 참석해야 하나.. 나의 직업군인시절 후유증으로 인해...갑자기 도져서 가지 못한다고 말하게 되었다...시작된 워밍업 클럽 수료식 과정중 코치님 감자 강사님께서 나오셔서 질의 응답 시간을 가졌다.유익한 시간이였고 좋은 정보도 얻었다. 추천 받은 책 : CODE (컴퓨터 구조에 대한 내용 밑바닥?)https://elfmfl.tistory.com/33 (펌 정보) 난 아직도 많은 공부를 해야만한다는 것을 느꼈다. 저곳에 모인 사람들 중에 분명 나보다더 대단한 사람도있고젊고 파릇파릇한 분들도 있을테고 여럿 사람들이 모였었을 것이다.부러웠다.. 저 자리에 위치할 수 있어서...하지만 또 나름 나의 시간을 아끼며 공부를 했다. 그렇게 질의응답시간이 끝나고 수료식의 대망의 수상 발표이다. 응?뭐지.. 적어도 26~30명 정도 CS 과정을 들었던거 같은데.. 우수러너에 뽑히게 되었다....다들 수상을 하고 있을 때 그저 축하해주기 위해서 남아있었는데.내가 수상하게 될 줄 은 꿈에도 몰랐다. 그래서 이 감사를 어떻게 해야 할지 바로 누군가에게 자랑을 했다. ㅎㅎ;;감사한 하루였다. 앞으로 어떤 과정이 또 생길지 모르겠다.하지만 이제 일을 시작했고, 이 일을 완벽히 하기 위해 더더욱 기초가 다져져야 한다.이 과정과 고난의 길 위를 즐기자. 기쁨으로 하루를 살아가자 이 과정을 겪을 수 있어서 감사합니다.인프런을 통해 많은 청년들이 새 꿈을 이룰 수 있게 해줬으면 좋겠다. " 모든 것의 가장 빠른 배움은 부딪히는 것이다. 그게 밑바닥이 되었든.가장 좋은것은 프로젝트를 하고 현업처럼 부딪히는 것 "     이제 다가올 2025년도를 위해인프런 공부를 하며 여러 사건과 여러 정치적인 이슈들이 있었다.우리는 내일을 위해 무언가를 지켜야 하고 싸워야 하는 경우가 생길 것이다.그저 지금 편안하게 우리가 공부할 수 있는 것은 누군가 희생되고 있음을 깨달아야 한다. "모든 일에는 당연한 것이 없다" 누군가의 배품, 누군가의 선함, 누군가의 악행,모든 것에는 이유가 있다. 포괄적차별금지법북한군파병이스라엘과 하마스 및 헤즈볼라윤모의 자금 횡령 및 국가비상금 빼돌림 여러 이슈들이 존재 한다. 우리는 공부하면서 깨어있어야 한다. 우리 미래가 결정되고우리 후대의 미래가 결정된다.해외 부자들 CEO들이 우리나라의 급격한 인구가 줄어드는 것을 바라보고 있다..대책이 없다... 그저 장막 안에서 보호를 받으면서 공부를 하는것도 그렇지만. 나라가 없어지면..공부도 무의미 하다... 깨어있는 공부를 하자. 부디 25년도에는 많은 것들이 청렴해지고 나아지길 바란다. 끝없이 성장하는 개발자가 되고생존하자. 버티며 끝까지 임하자 최선을 다하자. 내일 죽는한이 있더라도 자신의 위치에서 최선을다하자

알고리즘 · 자료구조인프런인프런워밍업클럽스터디2기자료구조알고리즘감자워밍업클럽

대롱대롱

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

드디어 스터디의 마지막 발자국을 작성하는 날이 왔습니다. - 이번주에 공부한 내용의 키워드 - 운영체제컴파일과 프로세스메모리-레지스터, 캐시, 메인메모리, 보조저장장치절대주소/상대주소가변분할/고정분할가상메모리동적주소변환세크멘테이션 분할방식/페이징 분할 방식스레싱/워킹셋여러가지 주변장치(입출력 디바이스와 저장장치)하드디스크파일과 파일시스템디렉토리디스크 자료구조와 알고리즘버블/선택/삽입/병합/퀵 정렬동적 프로그래밍(메모이제이션/타뷸레이션) - 이번주에 공부한 내용 요약 - 운영체제메모리는 가장 빠른 레지스터, 데이터 임시 저장하는 캐시, RAM이라 불리는 메인메모리, 그리고 보조기억장치가 있습니다. 물리주소는 말 그대로 물리적인 메모리 주소이고 논리주소는 사용자 관점에서 본 상대적 주소입니다. 메모리 할당방식으로는 가변분할방식과 고정분할방식이 있습니다. 현대에서는 두 가지 방식을 모두 사용하여 단점을 최소화하는 버디시스템을 사용합니다.가상메모리는 컴퓨터의 물리적 메모리의 크기를 확장하기 위해 사용되는 기술입니다. 동적주소변환은 메모리관리자가 가상메모리의 논리주소를 물리주소로 변환하는 것을 의미합니다.논리주소를 물리주소로 변환할 때 세그멘테이션 분할 방식은 메모리 관리자가 논리주소를 세그멘테이션 테이블을 이용해 물리주소를 찾고, 페이징 분할 방식은 논리주소를 페이지 테이블을 이용해 물리주소를 찾습니다.프로세스가 가상메모리에 접근요청 했을 때 물리메모리에 데이터가 없다면 페이지 폴터라는 인터럽트가 발생합니다. 이 때 HDD의 스왑영역에 있는 데이터를 메모리에 올리는 작업이 수행됩니다.스레싱은 페이지폴트가 발생해서 CPU사용률이 0에 가깝게 떨어지게 되는 현상을 의미합니다. 워킹셋은 메모리에 올라온 페이지를 하나의 세트로 묶어 메모리에 올리는 것을 의미합니다.주변장치들은 메인보드에 있는 버스로 연결되어 있으며 두 개의 채널과 두개의 버스로 구분합니다.파일관리자는 운영체제가 파일을 관리하기 위해 필요한 존재입니다. HDD나 flash memory는 블록 디바이스로 전송단위가 블록이지만 사용자는 바이트 단위로 파일에 접근해야 해서 파일관리자가 중간에서 관리해야합니다.파일은 순차파일구조, 직접파일구조, 인덱스파일구조가 있습니다.관련있는 파일을 모아두기 위해 필요한 것이 디렉토리입니다. 자료구조와 알고리즘정렬에는 크게 5가지 방식이 있습니다간단해서 구현은 쉽지만 성능은 좋지 못한 버블, 선택, 삽입 정렬과 이들보다 상대적으로 성능이 좋은 병합정렬과 퀵정렬이 있습니다.동적프로그래밍 방식으로 메모이제시녀과 타뷸레이션이 있습니다.메모이제이션은 계산결과를 기억하며 재귀를 사용합니다. 하향식 계산방식입니다.타뷸레이션은 계산에 필요한 모든 값을 계산하여 테이블에 저장하고 상향식 계산방식입니다.- 이번 주 회고 겸 스터디 회고 - 눈 깜짝할 사이에 스터디 마지막이 되었습니다. 완주를 위해 달려왔는데 목적했던 바를 이루어서 뿌듯합니다. 개인적으로 따로 다른 분들과 스터디를 했는데 운이 좋게도 열정적이고 좋은 분들을 만나 복습과 완강을 함께 할 수 있었습니다. 일주일에 세번씩 꾸준하게 디스코드 상에서 스터디를 했는데 아주 만족스러웠습니다. 덕분에 허물뿐인 완강이 아니라 제대로 공부하면서 완강을 하게 되었어요.이번주에는 중간점검도 있었는데 그 때 감자님께서 회고를 읽어보신다는 것을 알았습니다. 그동안 너무 주저리주저리 길게 쓰는 것은 지양해야겠다고 생각했는데 그냥 길~게 쓸걸 하는 아쉬움이 있습니다. 짧아서 심심하셨겠다는 생각이 드네요. 이번주 회고는 마지막인만큼 좀 분량 있게 써보겠습니다. 일단 이 CS스터디를 신청한 이유는 '그래도 개발의 길을 걷는 사람이 CS지식도 모르다니! 이럴 수는 없다!'는 마음이 있었기 때문입니다. 기본 지식은 쌓아야 한다는 생각이 강했어요(제가 운영체제 과목을 들은 적이 없습니다..^^;;). 그래서 제가 자주 하는 '일단 신청하자'를 시전했습니다. 왜 하필 이 강의를 선택했냐고 물으신다면 답은 하나입니다. 재미있어 보여서요. 저는 도파민중독자입니다. 일단 재미가 있어야 뭔가를 시작합니다. 감자님 강의를 보는데 애니메이션으로 설명하는 것이 너무 재미있어 보였어요. 이전에 '아 지금 공부하는 게 눈으로 보이면 좋겠다...'라는 생각을 했는데 이 강의가 딱 이 생각에 맞아버린 것이죠. 애니메이션으로 공부하니 재미있고 재미있으니 더 공부하고 싶고... 이런 선순환이 반복되어 어느덧 완강이라는 종착지에 다다르게 된 것입니다. 스터디원들과 스터디를 하다보니 발표자료도 만들게 되었는데 발표자료 만드는 것도 많은 정성을 기울였습니다. 남에게 보여야 하는 것인데 허접하게 만들 수는 없잖아요. 처음에는 노트앱에 기본으로 있는 템플릿을 썼는데 그 템플릿이 너무 마음에 들지 않았어요. 맘에 안들면 제가 만들면 됩니다(자급자족 라이프!). 그래서 만들어진 것이 '감자전용 템플릿'입니다. 귀엽게 디자인이 뽑혔고 이렇게 만든 템플릿 덕분에 스터디를 재미있게 할 수 있었던 것 같습니다. 강의 들으면서 1차적으로 적은 야생의 거친 필기를 이 템플릿으로 더 잘 정리하려는 마음에 한 파트 정리하는데 시간이 좀 많이 걸린다는 소소한 단점이 있기는 합니다... 그렇지만 이렇게 정리한 것이 나중에 복습할 때 도움이 크게 될 것이라 믿어 의심치 않습니다.적다보니 길어졌네요. 스터디가 끝나니 아쉬움이 남기는 합니다. 다음에도 이런 스터디가 또 열렸으면 좋겠어요. 저번에 들어보니 컴퓨터구조 강의도 준비하신다던데.... 그때 한번 또 스터디가 열렸으면 하는 소소한 바램이 있습니다. 이번에 들은 내용들 복습하면서 더 심화적인 내용도 개인적으로 공부해야겠습니다. 좋은 강의 감사하고 다음에 또 뵐 기회가 있으면 좋겠습니다.

운영체제자료구조CS워밍업클럽스터디

장서윤

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

이번 발자국은 과제 진행 과정을 작성해 볼 예정이다. 목차는 다음과 같다.1. 기능 목록 작성2. 공통 컴포넌트 구현3. 결과물4. 고민했던 부분 ✅️ 1. 기능 목록 작성1. 항목 추가/수정할 수 있다.지출 항목 + 비용을 입력받는다 (조건을 만족할 때까지)지출 항목은 문자열이여야 한다.비용은 숫자여야 한다.지출 항목 + 비용 모두 입력되어야 한다. (공백 제외)  조건을 만족할 경우, 버튼이 enable 된다. 추가/수정을 완료했을 경우, toast 메시지를 띄워준다. 2. 항목 리스트를 보여준다. (테이블 형식)각 항목(row) 마다 수정/삭제 버튼이 존재한다.수정 버튼을 누른 경우[ 기능목록 1. 항목 추가/수정할 수 있다 ] 로 이동한다.삭제 버튼을 누른 경우항목이 삭제되며, toast 메시지를 띄워준다. 총 지출 금액을 보여준다.항목 리스트가 없을 경우, '존재하지 않습니다' 를 보여준다.   3. 모든 항목을 삭제할 수 있다.목록 지우기 버튼을 누른 경우모든 항목이 삭제되며, toast 메시지를 띄워준다. ✅ 2. 공통 컴포넌트 구현MUI와 같은 UI 라이브러리를 쓰지 않고, tailwind css로만 구현할 것이기에, 필요한 컴포넌트는 직접 만들어야한다. 먼저 공통된 디자인을 위해 rounded만을 사용하고자 했다. ( 컴포넌트마다 rounded를 다 다르게 사용하지 않는다)색상은 emerald + slate 만을 최대한 사용했다. 그렇게 해서 필요한 컴포넌트는 다음과 같다. Outlined Input시간을 투자한 부분이다. 기본 html의 input은 굉장히 단순하기에 커스텀이 필요했다.focus 했을 때, label 을 input 박스 위로 가게 하고, 부드러운 애니메이션을 넣고자 했다.Contained Button + Text Button배경을 채운 Contained Button오직 text 만 존재하는 Text ButtonTable기본 table에 css만 추가했다.Toast 메시지 success : 초록색 체크 아이콘추가, 수정, 삭제가 성공적으로 완료되었음을 표시한다. warn : 노란색 경고 아이콘입력값의 유효성검사가 일치하지 않을때 표시한다.  ✅ 3. 결과물 ✅ 4. 고민했던 부분 지출 항목이 문자여야하는데, 이를 어떻게 판별하는가? 이다.애매한 부분이 지출 항목이 "맥북 pro 16" 처럼 오직 문자 type으로 이뤄지지 않고, 여러 type이 같이 존재할 수 있다. 그래서 이걸 어떻게 예외처리 해줄지 고민했었는데, 일단은 지출 항목을 절대 숫자로만 이뤄지지는 않을 것 같아서, isNaN()만을 판별했다. 이 부분은 고민이 더 필요할 것 같다.. toast 메시지의 색상을 어떻게 할 것인가? 이다.상품을 "삭제" 했을 경우, toast 메시지의 아이콘 색상을 고민했었다.빨간색 -> 부정적 의미 -> 삭제와 연관된다! -> 그러나 error 와도 연관됨 -> 사용자 입장에서 "에러가 났다..!" 로 혼동할 수 있음.초록색 -> 삭제가 완료되었다! 에 의미를 둠-> 그러나, 추가, 수정, 삭제도 어쨌든 완료이기에, 다른 기능임에도 아이콘 색상이 같아서 구별이 어렵다는 문제가 존재함.고민 끝에 error와 연관되는 빨간색보다는 초록색으로 가되, "추가", "수정", "삭제" text 를 크고 두껍게 처리해주는 것으로 합의를 보았다!후기UI 라이브러리만 사용하다가, tailwind css로 직접 컴포넌트를 만드니까, 생각보다 시간이 오래 걸렸다. 중간에 계속 애니메이션도 적용된 라이브러리를 사용하고 싶었지만, 이를 css로(비록 tailwind css지만) 직접 완성시켰을때 상당히 뿌듯했다!또한, 기능목록을 제대로 작성한건지 모르겠다. 조금 더 깔끔하게 작성하고 싶은데, 어디까지 자세하게 적어야하는지, ui 부분도 자세하게 적어야하는지(버튼 색깔이 바뀐다거나)를 잘 모르겠다. 더 공부해봐야겠다!  

웹 개발프론트FE워밍업클럽

Dream

[ 인프런 워밍업 클럽 Study FE 0기 ] Week 2 발자국

발자국워밍업 스터디 클럽이 2주 차에 접어들었습니다. 해당 발자국은 따라 하며 배우는 리액트 A-Z (섹션 0-5) 중심으로 작성되었습니다.요약React를 사용하려면 Node.js가 필요하다. Node.js를 설치하면 NPM도 같이 설치되니 꼭 Node.js를 설치하자. Node.js 공식 홈페이지에 접속하면 2개의 Node 버전이 있는데, 그중에서 안정적인 버전인 LTS를 설치하면 된다. Section 01. React[ React란? ]리액트는 사용자 인터페이스(user interface, UI)를 만들기 위해서 사용되는 자바스크립트의 라이브러리다. 리액트는 인터렉션이 많은 웹 앱을 개발하기 위해서 주로 사용된다. 이렇게 사용자 인터페이스를 만들기 위해 도움을 주는 TOOL로는 리액트 말고도 Vue.js와 Angular.js가 있다.React: 라이브러리Angular, Vue: 프레임워크[ Framework vs Library ]프레임워크와 라이브러리를 대략 설명하자면 다음과 같다.Framework : 어떠한 앱을 만들기 위해 필요한 대부분의 것을 가지고 있다.Library : 어떠한 특정 기능을 모듈화 해 놓은 것이다.프레임워크는 앱을 만드는데 필요한 대부분의 라이브러리를 가지고 있으며, 라이브러리들은 특정 기능을 위해 모듈화 되어있다.리액트는 라이브러리이다. 왜냐? 리액트는 전적으로 UI를 렌더링 하는 데 관여하기 때문이다. 리액트는 여러 모듈을 사용하며 앱을 관리한다.라우팅: react-router-dom …상태관리: redux, mobx …빌드: webpack, npm …테스팅: Eslint, Mocha …[ React Component ]리액트를 공부하다보면 무조건 마주치는 단어가 있다. 바로 컴포넌트이다. 리액트는 컴포넌트 기반이라고 하는데, 이 컴포넌트는 무엇을 말하는 것일까?컴포넌트(Component): React로 만들어진 웹/앱을 이루는 최소한의 단위리액트는 이 컴포넌트를 통해서 웹/앱을 개발하게 된다.리액트는 여러 컴포넌트 조각으로 되어있다. 이것은 블록같다고 생각하면 된다. 여러 블록 조각을 맞추고 쌓아 올려 하나의 블록 작품을 완성하는 것. 리액트도 마찬가지로 컴포넌트를 이리저리 조합하고 쌓아올려 하나의 웹 페이지를 구성하게 된다.리액트 컴포넌트에는 2가지가 있다.클래스형 컴포넌트함수형 컴포넌트React는 여러 컴포넌트 조각으로 구성된다.개인적인 설명을 덧 붙이자면 리액트는 레고 블럭과 같다고 생각한다. 레고 블럭들을 하나 둘 씩 쌓아 올려 하나의 완성된 레고 작품을 만드는 것이다.[ Component 종류 ]React는 2개의 컴포넌트 종류가 있다.클래스형 컴포넌트(Class Components)class App extends Component { render() { return <h1>Hello, ReactJS!</h1>; } }함수형 컴포넌트(Functioanl Components)function App() { return <h1>Hello, ReactJS!</h1>; }💡 현재 함수형 컴포넌트를 HOOK이랑 해서 많이 사용한다.💡 참고로 컴포넌트를 작성할 때 반드시 대문자 시작을 해야 한다. 소문자 시작 시 body, h1, p 같은 DOM 태그로 인식해 버린다.[ 브라우저가 그려지는 원리와 가상 돔 ]React의 가장 큰 특징은 가상 돔(Virtual DOM)이다. 이것을 사용하는 이유는 인터렉션 때문이다. 이 인터렉션에 의해 DOM에 변화가 발생하면 다시 DOM을 재구성하기 시작한다.JS 발자국에도 남겼었지만 웹 브라우저의 경우 다음과 같은 과정을 겪고 이 과정은 비용이 꽤 든다.Critical Render Path (웹 페이지 렌더링 과정): 데이터 파싱(HTML) ➔ DOM Tree 생성 ➔ CSSOM Tree 생성 ➔ JS 실행 ➔ Render Tree 생성 ➔ Layout 생성 ➔ PaintDOM을 재구성 한다는 것은 위 렌더링 과정을 다시 반복한다는 것이다. 즉, 인터렉션이 일어날때마다 위 과정을 다시 한다. 이것을 보완하기 위해서 나온 것이 가상 돔이다.가상돔 과정을 살펴보자..!데이터가 바뀌면 가상 돔에 렌더링 되고, 이전에 생긴 가상 돔과 비교를 해서 바뀐 부분만 실제 돔에 적용 시킨다.바뀐 부분을 찾는 과정을 Diffing이라고 부른다.바뀐 부분만 실제 돔에 적용 시키는 것을 Reconciliation(재 조정)이라고 부른다.[ Create React App 을 이용해서 리액트 설치하기 ]create-react-app 을 통해서 원하는 위치에 리액트를 설치할 수 있다. 이 때, Webpack과 Babel이 함께 설치가 된다. 따라서 React 앱 생성 전에 Webpack과 Babel에 대해서 간단히 알고 가자.Webpack정의: Webpack: 웹팩은 오픈 소스 자바스크립트 모듈 번들러써 여러 개로 나누어져 있는 파일들을 하나의 자바스크립트 코드로 압축고 최적화하는 라이브러리이다.장점여러 파일의 자바스크립트 코드를 압축하여 최적화할 수 있기 때문에 로딩 줄일 수 있. (네트워크 비용 줄음)모듈 단위로 개발이 가능하여 가독성과 유지 보수가 쉽다.Babel정의: 최신 자바스크립트 문법을 지원하지 않는 브라우저들을 위해서 최신 자바스크립트 문법을 구형 브라우저에서도 돌 수 있도록 변환 시켜주는 라이브러리이다.⇒ 이러한 Webpack과 Babel은 개발자가 React 개발 시 알아서 설정 해야 하지만 Create-React-App을 사용해서 React 앱을 생성하면 Babel이나 Webpack 설정이 이미 되어있기 때문에 준비 시간이 단축된다.[ Create-React-App ]프로젝트를 진행할 폴더 생성VSC에서 해당 프로젝트 폴더 열기Termial에 npx create-react-app 생성할파일명 입력강의에서는 npx create-react-app ./을 입력하였다../는 현재 위치를 뜻한다.[ npx create-react-app 에 대하여 ]npx: 노드 패키지 실행을 도와주는 도구이다.npx create-react-app이란 npm 레지스트리에 잇는 패키지를 ./에 실행시켜서 React를 설치해 주는 것이다.실행하는 방법실행하고자 하는 리액트 파일 위치에서 npm run start 입력(강의에서는 npm run start방법만 소개시켜 주셧는데 npm start도 가능하다.)🤔 개인적으로 요즘 vite에 관한 이야기가 보이는데 이도 조사해 보아야겠다… Section 2. 간단한 To-Do 앱 만들며 리액트 익히기[ create react app ]create-react-app으로 리액트를 설치하면 여러 파일이 등장하는데, 이 중에서 절대로 이름을 수정해서는 안되는 파일이 존재한다.public/index.html: 페이지 템플릿src/index.js: 자바스크립트 시작 점조심하자!💡그리고 우리가 새로 js, jsx, css 등 직접 생성할 파일들은 src 폴더에서 하면 된다. Webpack이 src/ 부분에만 작동하기 때문이라고 한다.[ package.json ]해당 프로젝트에 대한 정보들이 들어있다. 프로젝트 이름, 버전, 필요한 라이브러리와 라이브러리들의 버전이 명시되어 잇다.[ 싱글 페이지 애플리케이션(single-page application, SPA) ]싱글 페이지 애플리케이션(single-page application, SPA)은 서버로부터 완전한 새로운 페이지를 불러오지 않고 현재의 페이지를 동적으로 다시 작성함으로써 사용자와 소통하는 웹 애플리케이션이나 웹사이트를 말한다.위키백과React.js는 SPA이다. 즉, 어떠한 데이터에 관한 교체 이벤트가 발생했을 때, 서버로부터 페이지를 새롭게(html 파) 받아와 구성하는 것이 아니라 content를 바꿔치기 한다. 이는 HTML 5의 History API를사용해서 가능하게 만든다.[ History API ]전통적인 웹 사이트는 a page에서 b page로 이동할 때 a.html을 보여주다가 b.html을 보여주면 되었지만 SPA의 경우 오직 1개의 HTML(index.html)이 존재한다. 따라서 페이징 전환을 하기 위해서 HTML 5 History API를 이용한다.History.back(): 세션 기록의 바로 뒤 페이지로 이동하는 비동기 메서드History.forward(): 세션 기록의 바로 앞 페이지로 이동하는 비동기 메서드History.go(): 특정한 세션 기록으로 이동하게 해 주는 비동기 메서드History.pushState(): 주어진 데이터를 세션 기록 스택에 넣어준다.History.replaceState(): 최근 세션 기록 스택의 내용을 주어진 데이터로 교체한다.생성했던 React 프로젝트에서 public/index.js를 살펴보면 <div id="rood"></div>가 있다.그리고 src/index.js 코드에는 document.getElementById('root')라는 코드가 있다.자바스크립트 파일의 시작 점인 src/index.js에서 id값이 rood인 요소를 찾아 그곳에 해당 요소들을 렌더링하는 것이다. 즉, div라는 최상위 루트 노드 아래에 직접 정의한 요소를 더해 화면을 꾸며나가는 것이다!![ JSX ]JSX는 Javascript Syntax Extension의 약자로 자바스크립트의 확장 문법이다.리액트에서는 이 JSX를 이용해서 화면에서 UI가 보이는 모습을 나타내준다.JSX 사용이 필수는 아니나 사용하면 가독성이 너무 좋아서 필수 아닌 필수이다. (애초에 리액트 개발자들 대부분이 JSX를 사용한다고 한다.)JSX는 createElement를 쉽게 사용하기 위해서 사용한다.모든 UI를 만들때 마다 createElement를 사용해서 컴포넌트를 만들 수 없다.Ract는 React.crateElemnt API를 사용해서 엘리먼트를 생성한 후에 이 엘리먼트를 In-Memory에 저장한다. 그리고 RaectDOM.render 함수를 통해 웹 브라우저에 그린다.JSX를 사용하면 Babel이 사용한 문법을 crateElemnt로 자동 변환해준다. 따라서 그냥 개발자는 자유롭게 JSX 사용하면 된다.단, JSX는 컴포넌트에 여러 요소가 있다면 반드시 부모 요소 하나로 감싸줘야 한다.// 안된다. // 자식 요소가 여러 개 라면 부모 요소로 감싸줘라. function hello() { return ( <div>Hello, Raect!</div> <div>Hello, Wrold!</div> ); } // 이렇게 말이다. function hello() { return <div> <div>Hello, Raect!</div> <div>Hello, Wrold!</div> </div>; }💡 만약 JSX에서 JS 코드를 사용하고 싶다면 { } 내부에 작성해주면 된다.[ React와 Key ]map()을 사용한다면 언제나 명심해야 하는 것. KEY. 이것을 넣지 않는다면 에러가 발생한다.React에서 요소의 리스트를 나열할 때는 Key를 넣어줘야 한다. Key는 React가 변경, 추가 또는 제거된 항목을 식별하는 데 도움이 된다.추가적으로, 이 Key에 지정하는 값은 순회하고자 하는 목록의 아이템에 대한 ID 값이면 된다. 즉, 고유한 값이여야 한다. 정 없으면 index 넣어도 되지만 index 값은 권장하지 않는다.리액트는 가상 돔을 이용해서 바뀐 부분만 실제 돔에 적용한다. 그렇다면 리스트를 나열할 때 바뀐 부분만 어떻게 찾을까? 바로 이 key를 이용해서 어떠한 부분이 바뀌었는 인식하는 것이다.[ state ]정말 정말 중요한 개념!!!리액트에서 데이터가 변할 때 화면을 다시 렌더링 해주기 위해서 React State를 사용한다. State란 무엇일까?간단히 말해서 변수이다.단, 이 변수의 값이 변경되면 컴포넌트들이 재렌더링 된다.state에는 리액트의 흐름에 관한 데이터와 관련이 있다. Section 3. To-Do 앱 최적화 하기[ React HOOK ]엄청나게 중요하다. 이 HOOK은 클래스형 컴포넌트처럼 함수형 컴포넌트에서도 state와 생명주기 메서드를 사용할 수 있도록 해주는 메서드이다.클래스 형 컴포넌트에서는 Mounting, Updating, Unmounting 3단계 따라서 생명주기 메서드를 제공한다.Mounting: componentDidMount()Updating: componentDidUpdateUnmounting: componentWillUnmount()함수형 컴포넌트에서는 이를 위해 HOOK을 사용한다.[ HOC(Higher Order Component) ]화면에서 재사용 가능한 로직만을 분리해서 component로 만들고, 재사용 불가능한 UI와 같은 다른 부분들은 parameter로 받아서 처리하는 방법이다.HOC는 HOOK이 나오기 전에 사용했던 부분이다.Wrapper가 많아지면 흐름 파악이 어려워서 이제 잘 안 쓴다.HOC를 만들고 싶으면 Custom HOOK을 사용하자.[ HOOK ]기본적으로 알고 있어야 할 HOOK은 다음과 같다.useState()리액트의 유동적인 데이터들은 state에 담아 사용하기 위해 이용하는 HOOK클래스형 컴포넌트의 setState와 같이 state 객체에 대한 업데이트 실행단!!! state 변경 시 재 렌더링이 일어남useEffect()사이드 이팩트 처리 HOOK클래스형 컴포넌트의 생명 주기 함수 역할 수행useMemo()최적화 용 HOOK, 의존성 배열에 따라 작동의존성 배열에 있는 값이 변하면 지정한 함수를 실행하여 해당 반환 값을 반환useCallback()최적화 용 HOOK, 의존성 배열에 따라 작동의존성 배열에 있는 값이 변하면 함수를 반환useRef()요소의 참조를 위해 사용하는 HOOK[ Props ]Props는 Properties의 줄임말상위 컴포넌트에서 하위 컴포넌트로 데이터를 전송하고 싶을 경우 사용읽기 전용으로 자녀 컴포넌트에서 강제로 이 값을 변경할 수 없다.전달 받은 props가 state고 이 값을 바꾸고 싶다면 props로 set함수를 넘기고 이것을 이[ TailWindCSS ]HTML 안에서 CSS 스타일을 할 수 있게 해주는 CSS 프레임워크빠른 스타일 작업 가능id 혹은 class 명을 작성하기 위해 머리를 혹사 시키지 않아도 된다.class에 특정 키워드를 넣어서 CSS 조작정해진 속성 키워드가 워낙 많으니 공식 홈페이지 검색 필수다[ 리액트 불변성 ]불변성을 지키며 개발을 하자!참조 타입에서 객체나 배열의 값이 변할 때 원본 데이터가 변경되면 예상치 못한 오류가 발생할 수 있다.불변성을 지킬 수 있는 참조 관련 메서드:spread operator, map, filter, slice, reduce불변성을 해치는 참조 관련 메서드:splice, push[ React.memo ]React.memo는 Higher-Order Components(HOC)이다. 불필요한 컴포넌트 렌더링을 방지할 수 있게해준다. (일종의 최적화 용 HOC) Section 4-5. Netflix 앱 만들기주로 실습 내용 이었다. 정리할 이론만 추려내 보겠다.[ Styled Component ]자바스크립트 파일 안에서 CSS를 처리할 수 있게 해주는 라이브러리[ React Router Dom ]React Router DOM을 이용하면 웹/앱에서 동적 라우팅을 구현할 수 있다. 라우팅이 실행 중인 앱 외부의 구성에서 처리되는 기존 라우팅 아키텍처와 달리 React Router DOM은 앱 및 플랫폼의 요구 사항에 따라 컴포넌트 기반 라우팅을 용이하게 한다.React Router DOM을 사용하기 위해서는 몇 가지 설정을 해야한다.index.js에서 BrowerRouter로 루트 컴폰너트를 감싸준다.BrowserRouter은 HTML 5 History API를 사용하여 UI를 URL과 동기화 된 상태로 유지해준다.import { BrowserRouter } from 'react-router-dom'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <BrowserRouter > <App /> </BrowserRouter> </React.StrictMode> ); 여러 컴포넌트 생성 및 라우트를 정의한다.Routes와 Route를 사용한다.Routes: 앱에서 생성될 모든 개별 경로에 대한 컨테이너 상위 역할을 한다.Route: 단일 경로를 만드는 데 사용된다.path 속성: 원하는 컴포넌트의 URL 경로를 지정한다.element 속성: 경로에 맞게 렌더링 되어야 하는 컴포넌트를 지정한다.import { Routes, Route } from "react-router-dom"; function App() { return ( <div className="app"> <Routes> <Route path="/" element={<Home />}> <Route path="about" element={<About />} /> <Route path="contact" element={<Contact />} /> </Route> </Routes> </div> ); } +) <Link />를 통해 경로 이동하기Link 구성 요소는 HTML의 a 태그와 유사하다.to 속성은 링크가 유저를 데려가는 경로를 지정한다.앱 구성 요소에 나열된 경로 이름을 생성했기 때문에 링크를 클릭하면 경로를 살펴보고 해당 경로 이름으로 구성 요소를 렌더링한다.import { Link } from "react-router-dom"; function Home() { return ( <div> <h1>홈페이지</h1> <Link to="about">About 페이지를 보여주기</Link> <Link to="contact">Contact 페이지를 보여주기</Link> </div> ); } [ 중첩 라우팅 ]라우팅은 중첩 처리가 가능하다.[ Outlet ]자식 경로 요소를 렌더링하려면 부모 경로 요소에서 Outlet를 사용해야한다.하위 경로가 렌더링될 때 중첩된 UI가 표시될 수 있다.부모 라우트가 정확히 일치하면 자식 인덱스 라우트를 덴더링하거나 인덱스 라우트가 없으면 아무것도 렌더링하지 않는다.[ useNavigate ]경로를 바꿔준다.naviate(”/home”) ⇒ localhost:3000[ useParams ]:style 문법을 path 경로에 사용했다면 useParams()로 읽을 수 있다.function test() { return ( <Routes> <Route path="invoices/:invoiceId" element={<Invoice />} /> </Routes> ); } function Invoice() { let params = useParams(); return <h1>Invoice {params.invoiceId}</h1>; } [ useLocation ]현재 위치의 객체를 반환현재 위치가 변경될 때마다 일부 side effect를 수행하려는 경우 유용하다.[ useRoutes ]<Routes>와 기능적으로 동일하나 <Route> 요소 대신 자바스크립트 객체를 사용하여 경로를 정의한다.일반 <Route> 요소와 동일한 속성을 갖지만 JSX가 필요하지 않는다.[ Custom HOOK ]개발자가 정의하는 HOOK이다.HOOK의 이름은 use로 시작해야 한다.참고로 HOOK은 함수형 컴포넌트 또는 커스텀 HOOK에서만 호출이 가능하다.따라서 커스텀 HOOK도, 함수용 컴포넌트 또는 HOOK 내부에서 호출되어야 한다.강의에서는 useDebounce과 useOnClickOutside HOOK을 만들었다.useDebounce: input 요소에서 데이터 입력이 발생하면 설정한 set함수 때문에 매번 state 값이 바뀌고 재 렌더링이 일어난다. 따라서 keyup 이벤트의 처리를 지연시키는 커스텀 HOOK이다. (코드는 강의를 참고하자!)useOnClickOutside HOOK: 모달 창 밖의 부분을 클릭하면 해당 모달 창이 꺼지는 기능을 수행하는 HOOK이다. (코드는 강의를 참고하자!)이런 식으로 HOOK을 만들고 활용하는구나 싶었다…미션과제 총 합본 https://www.inflearn.com/blogs/7021 JS 미션 03. 퀴즈 앱[ 구현 해야하는 기능 ]1. 퀴즈 문제, 문제에 해당 하는 선택지 (선택지의 갯수가 매번 다름)2. 답 선택 시, 정답 여부에 따라 배경의 색상이 변경되어야 함문제는 data.json을 직접 작성하여 동적 생성했습니다. JS 복습 겸으로 해당 주제로 퀴즈 앱을 간단하게 만들어 봤습니다. 미션을 진행하며 문제는 없었습니다. JS 미션 04. 책 나열 앱[ 구현 해야하는 기능 ]1. 책 이름 입력 란2. 책 저자 입력 란3. 제출 버튼을 누르면 입력한 정보를 저장 함3-1. 제출 시 제출 했다는 안내 문구 떠야 함4. 제출된 데이터는 책 리스트에 출력 됨아이템은 다음과 같은 기능을 가져야 함5-1. 표기 할 데이터: 책 이름, 저자5-2. 각 아이템에는 삭제 기능이 있어야 함 구현하는데 문제가 없었습니다. REACT 01. 예산 계산기[ 구현 해야하는 기능 ]1. 지출 항목 입력 란2. 지출 비용 입력 란3. 제출 버튼을 누르면 입력한 정보를 저장 함3-1. 제출 시 제출 했다는 안내 문구 떠야 함아이템은 다음과 같은 기능을 가져야 함5-1. 표기 할 데이터: 지출 항목, 지출 비용5-2. 각 아이템에는 수정 및 삭제 기능이 있어야 함수정 버튼 클릭 시 수정 모드로 변경전체 삭제 기능이 있어야 함정말 막힘 없이 진행되다 딱 한 군데에서 문제를 맞았습니다. 상황에 맞게 알림을 띄우는 기능이었는데, JS에서는 아무런 문제 없이 해결했던 이 기능을 React에서 구현 하려고 하니 이상한 문제가 발생하더군요. 여러 동작을 해서 메시지가 많이 발생할 경우, 메시지가 예시처럼 모두 생성되는 것이 아니라 같은 자리에서 텍스트만 바뀌어서 출력이 되었습니다. 물론 잘 해결해서 과제를 마쳤습니다.회고워밍업 스터디의 2주 차에 진입하며 자바스크립트 공부를 마치고 새롭게 React 공부를 진행하며 React의 다양한 기술을 접하게 되었습니다. 특히 state, props, hook, 그리고 라우팅 부분은 처음에는 이해하기가 어려웠습니다. 그러나 부족한 이해를 보완하기 위해서 강의 내용을 정리하고, 추가적인 학습 자료를 찾아가며 개념을 확실히 파악하려고 노력했습니다.React 학습을 마치고 시작한 미션도 초반에는 막막함을 느꼈지만 코드를 작성해 나가며 수업 때 배운 내용을 적용해 가며 문제를 해결해 나갔습니다.워밍업 스터디도 이제 끝을 향해 가네요. 마무리되는 날까지 열심히 학습에 참여하고 미션 해결을 위해 도전해 보겠습니다. 

프론트엔드워밍업클럽FE

Dream

[ 인프런 워밍업 클럽 Study FE 0기 ] Week 1 발자국

들어가기 앞서...2024년의 첫 해가 밝으며, 지금까지는 단순히 관심만 갖고 있었던 웹 개발에 대한 공부를 시작해보기로 결심했습니다. 먼저 HTML과 CSS의 공부를 마치니 운이 좋게 인프런에서 JS와 ReactJS 스터디를 진행한다는 소식을 듣게 되었습니다. 이런 좋은 기회를 놓치지 않겠다고 생각하고, 워밍업 클럽에 참여하게 되었습니다.발자국OT를 참가한지 엊그제 같은데 시간은 정말 순식간에 지나가는 것 같습니다. 벌써 스터디가 시작된 지 1주차가 되었습니다. 이제 그 동안의 강의 내용을 간단하게 요약하고, 회고를 남겨 보려고 합니다. 이번 주 강의는 따라하며 배우는 자바스크립트 A-Z (섹션 0~8) 부분을 진행하였습니다.요약Section 01. 자바스크립트 기초[ Console 객체 ]자바스크립트의 console 객체는 코드를 작성하고 테스트를 할 때, 사용하기 좋은 함수를 제공해준다. 다음은 강의에서 소개한 주요 Console 객체의 함수들이다.console.log(): console에 메시지를 출력한다. console.table(): console에 배열이나 객체의 데이터를 테이블 형태로 출력한다. console.error(): console에 에러 메시지를 출력한다. console.warn(); console에 경고 메시지를 출력한다. console.time(), console.timeEnd(): 세트로 사용되며, 두 함수 사이의 코드 실행 시간을 측정한다. [ var, let, const과 스코프 ]변수/상수를 선언할 때 let, const 그리고 var 키워들 사용한다. let과 const는 ES6에 새롭게 추가된 키워드이다. var 키워드는 오래된 선언 키워드로 let과 const 사용을 권장하고 있다.let: 변수 키워드, 재선언 X, 재할당O const: 상수 키워드, 재선언 X, 재할당Xvar: 재선언 O, 재할당 O 그리고 사용한 let/const와 var 키워드에 따라 스코프가 다르게 처리된다. 스코프(scope, 유효/참조 범위)란 어떠한 변수를 참조하려고 할 때, 그 변수에 접근 가능한 유효 범위이다.let/const: 모든 코드 블록 { } 내부에서 선언된 변수는 코드 블록 내에서만 유효. var: 함수 내에서 선언된 var 변수는 함수 내에서만 유효하며, 함수 내에서 블록 내·외부에 관계없이 접근 가능. [ 호이스팅 ]코드가 실행되기 전에 변수 및 함수 선언을 로컬 범위(유효 범위)의 맨 위로 끌어 올려지는 경우를 말한다.[ 자바스크립트 타입과 타입 변환 ]자바스크립트의 데이터 타입(자료형)은 다음과 같다.원시 타입: Boolean, String, Number, null, undefined, Symbol고정된 크기로 Call Stack 메모리에 저장실제 데이터가 변수에 할당참조 타입: Object, Array데이터 크기가 정해지지 않고 Call Stack 메모리에 저장데이터의 값이 Heap에 저장되며 메모리의 주소 값이 할당 자바스크립트 변수에 저장된 값은 다른 데이터 유형으로 변환될 수 있다.명시적 데이터 변환(개발자가 직접 함수를 사용해서 변환)자동 데이터 변환(자바스크립트 자체에 의해 자동으로 변환) [ 연산 및 Math ]자바스크립트에서는 기본적인 산술 연산자, 논리 연산자, 비교 연산자를 제공한다.Math를 통해 더 많은 연산을 이용할 수 있다. [ Template Literals]Backtick(`)을 사용하여 문자열을 표현한 것을 템플릿 리터럴이라고 한다. 템플릿 리터럴을 이용하면 다음과 같은 이점이 있다.줄 바꿈이 쉽다.${}을 사용하여 내부에 표현식을 포함할 수 있게 한다. [ Loops ]for: 초기식, 조건식, 증감식을 포함하는 반복문으로 주어진 조건이 참일 경우 블록 안의 코드를 반복 실행for/in: 객체의 열거 간으한 속성들을 반복하는데 사용.while: 주어진 조건이 true일 동안 코드 블록을 계속해서 실행.do/while: 먼저 코드 블록을 실행한 후, 조건을 확인한다. 그러고 나서 조건이 true일 동안 반복 실행한다. Section 02. Window 객체 및 DOM[ Window 객체 ]브라우저에 의해 자동으로 생성된다. (자바스크립트 객체 X, 브라우저에서 제공 O)이 window 객체는 다음과 같은 역할을 수행한다.브라우저에 접근 및 조작 가능자바스크립트 코드의 전역 객체 역할 [ DOM ]문서 객체 모델(Document Object Model, DOM)요소로 이루어진 HTML 파일을 Tree 구조로 표현한 객체 모델최상단에는 document 노드가 위치해 있으며, 이를 통해 DOM 접근 및 조작 가능Critical Render Path (웹 페이지 렌더링 콰정)데이터 파싱(HTML) ➔ DOM Tree 생성 ➔ CSSOM Tree 생성 ➔ JS 실행 ➔ Render Tree 생성 ➔ Layout 생성 ➔ Paint +) 강의에서 수 많은 Property 및 Method를 소개해 주셨지만 너무 많은 관계로 생략... Section 03. Event[ Event ]만약 인프런에서 로그인 버튼을 누르면 무엇이 일어날까? 당연히 로그인 페이지로 이동할 것이다. 이렇게 웹 페이지에서 발생하는 사용자의 행동에 대응하여 브라우저에서 일어나는 특정 사건을 "이벤트"라고 한다. 자바스크립트에서는 다음과 같은 이벤트가 존재한다.UI 이벤트load, change, resize, scroll, error 키보드 이벤트keydown, keyup, keypress마우스 이벤트click, dblclick, mousedown, mouseout, mouseover, mousemove, mouseup포커스 이벤트focus, blur폼 이벤트input, change, select, reset, submit, cut/copy/paste 이벤트를 등록하기 위해서는 addEventListener()를 사용하면 된다. 또한 이벤트 흐름에는 이벤트 bubbling과 Capturing라는 2가지의 기본 모델이 존재한다.[ Event Bubbling과 Event Capturing ]이벤트 bubbling은 가장 깊게 중첩된 요소에 이벤트가 발생했을 때, 이벤트가 위로 전달 되는 것을 의미한다. 이벤트 bubbling은 target 이벤트에서 시작해서 요소를 거쳐 document 객체를 만날 때까지 각 노드에서 모두 발생한다. 만약 bubbling 중단을 원한다면 event.stopPropagation()을 호출하면 된다.event.stopPropagation()DOM Tree를 통한 이벤트 흐름 중지 가능브라우저 기본 동작은 취소 X 이벤트 Capturing은 bubbling과 다르게 제일 상단에 있는 요소에서 아래로 이벤트가 내려오는 것을 말한다.[ Event Delegation ]이벤트 bubbling과 이벤트 Capturing을 통해서 이벤트 위임을 이해할 수 있다. 이 이벤트 위임은 '하위 요소의 이벤트를 상위 요소에 위임하는 것'이다. Section 04. 자바스크립트 중급[ this]Method의 this: 해당 객체를 가리킨다.함수에서 this: window 객체를 가리킨다.constructor의 this: 빈 객체를 가리킨다. [ bind, call, apply]call():함수를 호출하는 함수.첫 번째 인자 값으로 어떠한 것을 전달해 주면 호출되는 함수의 this가 인자 값으로 지정apply(): call()과 유사하나 인수 부분에 배열을 넣어줘야함.bind(): 해당 함수가 지정한 인자 값을 가리키도록 하지만 call(), apply()와 다르게 직접 함수 실행 X [ 삼항 연산자 ]다음과 같은 구문을 갖는다.조건 ? true이면 반환 : false이면 반환 [ Event Loop]자바스크립트는 동기 언어이다. 하지만 가끔 비동기로 작동하는 setTimeout()를 사용하는 예시를 볼 수 있다. 자바스크립트는 비동기 코드를 작성하기 위해서 자바스크립트 이외의 도움을 받는다.[ Closure ]다른 함수 내부에 정의된 함수가 있는 경우, 외부 함수가 실행을 완료하고 해당 변수가 해당 함수의 외부에서 더 이상 엑세스할 수 없는 경우에도, 해당 내부 함수는 외부 함수의 변수 및 액세스가 가능하다. 이 기능을 Closure라고 부른다.[ 구조 분해 할당 ]배열이나 객체의 속성을 해제하여 그 값을 개별 변수에 담을 수 있게 해주는 표현 식이다.[ Map, Filter, Reduce ]Map, Filter, Reduce은 배열 메서드의 대표적인 예시이다.map(): 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출하고 나온 결과를 모아 새로운 배열로 만들어 반환한다.filter(): 주어진 함수의 필터를 통과하는 모든 요소를 모아 새로운 배열로 반환한다.reduce(): 배열의 각 요소에 주어진 리듀서(reducer) 함수를 실행하고, 하나의 결괏값을 반환한다.[ 얕은 비교 VS 깊은 비교 ]숫자, 문자열 등 원시 자료형은 값을 비교하게 된다. 하지만 배열, 객체 등의 참조 자료형은 참조되는 위치를 비교하게 된다. 얕은 비교를 하게 되면 원시 값의 경우 문제가 없지만 참조 값의 경우 실제 값이 아닌 저장된 위치(참조 값)이 비교되기 때문에 문제가 된다.깊은 비교를 사용하게 되면 참조 자료형도 실제 값으로 비교할 수 있게 된댜ㅏ.객체 depth가 깊지 않은 경우: JSON.stringify() 사용객체 depth가 깊은 경우: lodash 라이브러리의 isEqual() 사용[ 얕은 복사 VS 깊은 복사 ]위에서 정리한 내용처럼 복사에도 문제가 발생하게 된다. 따라서 참조 자료형의 값의 경우 깊은 복사를 사용하면 된다.JSON.stringify()lodash 라이브러리의 deepCopy[ 함수 표현식, 함수 선언문 ]함수 선언문: 함수 선언은 함수를 만들고 이름을 지정하는 것이다.일반적인 함수 선언 방식으로 function 키워드와 식별자를 표기하여 사용한다.함수 표현식은 함수를 만들고; 변수에 할당하는 것이다.익명 함수(function 키워드는 사용했으나 식별자 X), 화살표 함수 사용 Section 05. OOP[ OOP ]OOP(Object-Oriented Programming, 객체 지향 프로그래밍)란 Java 및 C를 비롯한 많은 프로그래밍 언어의 기본이 되는 프로그래밍 패러다임이다. 완전 간단하게 말하자면 객체 지향 프로그래밍은 객체들의 모임이라고 할 수 있다.OOP 특징으로는 다음과 같다.추상화:불필요한 정보는 숨기고 중요한 정보 만을 표현함으로써 프로그램을 간단히 만드는 것.상속:새로운 클래스가 기존의 클래스의 자료와 연산을 이용할 수 있도록 해주는 것.기존 클래스: 부모 클래스, 상위 클래스새로운 클래스: 자식 클래스, 하위 클래스다형성: 하나의 틀을 가지고 여러 개의 다양한 형태를 만드는 것이다.overriding을 통하여 다형성 구현 일반적인 코드를 재사용하고 작성할 수 있다.캡슐화:클래스 안에 있는 Method, 변수 등을 하나로 묶어준다. [ class와 constructor ]class에서는 constructor라는 특별한 메서드를 제공한다. 이 constructor는 생성자로, 인스턴스화된 객체에서 다른 메서드를 호출하기 전에 수행해야 하는 사용자 지정 초기화를 할 수 있게 해준다.클래스를 new 키워드를 붙여 인스턴스 객체로 생성하면 넘겨 받은 인자 값과 함께 constructor가 가장 먼저 실행이 된다. 따라서 이 곳에 초기화를 해야 하는 작업을 수행한다.[ Super]자바스크립트에서 super는 다음과 같은 역할을 수행한다.자식 클래스 내에서 부모 클래스의 생성자를 호출할 때 사용한다.자식 클래스 내에서 부모 클래스의 메소드를 호출할 때 사용한다. Section 06. 비동기[ 동기와 비동기 ]동기(Synchronous)코드를 순차적으로 실행하는 것. 즉, 한 작업이 끝나기를 기다렸다가 끝나면 다음 작업을 수행한다.각 작업이 완료될 때까지 다음 작업이 실행되지 않는다.비동기(Asynchronous)작업이 종료되지 않아도 다음 작업을 진행할 수 있는 방식비동기적인 코드는 특정 작업을 기다리지 않고 다음 작업을 계속 수행한다. [ Callbacks, ES6 Promise, ES7 Async / Await ]callbacks콜백 함수는 특정 함수에 매개변수로 전달된 함수를 의미한다.콜백 함수는 함수를 전달 받은 함수 내부에서 호출된다.단, 콜백 지옥을 맛볼 수 있다.Promise자바스크립트 비동기 처리에 사용되는 객체이다.new 키워드와 생성자를 사용해서 만들며, 생성자의 매개변수로 실행 함수를 전달한다.new Promise(실행함수) 실행 함수의 1번째 매개변수 resolve는 비동기 작업 성공 값이다.실행 함수의 2번째 매개변수 reject는 작업 실패 값이다.Promise는 다음 중 하나의 대기 상태를 갖는다.대기, 이행, 거부단, 체인 지옥이 시작된다...Async / Await비동기 코드를 마치 동기 코드처럼 작성할 수 있도록 해준다.Promise에서 than 체인 형식으로 호출하는 것보다 가독성이 좋다.await는 async 함수에서만 사용 가능하다.동기식 코드에서 사용하는 try...catch 문을 사용할 수 있다. Section 07. Symbol, Iterator, Generator[ Symbol ]ES6에 새롭게 추가된 원시 타입으로, 유니크한 식별자를 만들기 위해서 사용.단, for...in과 getOwnPropertyNames에서 제외 된다.Symbol 사용 시 기본적으로 Property가 숨겨진다. (찾을 수 있는 방법 有)따라서 for...in과 getOwnPropertyNames에서 symbol로 만든 Property가 안보인다.[ Iterator, Generator ]Iterator대표적인 예시로 배열이 있다.반복 가능한 것을 Iterable하다고 한다. for…of를 이용할 수 있다.[Symbol.iterator()] 값을 가지고 있다.Generator사용자의 요구에 따라 일시적으로 정지할 수 있고, 다시 시작할 수 있는 특별한 기능을 가지고 있다.function다음에 Asterisk (애스터리스크)를 붙인 형태로 사용한다.function*yield 키워드를 이용한다: 제너레이터 함수의 실행을 일시적으로 정지시킴. Section 08. Design Pattern[ 디자인 패턴 ]디자인 패턴은 개발자가 응용 프로그래밍나 시스템을 디자인할 때 일반적인 문제를 히결하는 데 사용할 수 있는 공식화된 모범 사례이다.- 위키 피디아다음과 같은 장점이 있다.최고의 솔루션재사용성풍부한 표현력향상된 의사 소통필요없는 코드 리팩토링코드베이스 크기 감소[ 디자인 패턴 종류 ]Singleton Pattern: 클래스의 인스턴스화를 객체 1개로 제한하는 디자인 패턴Factory Pattern: 비슷한 객체를 반복적으로 쉽게 생성하게 해주는 디자인 패턴Mediator Pattern(중재자 패턴): 객체 그룹에 대한 중앙 권한을 제공해주는 디자인 패턴Observer Pattern: event-driven 시스템을 이용하는 디자인 패턴Module Pattern: 코드를 더 작고 재사용 가능한 조각으로 분할하게 해주는 디자인 패턴 미션완벽히 해결한 미션은 다음과 같습니다.음식 메뉴 앱음식 메뉴 앱 미션은 주어진 카테고리에 해당되는 메뉴를 출력하는 웹을 구현하는 것이었습니다. 저는 카페 메뉴를 주제로 해당 웹을 구현했습니다. 다만 출력할 아이템에 대한 DB가 없어서 직접 data.json을 작성하여 처리했습니다. 미션을 해결하면서 기능 구현에는 특별한 문제가 없었으나 기능 구현보다 데이터 파일 생성이 더 오래 걸린 미션이었습니다... (출력되는 메뉴 이미지는 스타벅스 이미지를 활용했습니다.) 가위 바위 보 앱플레이어와 컴퓨터가 가위 바위 보를 하는 게임을 구현하는 미션입니다. 총 10번의 기회가 주어지며 게임에 대한 스코어 제공 및 승패 결과를 제공해야 했습니다. UI를 어떻게 구현할까 고민하다가 이미지를 추가적으로 더 넣어 구성했습니다. 컴퓨터의 가위 바위 보 선택지는 Math.random()을 이용해 처리했으며, 기능 구현에는 특별한 문제는 없었습니다.회고자바스크립트 강의를 들으며 기초를 다지고 그 지식을 바탕으로 주어진 미션을 해결하는 한 주를 보냈습니다. 특히 웹 개발이 처음이라서 미션을 해결해 나가는 시간이 정말 흥미로웠습니다. 앞으로 워밍업 클럽 Study를 진행하며 제가 얼만큼 발전할 수 있는지 궁금해지기도 합니다. 남은 기간 최선을 다해서 임해보겠습니다!

프론트엔드워밍업클럽

dohi

워밍업 클럽 4기 - 백엔드 3주차 회고

수정내역썸네일 추가3주차 회고 강의 수강레이어드 아키텍처와 계층별 테스트 전략이번 주에는 Spring 기반의 레이어드 아키텍처 구조를 중심으로,Persistence / Business / Presentation Layer 각각의 책임과 역할을 이해하고이에 적절한 단위 및 통합 테스트를 직접 구성해보는 학습을 진행했습니다.1. Persistence Layer 테스트Persistence Layer는 애플리케이션의 가장 하단에서 데이터 접근(CRUD)만을 책임지는 레이어(data access의 역할)비즈니스 로직은 이 레이어에 포함되지 않아야 하며, 주로 JPA 기반 Repository를 테스트 대상으로 삼습니다.사용 기술: Spring Data JPA, @DataJpaTest테스트 대상: Repository + JPA 동작 확인특징실제 DB와 유사하게 동작하는 경량 통합 테스트 수행DB 변경 없이 테스트 가능 (자동 롤백) 2. Business Layer 테스트Business Layer는 도메인의 핵심 로직을 처리하는 계층으로, 서비스 클래스가 주를 이룹니다.Persistence Layer와 상호작용하며 트랜잭션을 보장하는 것이 중요합니다.테스트 대상: Service 클래스, 로직 흐름사용한 테스트 기법given-when-then 패턴 검증 내용:입력에 따라 기대하는 응답이 나오는지트랜잭션 롤백이 제대로 작동(@Transactional)@SpringBootTest, @DataJapTest차이 DataJpaTest 는 트랜잭션 어노테이션이 있어 자동 롤백 3. Presentation Layer 테스트Presentation Layer는 외부 요청(HTTP 등)을 가장 먼저 받는 계층으로,파라미터 검증이나 라우팅 처리 등의 역할을 담당합니다.테스트 방식: 컨트롤러 단위 테스트 + 나머지 계층은 Mocking학습한 포인트:@Transactional(readOnly = true)를 클래스 단에 선언하여 조회 메서드는 최적화CUD 작업은 개별 메서드에 @Transactional을 덮어써 트랜잭션 활성화동시성 이슈를 고려한 설계 및 분리 4. 테스트 환경 구성application.yml을 통해 프로파일(local/test) 분리테스트 환경에 따라 다른 DB, 포트, 설정이 적용되도록 구성테스트 도중 DB 변경 방지를 위해 자동 롤백 + @AfterEach 정리 수행어노테이션역할@SpringBootTest전체 애플리케이션 컨텍스트 로딩@DataJpaTestJPA 관련 빈만 주입, 빠른 테스트 가능미션Day 11https://github.com/Goddohi/warming-up-readable-code/tree/study/day11 회고이번 주는 단순히 테스트 코드를 작성하는 것이 아니라각 계층의 역할에 맞춘 책임 분리와 테스트 전략 수립의 중요성을 몸소 느낄 수 있던 시간이었다.특히 레이어드 구조를 이해하고,Persistence는 데이터 검증에만 집중하고Business는 로직 흐름과 트랜잭션을,Presentation은 외부 입력에 대한 응답 및 검증에만 집중하는테스트의 방향성과 목적을 처음 명확히 잡아볼 수 있었다.이번에는 회사 출근과 프로젝트가 야간근무도 몰려서 많은 정리를 못해서 중구난방이라아직 잘 이해를 못한 점이 많다.더 한번더 복습이 필요하다.

백엔드백엔드워밍업클럽4기워밍업클럽

dohi

워밍업 클럽 4기 - 백엔드 2주차 회고

수정내역썸네일 추가2주차 회고강의 수강리팩토링에 대해서 배운점을 회사 본업을 하면서 실전 적용도 해봤다회사에서는 리팩토링에 대해서 왜 그렇게 수정하는지 잘 적어만 준다면 다 허락을 해줬다.실제로 중복 코드가 많은 부분은 리팩토링으로 정리 시켰고강의를 보면서 중요시 생각한 점객체에게 바로 예의없이 꺼내지않기객체에 대한 메서드로 해결 주석에 대한 양면성회사에서 관련된 주석이 많았는데몇몇개는 친절한 주석도 있었으나 너무 주석이 많았다.좋은 주석을 달아보려고 해야한다.변수와 메서드의 나열 순서테스트만들고 테스트하는 것은 통과하기 위한 테스트를 제작할 가능성이 있고테스트를 하고 만들면 통과 하기 위한 기능을 만들 수가 있다라는 생각.미션Day 7https://github.com/Goddohi/warming-up-readable-code/tree/study/studycafe회고회고에 적으려고 미션을 아주 짧게 적었었는데코드 리뷰를 멘토님께서 디테일 하게 해주셨는데코드 리뷰를 해주시면서 선배개발자로써의 개념으로 이야기를 해주셧고 다른 사람의 코드를 볼 수있는 경험이 좋았다.이번주는 회사일이 많이 바빠서 이동하면서 듣느라 작성할 만한 문건을 만들지 못했지만들을때마다 도움되는 개념이였던 만큼 한번더 다시 한번더 듣고 정리 해야겠다

워밍업클럽백엔드워밍업클럽4기

dohi

워밍업 클럽 4기 - 백엔드 1주차 회고

수정내역썸네일 추가1주차 회고강의 수강‘추상과 구체’ 과제를 통해 추상 개념에 대해 다시 한번 생각해볼 수 있었다.매직 넘버를 접하며, 추상적인 값은 별도 변수로 분리해 명확하게 표현하는 것이 중요하다는 점을 알게 되었다.추상화 레벨 개념을 통해 코드의 표현 단계와 책임 분리에 대해 고민해보는 계기가 되었다.내 코드를 분석하면서, 읽는 사람이 뇌의 메모리를 얼마나 사용할지 생각해보았고, 얼리 리턴을 적용해 리팩토링을 시도했다.특히 ‘부정어를 대하는 자세’에서는 코드에 부정 표현이 들어갈 때의 가독성과 인지 부담에 대해 다시 생각해보게 되었다.이점은 왜 이렇게 사용해야할 까 라는 생각을 했었지만 SOLID에서 이렇게 많이 사용하는 구나를 하면서 배우게 되었다.과제를 직접 수행하면서, 배운 내용을 실전에서 적용해보며 리팩토링 감각을 조금씩 익혀갔다.SOLID 원칙 각 요소를 복습할 수 있었고, 이를 실제 코드에 어떻게 적용해볼 수 있을지 고민해보는 기회가 되었다.특히 getter setter에 사용에 대해서 고려를 많이 하게 되었다.  미션Day 2추상을 고려할때 일단 사람들 간에 약속적인 의미로 생각하였다구체에는 자세하게 적었지만 불필요한 내용을 간추리기 라고 생각하였다. Day 4AS-IS에 있는 코드를 다 분석하고 TO-BE에는 배운 코드를 다 이용하려고 하였다해당 과제에 자세하게 적긴했지만일단 미리 리턴을 하도록 정리하였고부정어 처리그후 예외처리로 마무리하였다. SRP :한 클래스는 딱 하나의 역할만 하자.OCP :기존 코드를 고치지 않고, 기능을 확장할 수 있어야 한다.LSP:부모 타입을 사용하는 곳에 자식 타입을 써도 제대로 작동해야 한다.ISP :쓸데없는 인터페이스는 나눠서 큰 종합세트를 주지말고 작은 인터페이스 여러개가 좋다DIP:고수준 모듈은 저수준 모듈에 의존하지 말고, 추상(인터페이스)에 의존하자.

백엔드워밍업클럽워밍업클럽4기백엔드워밍업클럽백엔드

sein

[워밍업 클럽 4기 - 백엔드] Day 18 미션

미션@Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 정리@Mock 순수 자바 환경의 테스트 단위에서도 사용할 수 있다.가짜 객체를 생성한다. 실제 로직은 없다.행위에 대한 기대를 명세하고 그에 따라 동작하도록 한다.보통 테스트 대상 클래스의 의존 객체를 대체할 때 사용한다. @MockBean스프링 부트 환경 같이 Bean을 사용하는 통합 테스트에서 사용할 수 있다.스프링의 올라가있는 실제 Bean을 Mock 객체로 교환한다. @Spy순수 자바 환경의 테스트 단위에서도 사용할 수 있다.stub이면서 호출된 내용을 기록하여 보여줄 수 있는 객체다.일부는 실제 객체처럼 동작시키고, 다른 일부만 stubbing할 수 있다. 즉, 선택적 구현과 mocking을 섞어 사용할 수 있다. @SpyBean스프링 부트 환경 같이 Bean을 사용하는 통합 테스트에서 사용할 수 있다.기존 Bean을 Spy 객체로 감싸 실제 로직을 유지하면서 특정 메서드만 moking 한다. @InjectionMock순수 자바 환경의 테스트 단위에서도 사용할 수 있다.mock 객체를 자동으로 주입해준다.테스트 대상 객체에 mock된 의존성 객체들을 자동으로 주입한다. 즉, 스프링의 도움을 받지 않고 의존성을 주입할 때 사용한다.  테스트 코드 리팩토링@BeforeEach void setUp() { 1-1. 댓글 레포지토리.deleteAllInBatch(); 1-2. 게시글 레포지토리.deleteAllInBatch(); 1-3. 사용자 레포지토리.delteAllInBatch(); } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-1. 사용자 생성 - createUser() 호출 1-2. 게시물 생성 - createPost() 호출 // when 1-3. 댓글 생성 - createReply() 호출 // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 2-1. 사용자 생성 - createUser() 호출 2-2. 게시물 생성 - createPost() 호출 2-3. 댓글 생성 - createReply() 호출 // when 2-4. 댓글 수정 // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-1. 사용자1 생성 - createUser() 호출 3-2. 게시물1 생성 - createPost() 호출 3-3. 댓글1 생성 - createReply() 호출 3-4. 사용자2 생성 - createUser() 호출 // when 3-5. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 } private User createUser() { 1-1. 사용자 생성에 필요한 내용 준비 1-2. 사용자 생성 } private Post createPost() { 1-1. 게시물 생성에 필요한 내용 준비 1-2. 게시물 생성 } private Reply createReply() { 1-1. 댓글 생성에 필요한 내용 준비 1-2. 댓글 생성 } 한마디강의에서 배웠던 내용을 잘 적용해볼 수 있었던 미션같아서 한 번 더 정리하는 느낌이라 좋았다. 마지막 미션까지 달릴 수 있어서 뿌듯함 100배 출처인프런_워밍업_클럽_4기_BEPractical Testing: 실용적인 테스트 가이드

백엔드워밍업클럽박우빈백엔드테스트코드

sein

[워밍업 클럽 4기 - 백엔드] Day 16 미션

미션MVC 기반에서 가장 많이 사용되는 3티어 레이어별로 특징과 테스트 방법을 정리해보자! Layered Architecture 일반적으로 controller(presentation) -> service(business) -> repository(persistence) 구조로 이루어져있다.레이어를 단계적으로 구분하는 이유는 관심사 분리가 목적이다. persistence LayerDB와 직접적인 소통을 하는 계층이며 CRUD 쿼리 작업을 처리한다.Business 계층에서 넘어온 데이터를 처리한다.주로 JPA와 QueryDSL을 사용한다.  테스트 방법클래스 레벨에서 @SpringBootTest, @DataJpaTest 어노테이션을 사용할 수 있다.@SpringBootTest를 사용하는 것을 더 추천한다(다른 테스트와의 환경 통합을 위해)작성한 쿼리가 의도대로 동작하는지 테스트한다. business Layer비즈니스 로직이 메인이다.presentation에서 데이터를 받으며 중요 비스니스 로직을 수행하고 persistence 계층으로 전달하는 중간다리 역할을 한다.  테스트 방법클래스 레벨에 @SpringBootTest를 사용하거나 Mock을 사용하는 경우 @ExtendWith(MockitoExtension.class)를 사용한다. 이 역시 환경의 통합을 위해 되도록이면 SpringBootTest를 사용하는 것이 좋다. 스트 객체를 생성할 때 관련 테스트 메서드에는 꼭 필요한 데이터만 파라미터로 넘겨받아 빌더 패턴을 활용한다.단위 테스트를 작성할 수도, persistence 계층와 통합해서 테스트할 수도 있다. presentation Layer외부 세계를 제일 처음 맞이하는 계층이다. 또한 외부 세계에 응답 데이터를 전달해주는 계층이다.  테스트 방법사용자 요청의 데이터에 최소한의 검증을 해야한다. (validation) 다만, 타입의 유효성 자체에 대한 검증이 아닌 도메인과 관련된 검증들은 presentation 계층이 아닌 더 내부에서 진행한다.클래스 레벨에 @WebMvcTest(className.class)를 사용한다.mock을 사용한다.직렬화, 역직렬화를 위해 ObjectMapper 객체가 필요하다.   출처인프런_워밍업_클럽_4기_BEPractical Testing: 실용적인 테스트 가이드

백엔드워밍업클럽박우빈테스트코드MVC

호준

[인프런 워밍업 클럽 4기 - DevOps] 미션 2. Probe 응용과제

미션 전 사전 준비HPA minReplica 1로 바꿔서 Pod 1개로 진행 ▶ 응용1 : startupProbe가 실패 되도록 설정해서 Pod가 무한 재기동 상태가 되도록 설정해 보세요.대시보드 > 디플로이먼트 > 편집으로 아래 구문 수정, 기존 레플리카 셋 제거startupProbe: httpGet: path: "/startup" port: 8080 periodSeconds: 5 failureThreshold: 1 ▶ 응용2 : 일시적 장애 상황(App 내부 부하 증가)가 시작 된 후, 30초 뒤에 트래픽이 중단되고, 3분 뒤에는 App이 재기동 되도록 설정해 보세요.대시보드 > 디플로이먼트 > 편집으로 아래 구문 수정, 기존 레플리카 셋 제거readinessProbe: httpGet: path: "/readiness" port: 8080 periodSeconds: 10 failureThreshold: 3 livenessProbe: httpGet: path: "/liveness" port: 8080 periodSeconds: 60 failureThreshold: 3부하가 발생한 직후에는 API 요청이 성공하였으나, 30초 후 요청이 차단된 것 확인60초 간격으로 livenessProbe 3번 실패 후 App 재시작 확인 ▶ 응용3 : Secret 파일(/usr/src/myapp/datasource/postgresql-info.yaml)이 존재하는지 체크하는 readinessProbe를 만들어 보세요.대시보드 > 디플로이먼트 > 편집으로 아래 구문 수정, 기존 레플리카 셋 제거readinessProbe: exec: command: ["cat", "/usr/src/myapp/datasource/postgresql-info.yaml"] periodSeconds: 10 failureThreshold: 3해당 파일은 존재하므로 실패 로그 확인 불가.

데브옵스 · 인프라쿠버네티스워밍업클럽

sein

[워밍업 클럽 4기 - 백엔드] Day 4 미션

미션아래 코드와 설명을 보고, [섹션 3. 논리, 사고의 흐름]에서 이야기하는 내용을 중심으로 읽기 좋은 코드로 리팩토링해 봅시다.[as-is]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; } [to-be]public class Day4 { public boolean validateOrder(Order order) { try { isOrderItemsEmpty(order); isCustomerInfoEmpty(order); isTotalPricePositive(order); System.out.println("유효성 검사를 통과했습니다."); return true; } catch (IllegalArgumentException e) { System.out.println(e.getMessage()); return false; } } private static void isCustomerInfoEmpty(Order order) { if(!order.hasCustomerInfo()) { throw new IllegalArgumentException("사용자 정보가 없습니다."); } } private static void isTotalPricePositive(Order order) { if(order.getTotalPrice() < 0) { throw new IllegalArgumentException("올바르지 않은 총 가격입니다."); } } private static void isOrderItemsEmpty(Order order) { if(order.getItems().isEmpty()) { throw new IllegalArgumentException("주문 항목이 없습니다."); } } } class Order { private final List<Item> orderItem = new ArrayList<>(); private Customer customer; public void setItem(Item item) { orderItem.add(item); } public void setCustomer(Customer customer) { this.customer = customer; } public List<Item> getItems() { return orderItem; } public int getTotalPrice() { int totalPrice = 0; for(Item item : orderItem) { totalPrice += item.getPrice(); } return totalPrice; } public boolean hasCustomerInfo() { return customer != null; } } class Customer { private String id; public Customer(String id) { this.id = id; } } class Item { private final int price; public Item(int price) { this.price = price; } public int getPrice() { return price; } }수업에서 배운 내용들을 차분히 적용하도록 노력했다. 다음과 같은 순서로 리팩토링을 진행했다.메인인 validateOrder() 메서드 외엔 추상화를 적용하지 못했다. (시간이 없..어서) Early return복잡하게 얽혀있던 if-else문을 뜯어내 if문을 최소화했다. 메서드 추상화메서드의 경우엔 이름이 정말 고민 많았는데, 일단 세 메서드 다 isXXX로 통일시켰다.예외처리예외 처리를 통해 유효성 검사가 통과되지 않았을 때의 로직을 통일했다. return false를 하나하나 써주지 않아도 됐다. 테스트 결과public void run() { System.out.println("======= 시작 ======="); Order order1 = new Order(); validateOrder(order1); // "주문 항목이 없습니다." Order order2 = new Order(); Item item = new Item(1000); order2.setItem(item); validateOrder(order2); // "사용자 정보가 없습니다." Order order3 = new Order(); Item item2 = new Item(-10); order3.setCustomer(new Customer("id3")); order3.setItem(item2); validateOrder(order3);// "올바르지 않은 총 가격입니다." Order order4 = new Order(); Item item4 = new Item(1000); order4.setCustomer(new Customer("id4")); order4.setItem(item4); validateOrder(order4); // "유효성 검사를 통과했습니다." } SOLID에 대하여 자기만의 언어로 정리해 봅시다.SRP : Single Responsibility Principle / 단일 책임 원칙이상적인 사회 모습. 회사에서 한 사람 당 하나의 책임만 가졌으면 좋겠는 것 처럼, 객체는 단 하나의 책임만 가져야 한다. 하나의 객체가 여러 책임을 가질 경우 변경 시 파급력이 크다. OCP : Open-Closed Principle / 개방-폐쇄 원칙열린교회 닫힘. 새 신도는 환영하면서 문을 열어주지만 나갈때는 아니란다. 소프트웨어 요소는 확장에는 열려있어야 하고 변경에는 닫혀있어야 한다. 추가적인 요구사항에 유연하게 확장할 수 있어야한다. 기능 추가 시 최소한의 코드를 수정해야 함(물론 로직에 직접적인 영향을 주는 코드는 수정 X)  LSP : Liskov Substitution Principle / 리스코프 치환 원칙자식은 부모의 거울이다! 자식 클래스는 부모 클래스의 기능을 정확하게 확장해야한다. ISP : Interface Segregation Principle / 인터페이스 분리 원칙객체와 똑같다. 하나의 인터페이스에 너무 많은 기능을 넣으면 원치않는 의존성이 생길 수 있다. DIP : Dependency Inversion Principle / 의존 역전 원칙구현체가 아닌 추상에 의존해야 한다. 구현체에 의존하게 되면 어떠한 인터페이스에 대한 구현체가 바뀔 때마다 다른 코드에 영향을 줄 수 있다 !! 결합도를 낮추고 유연한 구조를 만든다.  출처인프런_워밍업_클럽_4기_BEReadable Code: 읽기 좋은 코드를 작성하는 사고법

백엔드클린코드워밍업클럽박우빈

leeebug

워밍업 클럽 스터디 3기 FS - 2주차 발자국

인프런 워밍업 클럽 스터디에 참여하고 벌써 2주 차도 마무리에 접어들고 있다. 4주간의 스터디이기 때문에 생각보다 일정이 타이트하여 시간관리가 무엇보다도 중요한 시기라고 생각한다.이번 주에는 파일 업로드 기능을 구현해야하기에 1주 차 과제를 급하게 마무리하고 지난주 토요일부터 서둘어서 미리 학습을 시작했다.깃 레포지토리의 경우에는 지난주에 사용했던 템플릿을 거의 수정없이 그대로 사용해서 개발환경 구축은 크게 어렵지 않았다.이번 주 강의에서는 Supabase Storage를 사용했는데 API가 잘 준비되어있어서 사용 방법을 익히는데도 크게 어렵지는 않았다. 다만 아래에서도 언급하겠지만 Supabase Storage는 AWS S3 기반으로 구현되어 강력한 네이밍 규칙이 적용되어 개인적으로는 Supabase Storage와 Supabase DB를 함께 사용했다. 📝 2주차 학습Supabase Storage클라우드 기반 객체 저장소로, AWS S3와 유사한 방식으로 파일을 저장하고 관리하는 서비스파일 및 이미지 업로드 및 관리 기능 제공PostgreSQL과 연동 가능권한 관리(RLS) 및 퍼블릭/프라이빗 파일 설정 가능Supabase SDK 또는 Restful API로 사용 가능  ✔ 파일명 규칙 (Supabase & AWS 공통) ASCII 문자, 숫자, 일부 특수 문자 허용 (- _ . /) 파일명을 /로 구분하여 폴더처럼 사용 가능 (folder/image.png) 공백 포함 가능하지만, URL Encoding이 필요할 수 있음 파일명에 한글, 이모지, 특수문자가 포함될 경우 정상적으로 업로드되지 않을 가능성이 있음 → URL-safe 변환 권장 React DropzoneReact에서 간편하게 파일 Drag & Drop 기능을 구현할 수 있는 라이브러리HTML5 File API를 활용하여 파일 업로드를 쉽게 구현할 수 있는 기능을 제공파일 타입, 크기, 개수 등 다양한 제약 조건 설정 가능비동기로 파일을 처리할 수 있는 onDrop 이벤트 제공 📋 2주차 미션💬 GitHub 저장소🚀 데모 영상 보러가기미션 해결 과정 요약2주 차 미션은 Next.js, React Query, TailwindCSS를 사용하여 이미지 업로드 앱을 구현하기였다. 필수 구현 기능으로는 이미지 업로드 기능(클릭 업로드 방식과 Drag & Drop 방식, 다중 업로드)과 이미지 삭제와 이미지 검색 기능 구현하기였다. 추가 기능은 파일의 마지막 수정 시간을 화면에 출력하는 UI 구현하기였다. 여기에 과제의 완성도를 높이기 위해서 개인적인 챌린지로 파일명에 한글 또는 특수문자 포함된 파일 업로드 기능, 1MB 미만으로 이미지를 압축하는 기능, 다운로드 기능을 추가로 구현하였다. 과제 추가 구현 기능✅ 마지막 수정 시간 표시const { error: insertError } = await supabase.from(DB_TABLE_NAME).insert({ name: file.name, originalName: originalFileName, imageId: uploadedFile.id, imageUrl: publicUrl, createdAt: new Date(file.lastModified).toISOString(), })생성: DB에 파일 데이터 업로드 시 createdAt에 file.lastModified를 ISOString 형식으로 저장 if (dbData) { const { error: updateError } = await supabase .from(DB_TABLE_NAME) .update({ name: file.name, originalName: originalFileName, imageUrl: publicUrl, updatedAt: new Date().toISOString(), }) .eq('imageId', uploadedFile.id)수정: DB에 해당 ID가 존재할 경우 updatedAt(string | null)에 현재 시간을 ISOString 형식으로 저장// DropImageManager 컴포넌트에서 생성 시간, 수정 시간을 포멧팅하여 DropImage 컴포넌트에 프롭스로 전달 const localCreatedAt = getLocalTime(image.createdAt) const localUpdatedAt = image.updatedAt ? getLocalTime(image.updatedAt) : null <!-- JSX 정렬이 잘 안되서 렌더링 형태만 봐주세요! --> <div className="w-5/6 truncate"> <span className={`text-[0.7rem] font-semibold ${localUpdatedAt ? 'text-mint-800' : 'text-gray-500'}`} > {localUpdatedAt ? localUpdatedAt : localCreatedAt} </span> {localUpdatedAt && ( <span className="text-[0.7rem] font-semibold text-mint-800"> (수정)</span> )} </div>출력: updatedAt이 존재할 경우 updatedAt과 (수정) 을 함께 출력, updatedAt: null이라면 createdAt를 출력 개인 챌린지 기능✅ 파일명 자동 변환 후 이미지 업로드하는 기능을 구현 (UX 개선)파일명 검증: 정규식을 활용하여 한글 및 특수 문자 포함 여부를 확인자동 변환: 검증 후 8자리 랜덤 문자열로 안전한 파일명 생성업로드 처리: 변환된 파일명으로 File 객체 생성 후 formData.append로 원본 파일명 함께 전송서버 액션: Supabase Storage에 저장 후, 완료 시 DB에 메타데이터 저장하여 연동결론: 파일명 변환을 자동화하여 업로드 오류를 방지하고, 원본 파일명도 유지하여 검색 및 관리 UX 개선✅ 파일 용량이 1MB 초과 시 자동 압축 후 업로드하는 기능을 구현 (UX 개선)browser-image-compression 라이브러리를 사용하여 파일의 용량 검증 후 1MB 초과 시 이미지 압축 후 업로드결론: 이미지 최적화로 업로드 속도 향상, 스토리지 비용 절감 효과✅ Blob URL을 활용한 다운로드 기능 추가 (UX 개선)Blob URL 생성: 업로드된 이미지를 fetch()로 가져와 Blob으로 변환다운로드 기능 구현: window.URL.createObjectURL(blob)으로 브라우저에서 직접 다운로드 가능하도록 처리결론: Blob URL 다운로드 방식을 적용하여 최적화된 이미지를 빠르게 다운로드 받을 수 있도록 개선🚧 기능 구현 시 어려웠던 부분Supabase Storage에 전달하는 File 객체 커스텀 불가원본 파일명을 추가하려 했으나, File 객체 자체를 수정하는 것이 제한적이다.파일 객체를 복사하여 원본 파일명을 추가하는 방법 시도전개 연산자를 사용하여 객체 복사 후 원본 파일명을 추가하려 시도하였으나 file 객체는 일반적인 방법으로는 복사할 수 없는 특별한 객체이다.ExtendedFile 확장 클래스로 인스턴스를 생성했으나 서버에 전달되지 않는 문제 발생확장된 ExtendedFile 객체를 formData에 담아 서버로 전송했지만, 서버에 정상적으로 전달되지 않았다.최종 해결 방법formData.append("file", file) formData.append("originalFileName, file.name)file 객체와 원본 파일명을 함께 서버로 전송 후 가공하여 Supabase Storage의 파일명에는 안전한 파일명만 저장하고 DB에 스토리지Id, 원본 파일명, 안전한 파일명, 이미지URL 등 정보를 저장했다. 🧾 ERD 다이어그램👀 2주차 회고아직 갈 길이 멀지만, 리팩토링을 통해 Next.js의 장점을 살릴 수 있는 구조로 점점 개선되어가는 과정을 경험하면서 이번 주 역시 알차게 보냈다고 생각한다.이번 주는 특히 MVP 패턴과 비슷한 형태로 컴포넌트 구조를 잡는 것에 익숙해지는 것을 개인적인 목표로 삼았다. 처음부터 MVP 패턴을 염두해 두고 설계한 것은 아니었지만, 진행하다보니 자연스럽게 MVP와 유사한 패턴으로 정리되어 가는 것을 느꼈다.화면 렌더링 시 상호작용이 필요하지 않은 정적인 요소들까지 클라이언트 컴포넌트로 관리하면 불필요한 하이드레이션 부담이 증가할 수 있다는 점을 다시 한번 체감했다.클라이언트 컴포넌트 내에서도 역할을 나눠 서비스 레이어나 상태 관리만 담당하는 매니져 컴포넌트와 프롭스로 상태를 전달받아 단순히 화면을 렌더링을 담당하는 UI 컴포넌트로 분리하는 연습을 진행했다.이러한 구조로 개선하면서 클라이언트 컴포넌트의 부담을 줄이고, 유지보수성을 높이는 방향으로 점차 최적화되고 있다는 점이 느껴졌다. 아직 개선해야 할 부분이 많지만 점진적으로 개선하여 더 나은 아키텍쳐를 만들어가는 과정이 의미 있었다고 생각한다.

풀스택워밍업클럽3기발자국회고과제미션

대롱대롱

인프런 워밍업 클럽 2기 CS 후기 및 오프라인 수료식 후기

인프런 워밍업 클럽이 끝났습니다한달간의 여정이 끝났네요오프라인으로 수료식을 한다기에 냉큼 달려갔습니다어떤 분들과 같이 스터디를 했는지 궁금했기 때문이죠 이번에 판교를 처음 가봤습니다지하철로 판교역까지 가서 한 20분 걸으면 목적지가 나옵니다판교 구경도 할 겸 좀 걸어봤습니다 판교테크노스타트업캠퍼스 3층 인프랩에 도착해서 이름표 받고 들어갔습니다올 때까지는 조용했는데 인프랩에 들어가고 나니 와글와글 하더라구요많은 분들이 오셨는데 저는 아는 얼굴도 없고 파워I라서 일단 조용히 앉아있었습니다(사람 많은 곳을 갔을 때 흔한 I의 모습) 간단한 식사로 피자와 음료가 제공되었어요알콜/논알콜 음료로 구분되었는데 저는 알콜 음료를 집었습니다이때 아니면 회사에서 언제 알콜을 마셔보겠습니까ㅎㅎㅎ스터디 종류에 따라 회의실에 모여서 네트워킹을 진행했어요저는 CS스터디를 들었기 때문에 CS 스터디원들이 모인 곳으로 갔습니다회의실 이름이 볼드모트인가... 암튼 그랬습니다저 혼자 알콜 먹나 했는데 한 분 더 있어서 서로 위안이 되었습니다먼저 간단하게 자기소개부터 시작했는데 백엔드와 프론트엔드 분들이 많더군요AI는 저 혼자더라구요... AI스터디로 열어줘요....현업에 계신 분들도 많아서 오 신기하다하고 그분들이 얘기를 들었죠고등학생 분도 있었는데 벌써 진로를 정하고 움직이다니 대단하다고 생각했습니다 네트워킹 이후에는 온라인 접속자들과 함께하는 Q&A 시간이 진행되었습니다질문들 중에서 주요 질문 5개만 감자님이 뽑아서 답변을 해주셨습니다 Q&A까지 마치고 다시 모든 참여자들이 한자리에 모였어요코치분들 소개가 진행된 후 스터디별로 우수러너 시상이 진행되었어요CS스터디가 가장 마지막 발표라서 옆에 앉은 분이랑 이런저런 이야기하고 있었는데 놀랍게도 옆에 분과 제가 우수러너로 발표되었어요되면 좋겠는데... 안되면 슬프겠지만 어쩔 수 없지...의 마인드였는데 받으니까 좋았습니다우수러너 혜택으로 인프런 한정판 굿즈와 1:1멘토링권이 주어졌어요에코백 안에 유리컵이랑 우산이랑 미니미한 뱃지가 들어있었는데 굉장히 귀엽습니다우수러너가 되길 너무 잘한 것 같아요(초록초록한 캐릭터 너무 귀엽습니다)(가슴팍에 새겨진 깨알같은 인프런 워밍업클럽. 이런 디테일을 제가 아주 좋아합니다) 아무튼 이렇게 인프런 워밍업 스터디가 진짜 끝났습니다뭔가 시원섭섭하고 그러네요다음번에는 어떤 스터디가 열릴지 기대됩니다AI 스터디도 열렸으면 하는 바램이 있습니다^^수료식 준비하신 스탭분들과 코치님들 모두 고생많으셨습니다다음에 기회가 되면 또 만나요~~      

워밍업클럽CS스터디수료식

김예지

[인프런 워밍업 스터디 클럽 2기 FE] 오프라인 수료식 후기

 오프라인 수료식 후기 퇴근하고 판교까지 늦지 않게 갈 수 있을까 걱정했는데 다행히 여유 있게 도착해서 이름표를 받았다.안으로 들어가니 이미 많은 분들이 일찍 도착해 계셨다.  코치님이랑 다른 러너분들이랑 자기소개도 하고 피자 먹으면서 자유 네트워킹 시간을 가졌다. 발자국을 남길 때 봤던 분들을 직접 만나게 되어서 좋았다. 다들 좋으신 분들이라 오프라인 수료식에 갈지 말지 고민했던 게 무색하게 재밌던 시간이 되어서 오길 잘했다는 생각이 들었다. 잠깐의 쉬는 시간이 지나고 시작된 Q&A 시간도 좋았다. 코치님께서 하나하나 해주시는 답변들이 정말 큰 도움이 되었다. 메모를 조금 하고 싶었는데 필기도구도 안 챙겼고.. 핸드폰에 쓰면 딴짓하는 사람처럼 보일까 봐 최대한 기억만 했다.그리고 하고 싶었던 질문이 있어서 할까 말까 고민하고 있었는데 마침 다른 분이 물어봐 주셔서 내 궁금증도 같이 해소가 되었다. 다른 분들은 어떤 고민을 하고 어떤 생각을 하시는지 들을 수 있는 점도 좋았다.궁금했던 부분도 해결하고 모르는 것들도 많이 알게 되어서 유익한 시간이었다. 자유 네트워킹, Q&A 시간이 너무 빠르게 지나간 것 같아서 아쉽다는 생각이 들었다. 다른 분들이랑 얘기를 더 나누고 싶었다.  이번에 워밍업클럽 신청하길 잘한 것 같다. 3주동안 열심히 했던 만큼 성장한 부분이 있다고 생각한다.      귀여운 인프런 굿즈가 생겼다 ✌  

워밍업클럽

채널톡 아이콘