블로그

Rojojun

[워밍업 클럽 스터디 2기::백엔드] 1주차 발자국

1주일간의 학습 회고이번 한 주 동안 운이 좋게도 시간을 내어 강의를 모두 들을 수 있었다. 강의를 들으면서 강사님이 예제로 주신 프로젝트를 리팩토링하는 시간을 가졌고, 이를 어떻게 하면 더 효율적으로 리팩토링할 수 있을지 고민도 많이 했다. 나의 개발 철학: 누구나 이해할 수 있는 코드내가 코드를 작성할 때 가장 중요하게 생각하는 점은 바로 누구나 이해할 수 있는 코드다. 아무리 정교하고 복잡한 로직이라도 나 외에 다른 사람들이 이해하지 못한다면, 코드 자체는 잘 작성했을지 모르지만 그 코드는 좋은 코드라고 할 수 없다. 개발자는 혼자 일하는 것이 아니라 여러 명과 협업하는 직업이다. 또한 코드는 끊임없이 변화하고 발전하는 유기체라고 생각한다. 그렇기에 모든 사람이 이해할 수 있고, 지속적으로 유지보수할 수 있는 코드가 좋은 코드라고 생각한다. 이번 주 학습에서 잘한 점이번 주 학습에서 내가 스스로 잘했다고 생각한 부분은 기존에 알고 있던 개념들, 예를 들어 톰 롱의 좋은 코드 나쁜 코드, 켄트 백의 Tidy First, 로버트 C. 마틴의 클린 코드와 같은 책에서 배운 내용을 확장시켰다는 점이다. 또한, 내가 경험한 부분들을 도입해서 좀 더 깊이 있게 이해하려고 노력했다는 점이 좋았다. 아쉬웠던 점: 집중력 유지의 어려움하지만 아쉬웠던 점도 있었다. 집중력 유지가 생각보다 쉽지 않았던 것이다. 외부적 요인이든 내부적 요인이든 컨디션에 따라 학습의 진도가 들쑥날쑥했다. 컨디션이 좋은 날은 많은 진도를 나갔지만, 좋지 않은 날은 적은 진도를 공부하게 됐다. 그럼에도 꾸준히 공부하고 성취를 이뤄냈다는 점은 매우 중요한 성과다. 이번 주에 목표했던 학습을 어느 정도 완료했고, 다가오는 한 주는 더 구체적인 목표를 세워 동료와 함께 학습 내용을 토론하며 우리 회사에 적용해 볼 계획이다. 실습과 이론이 어우러진 미션이번 주차에는 두 가지 미션이 주어졌다. 하나는 구체라는 개념을 일상생활에 빗대어 설명하는 미션이었고, 다른 하나는 주어진 코드를 SOLID 원칙에 맞게 리팩토링하는 과제였다. 구체를 일상생활에 빗대어 설명하는 과제는 매우 흥미로웠다. 프로그래밍을 공부하다 보면 언어 자체가 번역투로 이루어져 있거나 어려운 용어가 많아 쉽게 이해하기 힘들 때가 많다. 하지만 일상생활에 비유해 설명하니 훨씬 쉽게 이해할 수 있었고, 동료들에게도 설명할 때 유용했다. SOLID 원칙 과제에서는 내가 생각하는 중복 문제를 예시로 들고 설명했다. 이 과정에서 초등학생에게 설명한다는 가정하에 설명을 시도해 보았다. 초등학생도 이해하지 못한다면, 나 역시 완전히 이해하지 못한 것이기 때문이다. 이는 전문가는 어려운 개념을 쉽게 설명할 수 있지만, 사기꾼은 쉬운 개념을 어렵게 설명한다는 유명한 말과 일맥상통한다. 회사 팀원들과의 협업이번 스터디는 회사 팀원들과 함께 진행하고 있는데, 팀원들과 함께 성장할 수 있는 좋은 기회가 되고 있다. 강의 내용도 매우 만족스러웠고, 팀원들의 반응도 긍정적이다. 누군가 이 강의를 추천하냐고 물어봤을 때, 나는 이렇게 대답했다. “클린 코드 책 읽어보셨나요? 읽으셨다면 좋은 강의고, 안 읽으셨다면 꼭 들어야 할 강의에요.” 클린 코드는 한 사람의 의견만이 정답은 아니라고 생각한다. 여러 사람의 이야기와 경험이 모여야 비로소 읽기 좋은 코드가 완성된다고 본다.

백엔드클린코드백엔드

gusdnchl7144

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

 Section2) 추상Clean Code를 추구해야 하는 이유나를 포함해 다른 개발자가 코드를 읽고 이해하는데 드는 시간이 절약된다.프로그램의 정의프로그램 = (데이터가 담긴) 변수 + (변수를 사용하는) 메서드의 집합추상중요한 정보는 가려내어 남기고, 덜 중요한 정보는 생략하여 버리는 것적절한 추상화 : 도메인 안에서, 정말 중요한 핵심 개념만 남겨서 표현하는 것이다.추상화의 가장 대표적인 행위는 이름을 짓는 것이다.(변수) 이름 짓기 Tip1) 단수와 복수 구분- 끝에 '(e)s'를 붙여 구분2) 이름 줄이지 않기- 일반적으로 무엇이든 이름을 줄여서 사용하는 것은 가독성을 제물로 바쳐 효율성을 얻는 것인데,유지보수 관점에서 득보다 실이 크다.- 관용어 처럼 자주 사용하는 것은 줄여도 괜찮다.=> ex, column -> col, latitude -> lat=> count -> cnt (추천X)3) 은어/방언 사용X- 현재의 팀만 아는 용어 사용 금지4) 좋은 코드를 보고 습득하기메서드와 추상화한 메서드는 반드시 한가지 일만 해야 한다.2가지 일을 하게된다면 추상화된 내용(==메서드 선언부)을 보고 구체적인 내용(메서드 구현부)의 유추가 어렵다.추상화 레벨외부 세계(==추상화 레벨이 높은 세게)와 내부세계(==추상화 레벨이 낮은 구체)를 나누었을때 추상화 레벨이 달라지는데, 하나의 세계 안에서 각 로직의 추상화 레벨은 동등해야 한다.매직 넘버, 매직 스트링매직 넘버(스트링) : 의미를 갖고 있으나, 상수로 추출되지 않은 숫자, 문자열 등을 말한다.Mission 1) 생각나는 추상과 구체의 예시Execute Login1) 클라이언트가 서버에 암호화된 ID와 Password를 HTTP Body에 담아 Request를 보낸다.2) 서버는 ID와 Password를 복호화하고 각 필드에 대한 유효성 검사를 한다.3) 유효하다면, 복호화된 ID와 Password를 DB에 보내 가입된 유저인지 확인한다.4) 가입된 유저라면, Session Cookie 혹은 JWT 등에 사용자 정보를 담아 클라이언트에 Response로 보낸다.Section3) 논리, 사고의 흐름뇌 메모리 적게 쓰기최소의 인지적 노력으로 (뇌 메모리를 줄여) 최대의 정보를 제공해야 한다,Early returnelse (if) 대신 return을 사용하는 것을 권장한다,.사고의 Depth 줄이기1) 중첩 반복문을 메서드 혹은 Stream을 통해 개선하면 좋다.2) 사용할 변수는 가깝게 선언하기공백라인도 의미를 가진다.부정어if문에서 부정어(!) 사용시 메서드화하여 분리하기해피케이스와 예외처리1) 예외가 발생할 가능성을 낮추는게 좋다. (ex, 사용자 입력, 객체 생성자, 외부 서버의 요청 등)2) 의도한 예외(ex, Custom Exception)와 예상하지 못한 예외 구분하기3) NullPointException은 항상 발생하지 않게 해야 한다.- 메서드 설계시 return null을 자제하고, Optional 사용을 고려하기 - Optional의 orElse(), orElsGet(), orElseThrow() 메서드의 차이 이해 필요.Section4) 객체지향 패러다임객체 설계1) 새로운 객체 생성시 주의사항- 1개의 관심사로 명확하게 책임이 정의되었는지 확인 필요- 생성자, 정적 팩토리 메서드에서 유효성 검증이 가능함을 인지- setter 사용 자제- getter도 사용 자제하고, 반드시 필요한 경우에만 추가 - 필드의 수는 적을수록 좋다2) 도메인 지식은 만드는 것이 아니라 발견하는 것Mission 2-1) 읽기 좋은 코드로 리팩토링#중요하게 생각한 점1) order 객체 Null 체크 필요2) if-else문들 if문으로 개선3) 부정어구(!) 없애기4) getter 제거 → 객체에 의미가 담긴 메서드를 별도 생성5) 공백라인 사용public boolean validateOrder(Order order) { //1) Null Check if (order == null) { log.info("주문을 확인할 수 없습니다."); return false; } //2) remove (getter) if (order.hasNoItems()) { log.info("주문 항목이 없습니다."); return false; } //3) remove (! + if-else + getter) if (order.isInvalidTotalPrice()) { log.info("올바르지 않은 총 가격입니다."); return false; } //4) remove (! + if-else) if (order.hasNoCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false } return true; } public class Order { private List<Item> items; private double totalPrice; private CustomerInfo customerInfo; public boolean hasNoItems() { return items == null || items.isEmpty(); } public boolean isInvalidTotalPrice() { return totalPrice <= 0; } public boolean hasNoCustomerInfo() { return customerInfo == null; } }Mission 2-2) 자기만의 언어로 정리한 SOLID1) SRP- Single Responsibility Principle (단일 책임의 원칙)- “하나의 클래스에 변경이 발생한다면 그 이유(==책임)는 반드시 하나여야 한다”는 원칙- ex) 프로그램 실행 부와 실제 실행 로직은 나누어져 있어야 한다.- 높은 응집도, 낮은 결합도와 관련 있음.2) OCP- Open-Closed Principle (개방-폐쇄 원칙)- “기존 코드의 변경 없이, 기능을 확장할 수 있어야 한다”는 원칙3) LSP- Liskov Substitution Principle (리스코프 치환 원칙)- 상속 구조에서, “부모 클래스의 인스턴스는 자식 클래스의 인스턴스로 치환될수 있어야 한다”는 원칙 4) ISP- Interrface Segregation Principle (인터페이스 분리 원칙)- ”하나의 구체 클래스는 자신이 사용하지 않는 인터페이스에 의존해서는 안된다”는 원칙(이때는, 인터페이스를 2개로 분리해야 한다) 5) DIP- Dependency Inversion Principle (의존성 역전 법칙)- “레벨이 높은 모듈(ex, Lv2 카페)은 구체 모듈(ex, Lv0 커피)에 바로 의존해서는 안되고 추상화(ex, Lv1 음료)에 의존해야 한다”는 원칙 미션을 통해 SOLID 원칙을 다시 한번 상기시킬수 있었는데, 실제 업무에 활용하기 위해서는 스스로 좀더 깊은 학습이 필요할것 같다. 그리고 클린코드의 방법론을 미션을 통해 적용해 보면서 코드가 좀 더 잘 읽히고 이해하기 쉬워지는 것을 직접 느낄수 있었다.Section5) 객체지향 적용하기상속과 조합상속은 시멘트처럼 굳어지는 구조이기 때문에 수정이 어려우므로, 상속보다 조합을 사용하는게 좋다.Value Object도메인의 어떤 개념을 추상화하여 표현한 값 객체로, 불변성, 동등성, 유효성 검증 등을 보장해야 한다.VO (Value Object)는 내부의 모든 값이 다 같아야 동등한 객체로 취급한다. 이에 반해 Entity는 식별자만 같으면 동등한 객체로 취급한다.일급 컬렉션컬렉션(List, Set, Map 등)을 포장하면서, 컬렉션만을 유일하게 필드로 가지는 객체로, 단 하나의 컬렉션 필드만을 가진다.만약, getter로 컬렉션을 반환할 일이 생긴다면 외부 조작을 피하기 위해 꼭 새로운 컬렉션(List<Object타입>)으로 만들어 반환하는게 좋다. 스터디를 진행하면서, 처음에는 완벽하게 다 이해하려고 생각해 학습에 시간이 오래걸렸는데, 이제는 내가 당장 적용해 볼수 있는 부분들을 Target으로 하여 배워나가야 겠다는 깨달음을 얻었다. 출처https://inf.run/zgJk5https://inf.run/kHiWM

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

yoon

[워밍업 클럽 2기 BE 클린코드&테스트] 1주차 회고

워밍업 클럽 2기에 열린 BE 클린코드&테스트 스터디에 참가하고 있습니다. 1주차에는 클린 코드 관련한 강의를 듣고 예제 프로젝트를 수정해가며 연습하는 시간을 가졌습니다.아래에 1주차 동안 배운 내용을 요약했습니다. [배운 점]1. 추상화의 중요성클린 코드를 배우면서 가장 인상 깊었던 것은 추상화의 중요성입니다. 코드를 작성할 때 '무엇을 하는가'와 '어떻게 하는가'를 분리하는 것이 얼마나 중요한지 깨달았습니다.- 적절한 이름 짓기의 중요성- 메서드 추출을 통한 코드 구조화- 추상화 레벨을 일관되게 유지하는 것의 중요성이를 통해 코드의 가독성과 유지보수성이 크게 향상될 수 있다는 점을 배웠습니다.2. 논리와 사고의 흐름코드를 작성할 때 논리와 사고의 흐름을 명확히 하는 것이 중요하다는 점을 배웠습니다. 특히:- Early return을 사용하여 복잡성 줄이기- 부정문보다는 긍정문을 사용하여 이해하기 쉽게 만들기- 해피 케이스와 예외 처리를 명확히 구분하기이러한 방법들을 통해 코드를 읽는 사람의 인지 부하를 줄일 수 있다는 점이 인상적이었습니다.3. 객체 지향 패러다임의 적용객체 지향 프로그래밍의 원칙들, 특히 SOLID 원칙에 대해 배운 것이 큰 도움이 되었습니다- 단일 책임 원칙 (SRP)- 개방-폐쇄 원칙 (OCP)- 리스코프 치환 원칙 (LSP)- 인터페이스 분리 원칙 (ISP)- 의존관계 역전 원칙 (DIP)이러한 원칙들을 적용함으로써 더 유연하고 확장 가능한 코드를 작성할 수 있다는 것을 알게 되었습니다.4. 실제 적용과 리팩토링이론을 배우는 것도 중요하지만, 실제로 코드에 적용해보는 것이 더 중요하다는 점을 깨달았습니다.- Value Object와 일급 컬렉션의 활용- Enum을 이용한 다양한 상태 표현- 다형성을 활용한 조건문 개선이러한 기법들을 실제 코드에 적용해보면서, 코드의 품질이 눈에 띄게 향상되는 것을 경험할 수 있었습니다. 앞으로의 다짐이번 학습을 통해 클린 코드의 중요성과 방법에 대해 많이 배웠지만, 이는 시작에 불과하다는 것을 알게 되었습니다.1. 매일 조금씩이라도 기존 코드를 리팩토링하는 습관 들이기2. 코드 리뷰에 적극적으로 참여하여 다른 사람의 코드에서도 배우기3. 클린 코드 관련 서적을 꾸준히 읽고 학습하기이러한 노력을 통해 더 나은 개발자로 성장하고 싶습니다. 클린 코드는 단순히 '예쁜' 코드를 작성하는 것이 아니라, 효율적이고 유지보수와 협업에 용이한 코드를 만드는 것임을 깨달았습니다. 이는 개인의 성장뿐만 아니라 실무에서 팀과 회사의 생산성 향상에도 크게 기여할 수 있는 중요한 기술이라고 생각합니다.

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

전석희

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

인프런 워밍업클럽 2기 1주차피그마 배리어블 기능을 알아가고, 디자인시스템을 효과적으로 제작하기위해 강의를 신청했다.혼자하면 분명 미루게될 것 같아서 워밍업클럽으로 4주동안 다 듣는 것을 목표로 했다. 1주차때 배운 것배리어블 등록 (색상, 간격, 타이포그래피, 아이콘, 그림자)입력 컴포넌트 제작 (버튼, 체크박스, 라디오버튼, 스위치버튼)배리어블을 등록할 때 primitive와 semantic으로 나눠서 지정하는 것을 배웠다.이것을 강의 그대로 따라하는 것은 쉬웠지만, 내가 만들 프로젝트?에 대입해서 어떻게 구성할 것인지는...디자이너 혼자일 때는 어렵지 않겠지만 추후 개발자와 일을 하게 되었을 때에는 꼭 많은 소통이 필요하겠다고 느껴졌다.예전에 작업할 때 state랑 status를 혼동해서 작업했던 것 같다.. 이번 기회에 안헷갈리고 개념을 잘 정리하는 시간이었던 것 같다! 아쉬웠던 점강의를 따라하기만 한 점내가 하고 싶은 프로젝트의 디자인시스템을 만드는데 도움이 되고자 강의를 신청했는데, 일단 강의를 듣다보니 그대로 따라하고만 있었다. 물론 따라하는 것이 나쁜 것은 아니지만... 그 이후 복습했던 시간이 없었던 것 같다.시간 배분을 잘 못했다.강의 초반에는 오전에 강의를 듣고~ 실습하고 그럴려고했는데 사람 마음이.. 아침에 일어나서 공부를 하려니 조금 못했던 것 같다.. 막 점심에도 듣고 저녁에도 듣고... 취준생이라 시간 많으니 오전시간에 다시 듣도록 노력해야겠다.문서 정리를 못한점배리어블 만들기만하고 문서로 정리를 잘 못했다.. 다음에 시도할 점복습을 하자 + 문서 정리를 하자내 개인 프로젝트에 따로 제작을 해보면서 이걸 개발자와 소통하려면 어떻게 배리어블을 구성할 것인지... 문서를 어떻게 할 것인지 생각해보는 시간이 있으면 좋을 것 같다.오전에 수업을 다 몰아듣자!시간을 정해서 듣는게 더 효율이 좋을 것 같다. 2주차도 잘 듣고, 미션도 밀리지 않고싶다! 다들 화이팅..

UX/UI디자인시스템디자인UXUI피그마프로덕트디자인워밍업클럽

vin

[인프런 워밍업 클럽 BE 2기] 백엔드 프로젝트 - 1주차 발자국

새로운 프로젝트 아이디어를 찾다가 인프런에서 위밍업클럽 2기를 시작한다는 소식을 듣고 신청하게 됐다. 강의 목록 중 특히 끌리는 강의가 있었고, 코틀린을 사용하는 점도 마음에 들었다. 그동안 코틀린을 접해본 적이 없어서 배우고 싶은 마음도 컸고, 새로운 기술들을 익히면서 동시에 다양한 사람들과 네트워킹을 할 수 있다는 부분이 마음에 들었다. 프로젝트 미리보기 + 웹 개발 기본 개념이번 강의에서는 웹 프레임워크, HTTP, 그리고 REST API와 같은 웹 개발의 기본 개념을 간략하게 학습했다.강의 시간이 짧아서 깊이 있는 설명은 없었지만, 웹 개발에서 필수적인 기초 개념을 알기 쉽게 설명해주었다. 덕분에 그동안 혼란스러웠던 부분들이 정리되었고, 전체적인 웹 개발의 기본 흐름을 이해할 수 있었다. 프로젝트 시작하기 + 데이터베이스 기본 개념데이터베이스와 JPA에 대해 이론적으로 학습하고, 실습으로 테이블 설계와 개발 환경을 구성하여 프로젝트를 시작했다.이전에는 주로 마이바티스(MyBatis)를 사용해 DB와 연결했지만, JPA에 대해서는 개념만 알고 있었다. 이번 강의를 통해 JPA의 기본 개념과 동작 방식을 명확히 이해하게 되었고, Spring Initializr 사이트를 통해 강의에서 사용할 개발 환경을 설정하고 프로젝트를 생성했다. 프로젝트 기초 설정하기코드 형상 관리를 위해 git과 GitHub를 사용하는 방법을 학습했다.또한, 생성된 프로젝트를 GitHub에 연결하고, 기본적인 상수 클래스, 리포지토리 클래스, 엔티티 클래스를 생성하였다.불필요한 파일들이 추적되지 않도록 .gitignore 파일을 설정하였고, 이 작업은 gitignore.io에서 현재 개발 환경에 맞는 설정을 자동으로 생성하여 적용했다.추가로, application.properties 설정 파일을 application-default.yml과 application-docker.yml로 나누어 개발 서버와 운영 서버에서 각각 다른 환경 설정을 적용하였다. H2와 MySQL 중 하나를 선택하여 각 서버에 맞게 설정했다. 프로젝트의 뼈대 엔티티 개발하기설계한 테이블을 바탕으로 엔티티(Entity)를 개발했다. 기본적으로 BaseEntity와 프로젝트에 필요한 여러 엔티티를 작성하였다.JPA와 코틀린을 처음 접해 생소한 부분도 있었지만, 자바에 대한 기본 지식 덕분에 비교적 빠르게 적응할 수 있었다. 연관관계가 있는 엔티티와 없는 엔티티를 나누어 개발하면서 새로운 어노테이션도 많이 사용했는데, 강의에서 해당 어노테이션에 대한 설명이 명확해서 어려움 없이 따라갈 수 있었다. 미션 1 + 21:N테이블 설계하기, 깃허브 리포지토리 만들기1주차에서 배운 내용을 바탕으로 서브 프로젝트의 GitHub 리포지토리를 만들고 테이블을 설계하는 미션을 수행했다.GitHub 리포지토리 생성은 문제없이 따라갔으나, 테이블 설계에서는 과연 내가 올바르게 하고 있는지 의구심이 들었다.적은 수의 테이블을 설계하는 것조차 여러 요인을 고려해야 했고, 설계한 테이블들이 적합한지 확신이 서지 않았다.우선 테이블을 설계하고, 프로젝트를 진행하면서 고려하지 못했던 부분이나 잘못 설계된 부분은 수정해나가기로 생각하였고, 이 과정에서 배운 점들을 기록하며 앞으로 개선해나갈 예정이다.https://github.com/Malvin222/mission-backoffice 

웹 개발백엔드웹개발워밍업클럽스프링

vin 1개월 전
gotjd9773

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

개요인프런 워밍업 스터디 클럽 2기 백엔드(읽기 좋은 코드, 테스트 코드) 9/27 금요일 시작되었다.스터디 주제는 박우빈님의 강의인Readable Code: 읽기 좋은 코드를 작성하는 사고법Practical Testing: 실용적인 테스트 가이드이다.1 ~ 2주차에는 읽기 좋은 코드 강의를 수강하고, 3 ~ 4주차에는 테스트 강의를 수강 하게 되는데,이번 글은 1주차, 읽기 좋은 코드 강의를 수강하고 배운 것들을 정리해 보려고 한다. 1주차 공부한 내용발자국 작성을 위해 표로 정리했다. 생각보다 번거로운 작업이었다. 강의 하나 듣고 로그 기록하고...권장 진도표에 따르면, 섹션 5까지 1주차에 수강 하도록 되어 있는데,이번 주는 섹션 4까지가 한계였다. 생각보다 내용이 많았고, 한 번에 이해되지 않는 내용들은 복습해야 했다. 해결한 것 - 인텔리제이 한글 깨짐 이슈처음부터 난관을 겪었다.인텔리제이 한글 깨짐 이슈...강의에서는 지뢰찾기 게임을 콘솔 프로그램으로 구현이 되어 있고,콘솔에 출력되는 내용이 한글, 지뢰 모양, 네모박스 모양, 깃발 모양 등이 있는데,전부 깨져서 출력되었다.구글링을 통해 해볼 수 있는 것들은 다 해봤던 것 같다.그래도 안 되서 포기하려던 찰나, 유튜브에는 관련 내용이 없는지 살펴보았다.결국, 해결! (유튜브 만세!)Project Structure 에서 SDK와 Language level 을 17 버전으로 동일하게 맞춰주니 한글 깨짐 이슈가 해결되었다.기존에는 SDK는 21 버전이 적용되어 있었다.버전이 제대로 맞지 않으면 한글 깨짐 이슈가 일어나는구나를 깨달았다.  이미 알고 있던 것들1. 이름 짓기 이름을 잘 지어야 한 다는 것은 알고 있었다. 어려워서 그렇지...2. 메서드 추출 이거는 코드짤 때 열심히 활용하고 있다.Ctrl + Alt + M추가적으로 메서드로 추출할 때 주의사항을 설명해주셨는데 도움이 많이 되었다.메서드를 추출할 때마다 항상 주의사항 4가지를 점검해야겠다. 메서드 추출시 주의사항 4가지메서드명은 적절한가?혹시 메서드가 두 가지 일을 하고 있지는 않은가?파라미터는 적절한가?반환타입은 적절한가?왜 이 4가지를 주의 해야 하는지는 강의를 통해 확인하시라. 배운 것들1. 추상화 레벨 "하나의 세계 안에서는 추상화 레벨이 동등해야 한다." - 박우빈추상화 레벨을 동등하게 맞춰야 한다는 개념은 처음 알게 되었다.이해를 돕기 위해 들어주신 서점 비유가 와 닿았다.추상화 레벨을 맞추지 않는 것은 서점 주인이 책들 사이에 표지, 제목도 없는 종이 모음을 책 이랍시고 내놓는 것과 같다.서점에 들어갔는데 종이 모음을 보게 되면 많이 당황스러울 것 같긴 하다. ㅋㅋㅋ나는 이런 서점 주인이 되어서는 안되겠다고 다짐했다. 2. Early returnEarly return 이라는 용어는 처음 접했다.이거를 무의식적으로, 이런 용어가 있다는 것도 모른채 사용해왔던 것 같다.Early return을 사용하면 뇌 메모리의 부하를 줄일 수 있겠구나를 깨달았다. 3. orElse, orElseGet, orElseThrow의 차이자바 8 문법을 배울 때 한 번씩 사용해본 메서드들인데 이번에 제대로 정리할 수 있었다. 4. getter 사용 자제setter를 사용하지 말라는 것은 들어봤지만, getter도 사용 하지 않는 것이 좋다는 것은 처음 들었다.어쩔 수 없을 때는 getter를 써야 겠지만, 클래스를 설계할 때 무지성으로 getter를 선언하는 행동은 지양해야겠다. 미션인프런 워밍업 클럽 스터디는 강의 수강 뿐만 아니라 미션 수행도 해야 한다.이번 1주차에는 Day 2, Day 4 미션이 있었다. Day 2 미션 - 추상과 구체 예시일상 생활에서 추상과 구체에 대한 예시를 찾는 미션이었다.요즘 관심 있는 주제에서 예시를 찾으려고 했다.요즘 관심 있는 주제는 주식, 운동, 스타크래프트인데,운동 분야가 가장 설명하기 쉬워 보였고, 모든 사람이 알만한 스쿼트에 대해서 구체적으로 설명했다. Day 2 미션 답변 - 스쿼트를 구체 레벨에서 표현한다면?발을 어깨너비로 벌리고 무게중심을 발뒤꿈치에 두면서 무릎을 굽힌다.숨을 참고 복압을 유지한 상태로 엉덩이를 뒤로 밀며 허벅지가 지면과 평행해질 때까지 내려간다.하체 근육을 사용해 다시 상체를 들어 올린다.동작이 끝난 후 숨을 내쉰다. Day 4 미션 - 메서드 리팩토링 실습, SOLID 개념을 자신 만의 언어로1. 메서드 리팩터링 실습 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; }위의 메서드를 읽기 좋은 코드로 리팩토링 해보는 미션이었다.Early return, 추상화 레벨을 맞춰주기, 공백 라인, 부정어, 이름 짓기에 주의하며 리팩터링을 수행했다.아래 코드가 리팩터링을 거친 코드public boolean validateOrder(Order order) { if (order.getItems().isEmpty()) { log.info("주문 항목이 없습니다."); return false; } if (order.isTotalPriceInvalid()) { log.info("올바르지 않은 총 가격입니다."); return false; } if (order.hasNoCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } return true; }2. SOLID 개념을 자신만의 언어로견고한 객체지향 프로그램을 위해 제시된 개념인 SOLID를 자신만의 언어로 설명하는 미션이었다.글이 너무 길어지니까 이거는 생략하겠다. 아쉬웠던 점읽기 좋은 코드로 리팩터링하기 위해서는 테스트 코드가 꼭 필요하다.원래라면 테스트 코드를 짰을 테지만, 시간이 없었다는 핑계로 테스트 코드는 건너 뛰었다.하지만, 테스트 코드 없는 리팩터링이 오히려 시간을 더 잡아먹을 수 있고, 훨씬 개발자를 불안하게 만드는 것 같다.3주차부터는 테스트 코드를 본격적으로 배우게 될텐데 기대된다. 마무리100점 짜리는 아니었지만, 내 상황에서 최선을 다한 한 주였다.미션을 제 때 낼 수 있어서 기쁘다.2주차도 잘해보자. 

백엔드읽기좋은코드클린코드워밍업클럽객체지향추상화

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

프로그램의 정의프로그램 = 데이터 + 코드추상과 구체추상 : 중요한 정보는 가려내어 남기고, 덜 중요한 정보는 생략하여 버린다.메서드와 추상화잘 쓰여진 코드라면, 한 메서드의 주제는 반드시 하나다.메서드 선언부반환타입 메서드명 ( 파라미터 ) { 메서드 구현부 }void 대신 충분히 반환할 만한 값이 있는지 고민해보기 -> 반환값이 있다면 테스트도 용이해 진다. 인텔리제이 메서드 뽑아내는 단축키 : 코드 드래그 후 옵션 + 커맨드 + m -> 메서드로 만들어 준다 추상화 레벨R r = method( ) ; 메서드를 추출하는 것 자체가 외부 세계와 내부 세계로 나뉜다. (경계가 나뉨)하나의 세계 안에서는, 추상화 레벨이 동등해야 한다.  매직 넘버, 매직 스트링의미를 갖고 있으나, 상수로 추출되지 않은 숫자, 문자열 등상수 추출로 이름을 짓고 의미를 부여함으로써 가독성, 유지보수성 증가 public static final int BOARD_ROW_SIZE = 8; public static final int BOARD_COL_SIZE = 10; private static final String[][] BOARD = new String[BOARD_ROW_SIZE][BOARD_COL_SIZE]; private static final Integer[][] NEARBY_LAND_MINE_COUNTS = new Integer[BOARD_ROW_SIZE][BOARD_COL_SIZE]; private static final boolean[][] LAND_MINES = new boolean[BOARD_ROW_SIZE][BOARD_COL_SIZE]; public static final int LAND_MINE_COUNT = 10; public static final String FLAG_SIGN = "⚑"; public static final String LAND_MINE_SIGN = "☼"; public static final String CLOSED_CELL_SIGN = "□"; public static final String OPENED_CELL_SIGN = "■";인텔리제이 상수 뽑아내는 단축키 : 옵션 + 커맨드 + cEarly returnelse의 사용을 지양 : if , else-if , else 를 같이 쓰지 않고 if - return 으로 바꾸면 앞의 정보를 신경 쓰지 않아도 된다. 사고의 depth 줄이기무조건 1 depth로 만드는게 아니다-> 추상화를 통한 사고 과정의 depth를 줄이는 것이 중요-> 2중 중첩 구조로 표현하는 것이 가독성이 좋을 수도 있다. 메서드 분리부정어를 대하는 자세메소드명 자체에 부정어를 적기되도록 2번 생각 해야하는 부정연산자를 사용하지 않는다. 해피 케이스와 예외 처리사용자 입력, 객체 생성자, 외부 서버의 요청 주의의도한 예외와 예상하지 못한 예외를 구분하기 Null을 대하는 자세항상 NullPointException 경계Optional 사용 자제미션2// asis // 사용자가 생성한 주문이 유효한지를 검증하는 메서드 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; } /** 위 코드를 Readable Code로 리팩토링 한다면 * 1. early return을 사용해서 필요없는 else문 삭제하기 * 2. 최대한 getter 사용 지양하기 강제로 객체의 값을 가져오지 않고 객체에게 질문하기 */ // tobe public boolean validateOrder(Order order) { if (order.hasNoItems()) { log.info("주문 항목이 없습니다."); return false; } if (order.isInvalidTotalPrice()){ log.info("올바르지 않은 총 가격입니다."); return false; } if (order.hasNoCustomerInfo()){ log.info("사용자 정보가 없습니다."); return false; } return true; }출처:인프런 워밍업 클럽 2기(백엔드 클린코드, 테스트코드) - https://www.inflearn.com/course/offline/warmup-club-2-be-wb강의 출처 - 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

SK

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

[인프런 워밍업 클럽 2기] FE 1주차 발자국1주차 학습 요약강의 - 따라하며 배우는 자바스크립트 A-Zhttps://www.inflearn.com/course/따라하며-배우는-자바스크립트 - John Ahn1일차 OT 2일차 JS 기초, window, DOM, EventJS 기초 강의에서는 console 객체들, 변수 선언, 호이스팅, 타입, 타입 변환, 연산, 반복, window 객체, DOM, Event 등을 배움중요호이스팅var, let, const 가 모두 호이스팅 된다.예시 코드console.log(a) // undefined var a = 123 console.log(a) // 123JS 는 위에서 부터 순차적으로 읽어 내려오는 방식으로 코드를 읽는다. 위의 코드 같은 경우 var 의 선언된 a 를 메모리에 먼저 undefined 로 할당된 뒤 console.log(a) 를 읽어온다. 그러므로 undefined 라는 결과가 출력이 되고 그 뒤에 a 에 123이 할당된다.반대로 let과 const 는 어떨까.console.log(a) // ReferenceError: a is not defined let a = 123 // let 이나 const console.log(a) // 위의 log 에서 에러가 나므로 접근 안됨메모리에 먼저 a 를 할당 하는건 var 와 방식이 같다. 하지만 var 는 undefined 를 할당 하지만 let 과 const 는 undefined를 할당하지 않는다. 그러므로 변수 선언 위에 있는 log 에서 오류가 발생 한다.직접 보고 싶을 경우 about:blank 로 접속해서 개발자 모드의 콘솔창에 입력해보기 바란다.필자가 애용하는 브라우저 콘솔 테스트 환경1번 과제 - Food Menu Apphttps://food-menu-app-kappa.vercel.app/ - 완성본.. title 안바꿧네https://github.com/ygvbhy/food-menu-app.git - 코드빌드 도구 ViteCSS Bootstrap 5 (CDN)js Vanilla배포도구 Vercel해결 과정디자인은 똑같이 안했고 엇비슷하게 진행. css 보단 js 가 더 중요했으므로 css 는 신경 쓰지않음.메뉴 리스트는 데이터로 활용이 가능함. 그래서 json 파일로 따로 정리 import 해오는 방식으로 진행. 추후 api 도 json 방식으로 object 값이 반환 되는 경우가 많기 때문에 이런 방식으로 진행기초 틀 작업 - bootstrap 5 를 활용하여 전체적인 틀을 잡은 뒤 내부에 들어가는 메뉴정보를 js 에서 반복하여 작성 후 innerHTML 를 활용하여 내용 삽입All 과 각 메뉴의 구분 필요하고 로딩시 All 을 기준으로 메뉴들을 표기 해야 하므로 script 로딩 될때 해당 함수 실행. window.onload 사용해도 됨.3일차 자바스크립트 중급 1 ~ 8this, bind, call, apply, 삼항 연산자, Event loop, Closure, 구조 분해 할당, 전개 연산자, map, filter, reducethis 메소드 ⇒ 해당 객체를 가리킨다.(참조한다.) 함수 ⇒ window 객체를 참조 constructor ⇒ 빈 객체를 가리킨다.화살표 함수 (Arrow Function) 은 항상 상위 스코프의 this 를 참조함.삼항 연산자if (a) a = 'a' else a = 'b' // => a ? a = 'a' : a = 'b' Event Loop// 두 번째 인수가 시간 값. 밀리세컨드 값으로 1초 = 1000 으로 생각 하면 된다. // 내부 함수는 비동기이다. setTimeout(() => {}, 1000) 동기/비동기동기 ⇒ 시간을 맞춤비동기 ⇒ 시간을 맞추지 않음차이 : 동기는 먼저 이전의 것이 끝나야 다음 것을 함. 비동기는 1번을 하면서 2번도 가능하고 3, 4번도 가능함.JS 는 동기 언어임 그래서 JS 이외의 도움을 받는다. 브라우저 실행 → 브라우저 api 를 사용 (window object) Node 에서 실행 → Node api 사용 (global object)비동기 처리 과정브라우저 내부 : JS 엔진, web APIs, Callback Queue, Event LoopJS 엔진 : 메모리 힙, Call Stack메모리 힙 : 변수 저장 창고Call Stack : 함수 호출시 함수가 줄 서는 곳Closure다른 함수 내부에 정의된 함수(innerFunction)가 있는 경우 외부 함수 (outerFunction) 가 실행을 완료하고 해당 변수가 해당 함수 외부에서 더 이상 액세스 할 수 없는 경우에도 해당 내부 함수는 외부 함수의 변수 및 범위에 액세스할 수 있다.function outerFunction(outerVariable) { return function innerFunction (innerVariable) { console.log('Outer Variable: ', outerVariable) // Outer Variable: outside console.log('Inner Variable: ', innerVariable) // Inner Variable: inside } } const newFunction = outerFunction('outside'); newFunction('inside') outerFunction(’outside’) 은 변수 “newFunction” 에 할당되는 즉시 호출호출되면 outerFunction 은 변수 “newFunction” 을 outerFunction(outerVariable) 대신 innerFunction(innerVariable)을 반환 한다.그럼 다음 변수 newFunction(’inside’)으로 호출하여 innerFunction(’inside’)을 호출한다. 클로저는 innerFunction 이 원래 outerFunction(’outside’) 으로 설정한 outerVariable 매개변수를 기억하고 액세스 할 수 있는 것. 따라서 ‘inside’로만 호출되었더라도 ‘outside’와 ‘inside’ 를 모두 console.log() 할 수있다.구조 분해 할당let address = { city: '1234', zipCode: '12345' } const {city, zipCode} = address let a = [1, 2, 3, 4, 5] const [n1, n2, n3, n4, n5] = a 전개 연산자let a = [1, 2, 3, 4, 5] [...a, 123] // [1, 2, 3, 4, 5, 123] // 문자열도 가능 let a = "askdjhfqkwejhr" [...a] // ['a', 's', 'k', 'd', 'j', 'h', 'f', 'q', 'k', 'w', 'e', 'j', 'h', 'r'] // 문자열 분할 함수 - 위와 같은 효과 (배열에는 사용 못함) a.split('') // ['a', 's', 'k', 'd', 'j', 'h', 'f', 'q', 'k', 'w', 'e', 'j', 'h', 'r'] map, filter, reducemap → 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환filter → 주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환reduce → 배열의 각 요소에 대해 주어진 리듀서 함수를 실행 하고, 하나의 결괏값을 반환 4개의 인자 ⇒ 누산기 (acc), 현재 값 (cur), 현재 인덱스 (idx), 원본 배열 (src)2번 과제 - 가위바위보 게임https://rsp-game-five.vercel.app/ - 완성 화면https://github.com/ygvbhy/rsp-game.git - 코드빌드 도구 ViteCSS Bootstrap 5 (CDN)js Vanilla배포도구 Vercel해결 과정 전 과제와는 다르게 js 작동이 많아서 TODO 파일에 작동을 하나하나 작성 하면서 작업컴퓨터가 고른 가위 바위 보는 Math.random() 함수를 이용해 3가지중 랜덤값을 뽑아서 진행1,2,3중 1이면 가위 2면 바위 3이면 보사용자가 고른 값을 id 에 저장 해 두고 이 값과 랜덤으로 가져온 값을 비교 하여 판단.4일차 자바스크립트 중급 9 ~ 17undefined, null, 얕은 비교, 깊은 비교, 얕은 복사, 깊은 복사, 함수 표현식, 함수 선언문, IIFE(Immediately Invoked Function Expression), Intersection observer, 순수 함수, 커링, strict modestructuredClone : 깊은 복사를 지원하는 내부 함수IIFE(Immediately Invoked Function Expression) 정의되자마자 즉시 실행되는 함수( function () { } )() // 첫번째 소괄호 => 전역 선언 막고, IIFE 내부 안으로 다른 변수 접근 막기 // 두번째 소괄호 => 즉시 실행 함수를 생성하는 괄호 이를 통해 js 엔진은 함수를 즉시 해석 및 실행 목적 : 전역으로 선언하는 것을 피하기 위해. 또한 IIFE 내부 안으로 다른 변수들이 접근하는 것을 막을 수도 있다.Intersection observer기본적으로 viewport 와 설정한 요소의 교차점을 관찰하며, 요소가 뷰포트에 포함되는지 포함되지 않는지, 더 쉽게는 사용자 화면에 지금 보이는 요소인지 아닌지 구별하는 기능무한 스크롤 또는 이미지 레이지 로딩에 사용 됨순수 함수함수형 프로그래밍 패러다임의 한 부분이며, 순수 함수는 두 가지 규칙을 가지고 있다.같은 입력값이 주어졌을 때, 언제나 같은 결과값을 리턴사이드 이펙트를 만들지 않는다.사용 하는 이유클린 코드를 위해테스트를 쉽게 하기 위해디버그를 쉽게 하기 위해독립적인 코드를 위해커링 (Currying)f(a,b,c) 처럼 단일 호출로 처리하는 함수를f(a)(b)(c) 와 같이 각각의 인수가 호출 가능한 프로세스로 호출된 후 병합될 수 있게 변환하는 것커링은 함수를 호출하는 것이 아닌 변환 하는 것3번 과제 - 퀴즈 앱https://quiz-app-mauve-beta.vercel.app/ - 완성 화면https://github.com/ygvbhy/quiz-app - 코드빌드 도구 ViteCSS Bootstrap 5 (CDN)js Vanilla배포도구 Vercel해결 과정 TODO 에 동작을 하나하나 써가며 작업문제는 3개 정답은 2 ~ 3개 로 나눠져서 json 으로 데이터를 정리 해서 사용각 문제를 반복하여 innerHTML 로 문제를 삽입한 뒤 id 값으로 정답 값 구분정답의 구분을 위해 각 문제가 담긴 배열을 반복을 돌려 확인.이후 정답 버튼들은 각 정답 여부에 맞게 색상 입히고 배경은 정답일 경우 초록, 오답일경우 빨강으로 색 변경다음 문제 클릭시 색상 및 문제, 정답 버튼 새롭게 로딩5일차 OOP, 비동기OOP, 다형성, js prototype, ES6 classes, Sub Class(Inheritance), super(), Callbacks, ES6 Promise, Async, AwiatOOP : object oriented programming - 객체 지향 프로그래밍프로그래밍 언어의 기본이 되는 프로그래밍의 패러다임. 여러개의 독립된 단위 객체들의 모임특징자료 추상화불필요한 정보는 숨기고 중요한 정보만을 표현함으로써 프로그램을 간단히 만드는것. 객체안의 자세한 내용을 몰라도 중요 정보를 이용해서 해당 객체를 사용할 수 있게 됨.상속새로운 클래스가 기존의 클래스의 자료와 연산을 이용할 수 있게 하는 기능다형성다형성. 다양한 형태를 가질 수 있다.어떤 한 요소에 여러 개념을 넣어 놓은 것.캡슐화클래스 안에 관련 메서드, 변수 등을 하나로 묶어줌. 이 매커니즘을 이용해서 바깥에서의 접근을 막아 보안이 강화되고 잘 관리되는 코드를 제공.prototypejs 객체가 다른 객체로부터 메서드와 속성을 상속받는 매커니즘을 말한다. 이것을 프로토타입 체인이라 한다. 이렇게 하므로 인해 더 적은 메모리를 사용하고 코드를 재사용 할 수 있다.callbacksjs 는 싱글 스레드. 하나의 일을 할때 다른 일은 하지 못함.데이터를 가져오는데 10초가 걸린다면 10초동안 페이지에선 아무것도 못함. 그래서 이러한 문제를 해결하기 위해 비동기 요청을 사용함. 병렬작업 가능Promisejs 비동기 처리에 사용 되는 객체new 키워드와 생성자를 사용해 만든다. 생성자는 매개변수로 “실행 함수” 를 받는다. 이 함수는 매개 변수로 두 가지 함수를 받아야 하는데 첫 번째 함수(resolve) 는 비동기 작업을 성공적으로 완료해 결과를 값으로 반환할 때 호출해야 하고, 두 번째 함수는(reject) 작업이 실패하여 오류의 원인을 반환할 때 호출하면 된다. 두 번째 함수는 주로 오류 객체를 받는다.Promise 객체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타낸다.4번 과제 - 책 리스트 나열 앱https://book-list-app-three.vercel.app/ - 완성 화면https://github.com/ygvbhy/book-list-app - 코드빌드 도구 ViteCSS Bootstrap 5 (CDN)js Vanilla배포도구 Vercel해결 과정책 리스트를 저장 하는 방법으로 배열을 선택. 로컬 스토리지와 고민 하다가 1회성으로 보여주는 방향으로 결정삭제 버튼 클릭 부분에서 헷갈렸지만, 부모 요소를 선택하여 이벤트를 추가하는 걸로 해결알림 출력 부분도 출력 후 지우는건 가능한데 연속적으로 진행 했을 경우 나타나지 않는 오류로 인해 Math 함수를 사용해 임의 숫자를 id 값으로 부여 한 뒤 setTimeout 으로 랜덤 숫자의 id 를 찾아 해당 부분을 삭제하는 것으로 진행알림은 없지만 아무런 정보를 입력하지 않고 저장시 함수에서 return5번 과제 - Github Finder 앱https://github-finder-app-rose.vercel.app/- 완성 화면https://github.com/ygvbhy/github-finder-app - 코드빌드 도구 ViteCSS Bootstrap 5 (CDN)js Vanilla배포도구 Vercellibrary Axios해결 과정GitHub API 를 활용 하여 데이터를 받아와서 화면에 표기해주는 작업api 는 axios 를 사용하여 동기/비동기 작업 진행작업 도중 도중 ip 에 할당된 api 사용횟수 초과로 인해 힘들었다..  같은 내용이지만 노션 정리 내용https://skpost.notion.site/2-FE-1-1103a6f79dfb80da94ffd00752c9f9dd

프론트엔드워밍업클럽스터디프론트엔드JS1주차

SK 1개월 전
Taeho

인프런 워밍업 클럽 - CS Day 4

그림으로 쉽게 배우는 자료구조와 알고리즘(기본편)StackLIFO(Last-in First-out)가장 먼저 들어온 데이터가 가장 나중에 나가는 자료 구조가장 나중에 들어온 데이터가 가장 먼저 나가는 자료 구조Linked List를 사용하여 Stack을 구현할 수 있다.출처 : https://www.geeksforgeeks.org/stack-data-structure/?ref=header_outindLinked List를 사용한 구현head를 사용하여 스택을 간단하게 구현할 수 있다.데이터 삽입을 무조건 첫 번째 인덱스에 수행한다.⇒ 한쪽으로만 데이터를 삽입하고, 삭제하면 간단하게 구현할 수 있다.Stack을 사용하는 상황웹 브라우저 방문 기록 (뒤로 가기 기능)프로그램의 실행 취소(Undo) 기능 구현역순 문자열 만들기수식의 괄호 검사후위 표기법 계산함수 호출 관리 (프로그램의 함수 호출 스택)깊이 우선 탐색(DFS) 알고리즘 구현Stack ADTpush() - 데이터 삽입pop()- 데이터 제거peek() - 데이터 참조isEmpty() - 비었는지 체크QueueFIFO(First-in First-out)가장 먼저 들어온 데이터가 가장 먼저 나가는 자료 구조가장 나중에 들어온 데이터가 가장 나중에 나가는 자료 구조Linked List를 사용하여 Queue를 구현할 수 있다.출처 : https://www.geeksforgeeks.org/queue-data-structure/Linked List를 사용한 구현head를 사용하여 Queue를 간단하게 구현할 수 있다.데이터를 뒤에서 제거하는 것을 구현해야 한다.→ 단방향 Linked List의 경우에는 가장 마지막에 있는 Node에 접근하기 위해서는 head에서부터 순차적으로 접근해야 한다.→ O(n)의 시간이 소요된다.⇒ tail을 사용하여 가장 마지막의 노드 정보를 저장한다.→ tail을 사용하더라도 가장 마지막의 노드 정보를 갱신하기 위해서는 head에서부터 순차 접근해야 한다.→ O(n)의 시간이 소요된다.⇒ 이중 연결 리스트를 사용하여 구현하면 O(n)을 O(1)로 개선할 수 있다.Queue를 사용하는 상황프린터의 인쇄 대기열 관리OS에 작업 요청이 들어오면 들어온 순서대로 큐에 넣고, CPU가 순서대로 꺼내서 처리한다.→ FIFO 스케쥴링네트워크의 데이터 패킷 전송 관리실시간 시스템의 인터럽트 처리너비 우선 탐색(BFS) 알고리즘 구현캐시(Cache) 구현은행 창구와 같은 대기열 시스템 모델링동시성 프로그래밍에서의 작업 큐Queue ADTenqueue() - 데이터 삽입dequeue() - 데이터 제거front() - 데이터 참조(Tail 참조)isEmpty() - Queue가 비었는지 확인Deque데이터의 삽입과 제거를 head와 tail에서 자유롭게 할 수 있는 자료구조Deque을 사용하여 Stack과 Queue를 구현할 수 있다.출처 : https://www.geeksforgeeks.org/deque-in-python/?ref=header_outindDeque ADTprintAll() - 리스트의 모든 데이터 출력addFirst() - head에 데이터 삽입removeFirst() - head에서 데이터 제거addLast() - tail에 데이터 삽입removeLast() - tail에서 데이터 제거isEmpty() - 리스트가 비었는지 체크그림으로 쉽게 배우는 운영체제Context Switching프로세스를 실행하는 중에 다른 프로세스를 실행하기 위해 실행중인 프로세스의 상태를 저장하고, 다른 프로세스의 상태값으로 전환하는 작업Context Switching이 발생할 때 PCB의 내용이 변경된다.프로세스 상태, 프로그램 카운터, 레지스터 정보, 메모리 관련 정보 등이 변경된다.발생하는 이유CPU 점유 시간의 종료I/O 요청인터럽트가 발생한 경우프로세스 생성OS가 부팅되고 0번 프로세스가 생성될 때 딱 한 번만 수행된다.→ 그 이후에 생성되는 프로세스는 fork()를 사용하여 복사해서 사용된다.→ 새로 생성하는 것보다 복사를 하는 것이 더 빠르기 때문실행 파일(.exe)실행OS는 해당 프로그램의 코드 영역과 데이터 영역을 메모리에 로드빈 스택과 빈 힙을 만들어 공간을 확보프로세스를 관리하기 위한 PCB 생성 및 초기화exec()부모를 복사한 자식 프로세스의 코드와 데이터 영역을 원하는 값으로 덮어쓸 수 있다.→ 부모 프로세스와 다른 방식으로 동작할 수 있다.좀비 프로세스부모 프로세스가 자식 프로세스보다 먼저 종료되거나 자식 프로세스가 비정상적으로 종료돼 exit()신호를 주지 못해서 Exit Status를 읽지 못해 메모리에 계속 살아있는 상태Thread프로세스 내에 존재하고, 1개 이상이 존재할 수 있다.하나의 프로세스 내에 있는 쓰레드들은 프로세스의 PCB, Code, Data, Heap 영역을 공유한다.Stack은 공유하지 않고, 쓰레드마다 하나씩 갖고 있다.OS에서 작업을 처리하는 단위Thread 구분자Thread IDTCB(Thread Control Block)Process vs Thread안정성Process는 독립적이기 때문에 서로 영향을 받지 않는다.Thread는 하나의 Process를 공유하기 때문에 하나의 Thread에 이상이 생기면 다른 Thread에도 이상이 전파될 수 있다.⇒ Process가 유리속도와 자원각각의 Process는 서로 고유한 자원을 갖는다.코드, 데이터, 힙, 스택 영역을 전부 따로 두고 있다.Process간에 통신을 하려면 IPC를 사용해야 해서 오버헤드가 크고 속도가 느리다.쓰레드는 하나의 Process의 자원을 스택 영역을 제외한 영역을 모두 공유하기 때문에 오버헤드가 느리다.

알고리즘 · 자료구조DAY3워밍업클럽CS전공지식

Taeho

인프런 워밍업 클럽 - CS Day 5

Hash TableHash Function해시 함수는 키(key)를 입력받아 해당 키의 저장 위치(버킷 또는 인덱스)를 결정하는 계산을 하는 함수좋은 해시 함수 ⇒ 데이터를 골고루 분배시켜주는 함수장점빠른 데이터 읽기, 삽입, 삭제단점메모리를 많이 차지한다.좋은 해시 함수의 구현이 필수적이다.Hash Collision해시 충돌은 해시 함수가 서로 다른 두 개 이상의 입력 값에 대해 동일한 해시 값을 출력하는 상황을 의미Hash 충돌이 발생한 곳의 Value들을 연결리스트로 구성하여 데이터들을 연결한다.기존값과 새로운 값을 동시에 저장할 수 있다.찾고자 하는 Value가 나올 때까지 연결리스트를 탐색한다.→ O(n)의 성능을 갖는다.해결 방법체이닝 (Chaining)각 버킷에 연결 리스트를 사용하여 충돌된 항목들을 저장한다.장점: 구현이 간단하고, 해시 테이블의 확장이 필요 없다.단점: 최악의 경우 검색 시간이 O(n)이 될 수 있다.개방 주소법 (Open Addressing)충돌 발생 시 다른 빈 버킷을 찾아 데이터를 저장한다.유형:선형 탐사 (Linear Probing)제곱 탐사 (Quadratic Probing)이중 해싱 (Double Hashing)장점: 추가적인 메모리 사용이 없다.단점: 클러스터링 현상이 발생할 수 있다.재해싱 (Rehashing)해시 테이블의 크기를 동적으로 조정하여 충돌 가능성을 줄인다.Tip.Java의 HashMap의 경우에는 기본적으로 체이닝 방식을 사용한다.But. 성능 최적화를 위해 다음과 같이 구현된다.- 하나의 버킷에 8개 이상의 항목이 저장되면 연결 리스트를 트리 구조로 변환한다.- 버킷의 항목 수가 6개 이하로 줄어들면 다시 연결 리스트로 변환한다.참조 : https://d2.naver.com/helloworld/831311시간 복잡도읽기, 삽입, 수정, 삭제 : Key만 알고 있으면 Value에 O(1)로 읽기가 가능HashTable ADTset() - 데이터 삽입get() - 데이터 읽기remove() - 데이터 삭제Set데이터의 중복을 허용하지 않는 자료구조HashTable을 사용하여 구현할 수 있다.→ HashTable을 사용하기 때문에 HashSet이라고도 한다.→ HashTable의 value 값은 사용하지 않고 key만 사용하여 구현한다.(key가 key와 value의 역할을 수행한다.)Set ADTadd(data) - 데이터 삽입isContain(data) - 데이터 체크remove(data) - 데이터 제거clear() - 셋 비우기isEmpty() - 셋이 비었는지 확인printAll() - 모든 데이터 출력CPU Scheduling스케줄러가 고려해야 할 사항어떤 프로세스에게 CPU를 할당해야 하는가?CPU를 할당받은 프로세스가 얼마의 시간동안 CPU를 점유해야 하는가?→ 컴퓨터의 성능에 굉장히 큰 영향을 미친다.CPU BurstCPU를 할당받아 실행하는 작업I/O BurstI/O 작업목표목표들을 전부 만족할 수는 없다.→ 목표들에 따라 Trade-Off가 있기 때문ex) 처리량 ↑ ⇒ CPU 오래 할당, 응답시간 ↓ ⇒ 여러 프로세스에 CPU를 골고루 할당⇒ 처리량과 응답시간 사이에 Trade-Off가 발생한다.리소스 사용률CPU 사용률 높이기I/O 디바이스의 사용률 높이기오버헤드의 최소화Context Switching시에 발생하는 오버헤드를 최소화하는 것공평성모든 프로세스에게 우선순위에 따라 공평하게 CPU가 할당되어야 한다.처리량같은 시간내에 더 많은 처리를 할 수 있게 하는 것대기시간작업을 요청하고 실제 작업이 실행되기 전까지 대기하는 시간이 짧은 것응답시간사용자의 요청이 얼마나 빨리 요청하는지다중 Queue프로세스가 대기하고 있는 준비상태와 대기상태는 Queue라는 자료구조로 관리된다.OS는 해당 프로세스의 우선순위를 보고, 그에 맞는 준비 큐에 PCB를 넣는다.CPU 스케줄러는 준비상태의 다중 큐에 들어있는 프로세스들 중에 프로세스를 선택해서 실행상태로 전환시킨다.프로세스가 실행상태에서 I/O 요청을 받아 대기상태로 전환되는 경우 I/O 작업 종류에 따라 분류된 큐에 PCB가 들어간다.I/O 작업이 완료되어 인터럽트가 발생되면 분류된 큐에서 프로세스를 꺼낸다.FIFO(First-In First-Out)먼저 들어온 작업이 먼저 나간다.스케쥴링 큐에 들어온 순서대로 CPU를 할당받는 방식단점먼저 들어온 프로세스가 완전히 종료되어야만 다음 프로세스가 실행될 수 있다.→ I/O 작업이 발생하면 CPU는 I/O 작업이 끝날 때까지 쉬기 때문에 CPU 사용률이 떨어진다.→ 작업이 빠르게 종료될 수 있는 간단한 프로세스가 작업이 무거운 프로세스 뒤에 들어오면 무거운 프로세스가 완료될 때까지 기다려야 한다.프로세스의 Burst Time에 따라 성능의 차이가 심하게 나기 때문에 현대 OS에서 사용되지 않고, 주로 일괄 처리 시스템에서 사용된다.스케줄링의 성능평균 대기 시간스케줄링 성능 평가의 척도프로세스 여러개가 실행될 때 해당 프로세스들이 모두 실행되기까지 대기시간의 평균값ex)

알고리즘 · 자료구조워밍업클럽CS전공지식DAY5

Taeho

인프런 워밍업 클럽 - CS Day 3

그림으로 쉽게 배우는 자료구조와 알고리즘(기본편)Array배열의 인덱스 참조는 길이에 상관없이 한 번에 가져온다. → O(1)의 성능을 갖는다.삽입, 삭제의 성능이 좋지 않다. → 데이터를 추가, 제거하려면 내부적으로 필요한 단계가 많다.데이터 추가, 제거 시 내부적으로 수행해야 하는 단계연속된 메모리 할당배열은 메모리상에 연속적으로 저장되어 있다.→ 중간에 요소를 삽입하거나 삭제할 때 문제가 발생요소 이동 필요배열의 중간에 새로운 요소를 삽입하거나 기존 요소를 삭제할 경우, 해당 위치 이후의 모든 요소들을 이동시켜야 한다.→ 오버헤드가 발생한다.고정된 크기정적 배열의 경우 크기가 고정되어 있어, 삽입 시 공간이 부족하면 새로운 더 큰 배열을 생성하고 모든 요소를 복사해야 한다.삽입/삭제 위치에 따른 성능 차이배열의 끝에서 삽입/삭제하는 경우는 O(1)로 빠르지만, 최악의 경우(배열의 시작 부분에서 삽입/삭제) O(n)의 시간이 소요된다.메모리 재할당동적 배열의 경우, 크기를 늘릴 때 새로운 메모리 공간을 할당하고 기존 데이터를 복사해야 하므로 추가적인 시간이 소요된다.JS의 Array상황에 따라서 연속적, 불연속적으로 메모리를 할당한다.일반적으로 불연속적으로 할당한다.불연속적으로 할당된 메모리는 내부적으로 연결해서 사용자에게는 배열처럼 느껴진다.Linked List배열의 단점인 삽입, 삭제의 성능을 보완하기 위한 자료구조저장하려는 데이터들을 메모리(힙 영역)에 분산하여 할당하고, 해당 데이터를 서로 연결한다.노드를 사용하여 데이터들을 저장하고, 각 노드가 다음 노드를 가리키도록 한다.첫 노드의 주소만 알고 있으면 그 이후의 모든 노드에 접근할 수 있다.장점데이터 추가 및 삭제빈 메모리 공간 아무 곳에 데이터를 생성하고, 연결만 해주면 데이터 추가가 완료된다.중간에 데이터가 삽입/삭제 된다고 한다면 배열은 해당 데이터 이후의 모든 데이터들을 이동시켜야 하지만 연결리스트는 해당 데이터와 그 이전, 이후의 데이터만 수정하면 된다.단점특정 데이터를 찾고 싶다면 노드를 순회해야 한다. → O(n)의 성능을 갖는다. Array vs Linked List데이터의 참조가 많은 경우 ⇒ Array 사용데이터의 삽입과 삭제가 많은 경우 ⇒ Linked List 사용추상 자료형(ADT, Abstract Data Type)어떠한 데이터와 그 데이터에 대한 연산을 표기하는 방법→ 데이터의 논리적인 동작을 정의한다.구현 방법을 명시하지 않고, 자료구조의 특성과 연산만을 설명한다.데이터의 타입과 해당 타입에 수행할 수 있는 연산들만을 정의한다.내부 구현 세부사항은 숨기고 인터페이스만을 제공한다.Linked List의 ADT모든 데이터 출력 → printAll()모든 데이터 제거 → clear()인덱스 삽입 → insertAt(index, data)마지막 위치에 데이터 삽입 → insertLast(data)원하는 인덱스의 데이터 삭제 → deleteAt(index)마지막 데이터 삭제 → deleteLast()특정 인덱스 데이터 읽기 → getNodeAt(index)그림으로 쉽게 배우는 운영체제Program(= Application, App)저장장치에 저장된 명령문의 집합체Windows에서는 .exe의 형식저장 장치만 사용하는 수동적인 존재Process실행중인 프로그램저장장치에 저장된 프로그램이 메모리에 올라갔을 때 프로세스라고 한다.메모리, CPU, I/O 작업을 수행하는 능동적인 존재구조Code자신을 실행하는 코드가 저장되어 있는 영역Data전역 변수와 Static 변수가 저장되어 있는 영역Stack지역 변수와 함추 호출을 했을 때 필요한 정보들이 저장되는 영역함수 호출시 매개변수와 돌아갈 주소가 저장된다.Heap프로그래머가 동적으로 메모리를 할당하는 데 사용되는 영역→ 프로그래머가 런타임시 할당할 수 있는 메모리 공간Program → Process가 되는 과정(C 언어 기준)전처리기를 거쳐서 매크로로 정의한 숫자를 치환하고 필요한 파일을 불러온다.전처리기를 거치면 파일의 확장자는 .i가 된다.컴파일러가 컴파일 수행고수준인 C언어를 저수준인 Assembly어로 치환해준다.파일의 확장자는 .s가 된다.어셈블러가 어셈블리어를 기계어로 치환한다.파일의 확장자는 .o가 된다.링커가 링킹을 수행하여 여러 가지 라이브러리나 다른 소스 코드를 연결한다.파일의 확장자는 .exe가 된다.저장장치에 저장된 .exe파일을 실행하면 메모리에 올라가게 된다.→ 프로세스가 된다.프로세스는 운영체제에 의해 관리된다.Uni-Programming메모리에 오직 하나의 프로세스가 올라온 상태메모리 관점으로 정의Multi-Programming메모리에 여러개의 프로세스가 올라온 상태메모리 관점으로 정의Multi-ProcessingCPU 관점으로 정의CPU가 여러 개의 프로세스를 처리하는 것을 의미한다.Swapping메모리에 있는 데이터를 다른 저장장치로 보내고 다른 저장장치에서 데이터를 메모리로 올리는 방법PCB(Process Control Block)프로세스가 만들어지면 운영체제는 해당 프로세스의 정보를 갖고 있는 PCB를 만들고 저장한다.PCB들은 연결리스트라는 자료구조로 저장된다.OS는 프로세스가 종료되면 연결리스트에서 해당 프로세스의 PCB를 제거한다.구조Pointer부모와 자식 프로세스에 대한 포인터할당된 자원에 대한 포인터프로세스의 한 상태에서 다른 상태로 전환될때 저장하는 포인터Process Status현재 프로세스의 5가지 상태를 의미생성, 준비, 실행, 대기, 완료Process ID : 프로세스를 식별하기 위한 숫자Program Counter다음에 실행될 명령어의 주소를 포함한다.특정 프로세스가 CPU를 사용하다가 다른 프로세스에게 CPU를 반납하고 다시 CPU를 사용할 때 이전 상태의 명령어가 실행되어야 하기 때문에 반드시 필요하다.Register Info프로세스가 실행될 때 사용했던 레지스터의 정보PC와 마찬가지로 CPU를 뺏기고 다시 시작할 때 이전에 사용하던 값을 복구하기 위한 용도로 사용Memory Info프로세스가 메모리에 있는 위치 정보경계 레지스터 값이 저장CPU Scheduling InfoCPU 스케줄링에 필요한 우선순위, 최종 실행시간, CPU 점유시간등이 저장된다.Process Status시분할 처리를 위한 5가지 상태값New(생성)PCB를 생성하고 메모리에 프로그램 적재를 요청한 상태메모리에 프로그램 적재를 승인받으면 준비상태로 넘어간다.Ready(준비)CPU를 사용하기 위해 대기하고 있는 상태CPU 스케줄러에 의해 CPU가 할당된다.Waiting(대기)프로세스가 I/O 요청을 하면, I/O가 완료될때까지 기다리는 상태I/O 작업은 무거운 작업이기 때문에 I/O 작업이 완료될 때까지 CPU를 놀리는 것은 비효율적→ I/O 요청을 한 프로세스는 I/O 작업이 완료될 때까지 대기 상태로 두고 다른 프로세스에게 CPU를 할당한다.→ I/O 작업이 완료되면 대기 상태에 있던 프로세스에게 CPU 할당 기회를 준다.Running(실행)준비상태에 있는 프로세스가 CPU 스케줄러에 의해 CPU를 부여된 시간만큼 할당받아 실행되는 상태실행상태에 있는 프로세스의 수는 CPU의 개수이다.부여된 시간이 종료되면 CPU 스케줄러가 강제로 CPU를 빼앗는다.→ 준비 상태로 돌아간다.Terminated(완료)프로세스가 종료된 상태프로세스가 사용했던 데이터를 메모리에서 제거하고 PCB도 제거한다.

알고리즘 · 자료구조워밍업클럽CS전공지식DAY2

[워밍업 클럽 스터디 2기] 1주차 발자국 🐾

강의 : Readable Code: 읽기 좋은 코드를 작성하는 사고법1주차 진도섹션 2. 추상섹션 3. 논리, 사고의 흐름섹션 4. 객체 지향 패러다임 (SOLID) SRP(Single Responsibility Principle) : 단일 책임 원칙클래스는 단 하나의 책임을 가져야 한다.변경하는 이유는 단 하나여야 한다.SRP 원칙을 잘 지키면, 유지보수가 필요한 상황이 생겼을 때 수정할 대상이 명확해진다.클래스를 분리할 때 주의점어떤 파라미터를 전달할지 객체 입장에서 고민하기예) 익셉션 핸들러에게 e를 줄까? e.getMessage를 줄까? ⇒ e ( ∵ e를 가지고 뭘 할지는 핸들러가 알아서 해 ~ )클래스에게서 get으로 필드를 가져오는 건 무례하다구! Rude! ⇒ 메서드로 필요한 정보만을 요청하자예) 지뢰찾기 게임‘게임의 진입점’과 ‘지뢰찾기 실행’ 부분 분리입출력 관련한 것 분리게임보드 분리 OCP(Open Closed Principle) : 개방 폐쇄 원칙확장에는 열려 있고, 수정에는 닫혀 있어야 한다.새로운 요구사항이 생겼을 때, 기존 코드의 수정은 최소화 되고 새로운 기능 확장은 손쉽게 되도록 해야 한다.인터페이스를 활용하면 새로운 기능을 추가할 때기존 코드를 수정하지 않고새로운 구현체 클래스를 생성하면 된다.예) 지뢰찾기 게임 : 난이도에 따라 보드의 크기를 달리 하는 기능 추가상수로 박아둔 크기를 변수 처리GameLevel 인터페이스 사용각 난이도는 각 구현체로 LSP(Listov Substitution Principle) : 리스코프 치환 원칙부모 클래스의 인스턴스를 자식 클래스의 인스턴스로 치환할 수 있어야 한다. 상속 구조로 리팩토링할 때, 타입 체크를 하는 방향은 좋은 설계가 아니다.기존 패턴을 유지하면서 통합하는 방식으로 인터페이스를 만들면 타입 체크가 생기게 돼 ⇒ 더 추상화된 관점에서 새로운 설계를 떠올릴 수 있어야 해예) 지뢰찾기 게임 : 지뢰 Cell, 숫자 Cell, 빈 Cell을 Cell을 상속 받는 구조로 리팩토링지뢰 Cell을 구현체로 만들었으므로 플래그를 세우는 turnOn 메서드 삭제숫자 Cell을 구현체로 만들었으므로 주변부 지뢰 개수를 세서 update하는 메서드 삭제 ⇒ 생성자로 넣기 ISP(Interface Segregation Principle) : 인터페이스 분리 원칙클라이언트는 자신이 사용하지 않는 인터페이스에 의존해서는 안 된다. 예) 지뢰찾기 말고 다른 게임이 추가되는 상황새로운 게임은 initialize 메서드 사용하지 않아 ⇒ Game 인터페이스를 GameInitial과 GameRunnable로 분리 DIP(Dependency Inversion Principle) : 의존 역전 원칙상위 수준의 모듈은 하위 수준의 모듈에 의존해서는 안 된다. ⇒ 둘 다 추상화에 의존해야 한다.의존성의 순방향 : 고수준 모듈이 저수준 모듈을 참조하는 것의존을 역전시킨다 = 고수준, 저수준 모듈 모두 추상화에 의존한다.저수준은 구체 쪽에 가깝기 때문에 수정이 잦으므로 고수준이 추상화 된 스펙만 참조하도록 한다.저수준 모듈이 자유롭게 변경되어도 고수준 모듈에는 영향이 가지 않게 설계해야 한다. 예) 콘솔 외의 다른 I/O가 추가되는 상황현재 코드에서 수정하려 한다면, 마인스위퍼의 수정 불가피 해 (저수준 모듈의 변경이 고수준 모듈에 영향을 미치는 것)콘솔 핸들러를 구현체로 가지는 인풋,아웃풋 핸들러 인터페이스 생성해서 마인스위퍼에서 사용기존 메서드명이 어색해진다면 이것도 더 추상화 된 메서드 명으로 수정 : printXXX → showXXX  회고칭찬하고 싶은 점 : 워밍업 클럽의 미션을 성실히 수행했다.아쉬웠던 점 : 진도를 따라잡기 위해 리팩토링을 직접 고민해보는 과정은 생략했다.보완하고 싶은 점 : 강의에서 질문거리가 나오면 잠시 멈춰두고 혼자 고민하는 시간을 가지면 좋을 것 같다. 미션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 Beif - else 문은 else 대신 return을 사용해서 Early return중첩 조건문은 메서드로 추출해서 사고의 depth 줄이기의미 단위로 공백 주기부정어 줄이기public boolean validateOrder(Order order) { if (order.getItems().size() == 0) { log.info("주문 항목이 없습니다."); return false; } if (order.getTotalPrice() > 0) { return checkCustomerInfo(order); } log.info("올바르지 않은 총 가격입니다."); return false; } public boolean checkCustomerInfo(Order order) { if (order.hasCustomerInfo()) return true; log.info("사용자 정보가 없습니다."); return false; }   

이준우

인프런 워밍업 클럽 스터디 2기 CS 1주차 과제

운영체제1.while(true){wait(1); // 1초 멈춤bool isActivated = checkSkillActivated(); // 체크}Q1 > 위 코드는 1초 마다 플레이어가 스킬을 사용했는지 체크하는 코드입니다. 이 방식은 폴링 방식입니다. 1초마다 체크하기 때문에 성능에 좋지 않습니다. 이를 해결하기 위한 방식으로 어떤 걸 이용해야 할까요? A1 > 인터럽트이다.인터럽트 방식은 하드웨어 장치에서 많이 사용되고 소프트웨어적(Python에서는)으로는 asyncio를 사용한다. 위 코드에서는플레이어가 스킬을 사용했을때, 인터럽트를 발생시키는 방식이 좀더 효율적이라는 것.(flag와 같은 역할을 한다고 생각함.) 그렇다고 풀링 방식이 안좋은 건 아니다. 실시간 데이터를 모니터링하거나 수집해야 할 경우 폴링 방식을 사용한다면 원활하게 데이터 수집이 가능해지기 때문이다.Q2 > 프로그램과 프로세스가 어떻게 다른가요? A2 > 프로그램은 하드디스크에 저장된 명령문의 집합체이다. 즉, 애플리케이션이라고도 불린다.프로세스는 프로그램이 메모리에 올라가서 실행되는 활동 단위이다. 즉, 실행 중인 프로그램을 의미한다.Q3 > 멀티프로그래밍과 멀티프로세싱이 어떻게 다른가요? A3 > 메모리 관점, CPU 관점으로 나뉘게 된다.멀티프로그래밍은 메모리에 여러개의 프로세스가 올라와 있는 상황을 말한다.-> 이렇기 때문에 우리는 컴퓨터에 여러 개의 프로그램을 실행(프로세스)할 수 있게 된다.멀티프로세싱은 CPU가 시분할 처리로 각각의 프로세스를 짧은 시간동안 교대로 실행하는 것을 말한다.-> 이렇기 때문에 우리는 컴퓨터가 동시에 여러 개의 프로그램을 실행(프로세스)하는 것처럼 보인다.Q4 > 운영체제는 프로세스를 관리하기 위해서 어떤 것을 사용하나요? A4 > PCB(Process Control Block)를 사용한다.우리가 햄버거, 라면 등과 같은 인스턴스 음식을 먹을때, 영양정보를 확인한다.(해당 제품의 구성 확인 가능)PCB도 영양정보와 같은 역할을 담당한다. 운영체제는 프로세스의 정보를 PCB에 저장한다.PCB는 포인터, 프로세스 상태, 프로세스 ID, 프로그램 카운터, 레지스터 정보, 메모리 관련 정보, CPU 스케쥴링정보를 담는다.Q5 > 컨텍스트 스위칭이란 무엇인가요? A5 > 컨텍스트 스위칭이란 프로세스를 실행하는 중에 다른 프로세스를 실행하기 위해 실행중인 프로세스의 상태를저장하고 다른프로세스의 상태로 저장하는 작업이다. 여기서 프로세스의 시분할 처리를 위한 다섯가지 상태를 알고 있으면 좋은데, 1. 생성 2. 준비 3. 실행 4. 대기 5. 완료로 나뉜다. 예를 들어, 내가 롤이라는 게임을 하고 있다가 크롬을 켜서 웹툰을 본다면 롤이라는 프로세스는 실행 상태에서 준비상태로 돌입하고 크롬이라는 프로세스는 준비 상태에서 실행 상태로 바뀌게 된다. 이때 CPU는 롤이라는 프로세스의 PCB는 저장하고 크롬 프로세스의 PCB로 다시 세팅하는 것이다.자료구조와 알고리즘 Q1 > 여러분은 교실의 학생 정보를 저장하고 열람할 수 있는 관리 프로그램을 개발하려고 합니다. 이때 여러분이라면 학생의 정보를저장하기 위한 자료구조를 어떤 걸 선택하실 건가요? 이유를 함께 적어주세요. A1 > 딕셔너리를 사용한다. 해시테이블이라고도 한다.딕셔너리의 장점은 시간복잡도가 O(1)이다. 시간 복잡도가 O(1)이기 때문에 빠르게 접근할 수 있으며, key와 value 형식이기 때문에 관리하기도 용이하며 해당 필드에 쉽게 추가, 삽입도 가능하다.Q2 > 여러분은 고객의 주문을 받는 프로그램을 개발하려고 합니다. 주문은 들어온 순서대로 처리됩니다.이때 여러분이라면 어떤 자료구조를 선택하실 건가요? 이유를 함께 적어주세요. A2 > FIFO의 자료구조를 갖는 큐를 사용하는 것이 적합하다.문제에 직면할 때, LIFO, FIFO, LIFO&FIFO 중 어떤 문제인지 정확하게 아는 것이 중요하다.이 질문에선 '주문이 들어 온 순서대로 처리한다' 가 핵심이며, 처음 들어온 것이 가장 처음으로 나가는 구조를 갖는큐를 사용하는 것이 가장 적절하다.

워밍업

워밍업클럽2기-Backend 클린코드-#2_Day4 발자국 미션-SOLID

SOLID- 나의 언어로 정리하기 SRP- Single Responsible Principle 단일 책임 원칙객체는 단 하나의 책임만 가지고 있어야 한다. 책임을 분리하면 읽기 쉽고 유지보수하기 쉬운 코드가 된다.책임을 분리해서 서로 상호작용하며 기계 부품들 처럼 굴러가는 어플리케이션 만들기!객체들간에 서로의 코드가 어떻게 작동 하는지를 알수없게 책임을 나눠 메서드 안에 넣고 깔끔하게 숨긴다.-(뇌메모리 적게 쓰기) OCP- open closed principle -개방 폐쇠 원칙확장에는 열려있고 변경에는 닫혀있다. 인터페이스를 사용해서 다양한 확장 가능성을 열어둔다. 객체는 인터페이스만 알면 어떤 클래스가 들어오는지 몰라도 사용할수있게 코드 짜기.지뢰찾기 게임에서 처음에는 난이도가 하나밖에 없었는데 나중에 난이도 여러개를 만든다면 코드에 직접 적어서 변경하지 않고 난이도 인터페이스로 만들고 easy, normal, hard 클래스들을 만들어준다. 객체는 난이도 인터페이스는 알지만 어떤 난이도의 클래스가 들어오는지 모른다(변경X). LSP- Liskov Substitution Principle 리스코프 치환 원칙자식 클래스 는 상속 받은 부모 클래스가 가진 책임의 틀안에서 확장되어야 한다.부모클래스의 기능을 존중하지 않으면 필요하지않는 예외처리가 필요하다.예) 새 (부모 클래스) 안에 fly()메서드가 있는다 자식 클래스가 팽귄이라서 fly()에 수영하는 기능이 추가되어있다면 이건 LSP를 위반하는거고 에러가 뜰수있다. IPS- Interface Segregation Principle 인터페이스 분리 원칙인터페이스를 분리하기- 인터페이스가 너무 무거우면 사용하지않는 코드들이 많아지고 불필요한 결함도 높아진다.인터페이스를 잘게 쪼개어서 쓰지않는 기능들은 클라이언트가 가지고 있지않게 한다.텔레토비들이 먹는 쿠키를 찍어낼때 필요한 쿠키 틀을 만들때 눈과 입 모양의 쿠키 틀 인터페이스를 만드는게 아니라 쿠키의 모양 틀 인터페이스(a), 쿠키의 눈만 찍어낼수있는 인터페이스(b), 쿠키의 입만 찍어낼수있는 인터페이스(c) 이렇게 따로 분리해서 만들면 a,b 를 사용해서 눈만 있는 쿠키, a,b,c를 사용해서 눈과 입이 있는 쿠키처럼 인터페이스를 따로 분리해서 깔끔하고 다양하게 쿠키 들을 찍어낼수있다. DIP- Dependency Inversion Principle 의존역전 원칙구체적인 클래스가 아닌 추상화된 인터페이스에만 의존하게 설계하고, 실제 구현체는 외부에서 주입받아 사용하도록 한다. 이렇게 하면 어떤 구현체가 들어오더라도 기존 코드를 변경할 필요가 없고, 확장성이 크게 증가한다.쿠키 찍어내는 기계는 쿠키틀의 모양만 알면 다양한 구현체 모양의 쿠키틀의 표정은 몰라도 모양을 맞으니 그냥 끼워서 사용할수있다 😀   리팩토링 public boolean validateOrder(Order order) { if (order.getItemSize() == 0) { log.info("주문 항목이 없습니다."); return false; } if(order.getTotalPrice() <0){ log.info("올바르지 않은 총 가격입니다."); return false; } if (order.doesntHaveCustomerInfo()) { log.info("사용자 정보가 없습니다"); return false; } return true; } 추가로 변경하기 예의를 갖추어 오더에게 여쭈어보라고 강사 선생님이 그러셨당.  public boolean validateOrder(Order order) { if (lacksOfUserInfor(order)) { log.info("사용자 정보가 없습니다"); return false; } if (isOrderEmpty(order)) { log.info("주문 항목이 없습니다."); return false; } if(hasInvalidOrderPrice(order)){ log.info("올바르지 않은 총 가격입니다."); return false; } return true; } private static boolean hasInvalidOrderPrice(Order order) { return order.getTotalPrice() < 0; } private static boolean isOrderEmpty(Order order) { return order.getItemSize() == 0; } private static boolean lacksOfUserInfor(Order order) { return order.doesntHaveCustomerInfo(); }

인프런

김예지

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

 1주차JavaScript와 React를 더 공부하고 싶어서 워밍업클럽이 좋은 기회라고 생각해 신청하게 됐다. 혼자 하는 것보다 여러 명이 함께하면 더 동기부여가 되기 때문이다. 커리큘럼을 봤을 때 회사와 병행하기에 빡빡하다고 느꼈지만, 10월에 휴일이 많아 완주할 수 있을 것이라 생각했다. 막상 해보니 예상보다 빠듯하지만 완주를 목표로 하고 있다. 학습 (자바스크립트 A-Z 섹션 2~6)자바스크립트 기초를 다시 학습하면서 몰랐던 부분이나 대충 알고 있던 부분들을 확실하게 짚고 넘어갈 수 있었다. 특히 섹션 5가 재미있었는데, 구조 분해 할당, Intersection Observer를 사용한 lazy-loading, 커링 함수 등 새롭게 접한 개념들이 좋았다.  미션미션 전체 코드는 깃허브에 올렸습니다. 01 음식메뉴 앱GitHub : 01-food-menu개요객체 및 DOM, Event 다루기 필요한 기능각 카테고리별로 메뉴 항목을 HTML 요소로 동적으로 생성하여 추가탭을 클릭하면 활성화된 탭의 메뉴를 보여주기초기 상태에서는 첫 번째(0번째) 카테고리 메뉴를 기본으로 보여주기구현data.js 파일에 필요한 데이터 정리 poke: [ { name: '클래식 참치 포케', englishName: 'Classic Tuna Poke', mainIngredient: 'Tuna', description: '특제 간장 베이스와 클래식 소스가 어우러진 참치', img: 'https://www.slowcali.co.kr/data/file/main_menu/3b25130ffa2b782b388a0db95e8c1b6f_ofB4aSuQ_855bd95ad4a7a0acd9c9e0d2ca708eab2b96d5cf.png', }, ...예쁜 메뉴판을 만들고 싶어서 슬로우캘리 홈페이지에서 메뉴와 이미지를 가져다 사용했다.const categories = ['poke', 'bowl', 'wrap', 'side'];각 카테고리를 설정하고 forEach를 사용해 메뉴 생성하고 탭 클릭 이벤트를 준다..tab-content { display: none; } .tab-content.active { display: flex; }// 탭 클릭 이벤트 function handleTabClick() { const tabItems = document.querySelectorAll('.tab-item'); const tabContents = document.querySelectorAll('.tab-content'); tabItems.forEach((tab, index) => { tab.addEventListener('click', () => { // 탭 활성화 tabItems.forEach((item) => item.classList.remove('active')); tab.classList.add('active'); // 콘텐츠 활성화 tabContents.forEach((content) => content.classList.remove('active')); const selectedCategory = categories[index]; document.getElementById(selectedCategory).classList.add('active'); }); }); }탭 & 메뉴 활성화 방법 : css에서 미리 설정한 active class로 현재 선택된 메뉴를 보여준다. 회고html을 생성하는 방법은 여러가지가 있는데 이번 미션을 하면서 innerHTMl과 DOM 요소 직접 생성 방법에 대해서 더 알게된 사실이 있다.단순히 둘 다 HTML을 생성한다고 생각했는데 innerHTML은 문자열로 HTML을 삽입하기 때문에 외부 입력을 그대로 반영할 경우 악성 스크립트가 실행될 수 있어 XSS 공격에 취약하고 DOM 요소를 직접 생성하는 방법은 데이터가 HTML 구조로 변환되는 과정을 명시적으로 제어하기 때문에 잠재적인 악성 스크립트가 삽입될 가능성을 줄여준다고 한다.   02 가위 바위 보 앱GitHub : 02-rock-paper-scissors개요객체 및 DOM, Event 다루기 + 삼항 연산자 사용하기필요한 기능플레이어가 입력한 게임 횟수를 바탕으로 게임 시작하기플레이어가 가위,바위,보 중 하나를 선택하면 컴퓨터가 랜덤으로 선택최종 승리자 판별게임이 끝난 후 다시 시작하기구현let win = [0, 0]; //플레이어와 컴퓨터의 승리 횟수 let remainingGames = 0; //남은 게임 const options = ['✌', '✊', '✋']; //컴퓨터가 무작위로 선택할 배열 //게임 초기화 const resetGame = () => { win = [0, 0]; remainingGames = 0; playerMeWin.textContent = '0'; playerComputerWin.textContent = '0'; playerMeSelect.textContent = '?'; playerComputerSelect.textContent = '?'; gameCount.textContent = '0'; gameResult.textContent = '-'; };게임 상태 관리const handlePlayerChoice = (playerChoice) => { return function () { const computerChoice = options[Math.floor(Math.random() * options.length)]; playerMeSelect.textContent = playerChoice; playerComputerSelect.textContent = computerChoice; determineWinner(playerChoice, computerChoice); remainingGames--; gameCount.textContent = remainingGames; if (remainingGames === 0) { endGame(); } }; };플레이어가 가위, 바위, 보 중 하나를 선택하면 handlePlayerChoice() 함수를 호출하고 컴퓨터도 랜덤한 값을 선택하게 된다.function determineWinner(player, computer) { gameResult.textContent = player === computer ? '무승부 입니다!' : (player === '✌' && computer === '✋') || (player === '✊' && computer === '✌') || (player === '✋' && computer === '✊') ? '플레이어가 이겼어요!' : '컴퓨터가 이겼어요!'; gameResult.textContent.includes('플레이어') ? (win[0]++, (playerMeWin.textContent = win[0])) : gameResult.textContent.includes('컴퓨터') && (win[1]++, (playerComputerWin.textContent = win[1])); }determineWinner() 함수에서는 플레이어와 컴퓨터의 선택값을 비교해 삼항연산자로 승패를 결정하고 승리한 쪽의 승리 횟수를 증가시키고 화면에 반영한다. 모든 게임이 끝나면 endGame(); 함수를 호출해 최종 승리 횟수를 비교하고 결과를 팝업을 통해 알려준다. 다시하기 버튼을 누르면 resetGame() 함수를 호출해 게임을 초기화 시키고 다시 시작할 수 있다. 회고10번은 많아보여서 플레이어가 직접 게임 횟수를 정하는 기능도 추가해봤다. 컴퓨터와 플레이어 게임 횟수를 단순히 [0, 0] 이렇게 배열로 지정했는데 명확한 변수명으로 구분하는 것이 가독성 면에서는 더 좋을 것 같다.    03 퀴즈 앱GitHub : 03-quiz개요객체 및 DOM, Event 다루기 , Curry Function필요한 기능문제 1개씩 출력하기문제 번호 보여주기정답 확인 및 문제 설명 출력Next 버튼 눌렀을 때 다음 문제로 이동구현data.js 파일에 필요한 데이터 정리 { question: '다음 중 JavaScript의 데이터 타입이 아닌 것은 무엇일까요?', options: ['Number', 'String', 'Boolean', 'Character'], answer: 3, // Character explanation: 'JavaScript의 기본 데이터 타입에는 Number, String, Boolean 등이 있지만, Character 타입은 존재하지 않습니다.', },data.js에 문제들을 정리하고 이 데이터들을 바탕으로 DOM을 생성하여 문제를 보여준다.const handleAnswer = (correctAnswer, explanation) => (selectAnswer) => { quizResult.classList.add('active'); if (selectAnswer == correctAnswer) { quizMessage.textContent = '🎉 정답입니다. 🎉'; } else { quizMessage.textContent = '❌ 오답입니다. ❌'; } quizExplanation.textContent = explanation; }; // 정답 선택 quizContainer.addEventListener('click', (event) => { if (event.target.tagName === 'BUTTON') { const answerItem = event.target.parentElement; const allAnswerItems = Array.from(answerItem.parentElement.children); const index = allAnswerItems.indexOf(answerItem); allAnswerItems.forEach((item) => item.classList.remove('active')); answerItem.classList.add('active'); selectAnswer = index; // 정답 여부 확인 const correctAnswer = quizQuestions[currentQuestionIndex].answer; const explanation = quizQuestions[currentQuestionIndex].explanation; const checkAnswer = handleAnswer(correctAnswer, explanation); checkAnswer(selectAnswer); nextButton.classList.add('active'); } });handleAnswer(correctAnswer, explanation)에서 퀴즈의 정답과 설명을 받고 이후 선택된 답을 처리하고 정답 여부와 문제의 해설을 출력해준다. 회고강의에서 들은 것을 잘 활용하고 이게 맞는지 잘 모르겠다.추가해서 넣은 부분은 문제 총 갯수, 현재 풀고 있는 문제 번호 보여주기, 정답여부 보여줄 때 문제 해설도 같이 출력하기, 문제 답을 선택하기 전에는 button 비활성화 처리 선택 후 활성화하기가 있다. 문제 데이터를 더 많이 만들어서 문제를 랜덤으로 출력하고 정답률을 보여주는 부분을 추가해도 좋을 것 같다.   04 책 리스트 나열 앱GitHub : 04-display-book-list 개요기능별 클래스와 메서드 사용하기필요한 기능책 리스트 추가사용자가 값 입력 후 input 필드 초기화 하기책이 추가&삭제될 때 메세지 1초 보여주기구현class BookManager 에서는 데이터를 추가,삭제하고 목록을 관리한다.class BookUI { // constructor, init , showToast, handleDelete, createTableRow, handleAddBook 메서드 사용 }class BookUI는 책을 추가하거나 삭제할때 이를 UI에 반영하고 이벤트를 처리한다. constructor() { this.bookTitle = document.querySelector('.book-title'); this.bookAuthor = document.querySelector('.book-author'); this.submitButton = document.querySelector('button.submit'); this.tableTbody = document.querySelector('.table .tbody'); this.toastsArea = document.querySelector('.toasts'); this.bookManager = new BookManager(); this.init(); }DOM 요소들을 선택하고 BookManager 인스턴스를 생성init() { this.submitButton.addEventListener('click', this.handleAddBook.bind(this)); }사용자가 책을 추가하는 버튼을 누르면 handleAddBook 연결handleAddBook() { const titleValue = this.bookTitle.value; const authorValue = this.bookAuthor.value; if (titleValue && authorValue) { this.bookManager.addBook(titleValue, authorValue); this.createTableRow( titleValue, authorValue, this.bookManager.getBooks().length - 1 ); this.showToast('add'); this.bookTitle.value = ''; this.bookAuthor.value = ''; } else { alert('책 이름과 저자 모두 입력해야 합니다.'); } }BookManager class 에 책 추가createTableRow 메서드에서 해당 값을 받아 책 이름 / 저자 / 행 삭제 버튼 UI를 만들어준다.showToast 메서드를 통해 책 추가 메세지 출력하고 input 필드를 초기화 한다.showToast(actionType) { const messageDiv = document.createElement('div'); messageDiv.classList.add('toasts-message'); if (actionType === 'add') { messageDiv.classList.add('add'); messageDiv.textContent = '책이 추가되었습니다.'; } else if (actionType === 'delete') { messageDiv.classList.add('delete'); messageDiv.textContent = '책이 삭제되었습니다.'; } this.toastsArea.appendChild(messageDiv); setTimeout(() => { this.toastsArea.removeChild(messageDiv); }, 1000); }showToast 메서드는 현재 책이 추가된건지 삭제된건지 파라미터를 통해 받아 해당 메세지를 출력한다. handleDelete(button, rowElement, index) { button.addEventListener('click', () => { this.tableTbody.removeChild(rowElement); this.bookManager.removeBook(index); this.showToast('delete'); }); }삭제 메서드에서는 delete를 전달해 책이 삭제되었다는 메세지를 출력한다. 회고처음에는 생각 없이 앞에 했던 미션과 같은 흐름으로 코드를 작성했지만, 섹션 6, 7에 해당하는 미션이기 때문에 클래스로 구조를 변경했다. 익숙한 방식대로 작성하려는 경향이 있는 것 같다. 앞으로는 조금 더 생각하고 코드를 짜야겠다. 배운건 활용해야 하니까.하나의 책임을 가지는 클래스와 명확한 역할을 수행하는 메서드를 쓰고 싶었는데 하나의 클래스에서 너무 많은 메서드를 썼나 싶다.미션을 하는 건 재밌는데 이렇게 해도 되는 게 맞는가 하는 생각이 든다.  05 Github Finder앱GitHub : 05-github-finder  개요API 사용하기, 비동기필요한 기능사용자가 input에 입력하는 값 실시간으로 받기github API를 통해 유저 정보 보여주기사용자 명(input 값)이 비어있을 때는 copyright를 보여줌구현userID.addEventListener('input', (event) => { const username = event.target.value.trim(); if (username === '') { copyright.classList.add('active'); user.classList.remove('active'); } else { copyright.classList.remove('active'); user.classList.add('active'); getUserProfileAndRepos(username); } });유저 id에는 공백이 들어가지 않기 때문에 input에서 사용자가 실수로 입력한 공백은 삭제해준다. getUserProfileAndRepos()함수로 입력된 값을 전달.async function getUserProfileAndRepos(username) { /* profileUrl , reposUrl 링크에서 username 받음 블로그에서 자꾸 이상하게 입력되어서 코드는 아래에 따로 뺐다. */ try { const [profileResponse, reposResponse] = await Promise.all([ fetch(profileUrl), fetch(reposUrl), ]); if (profileResponse.ok && reposResponse.ok) { const profileData = await profileResponse.json(); const reposData = await reposResponse.json(); userImageElement( '.user-profile-img img', profileData.avatar_url, profileData.login ); userTextElement('.user-profile-link', profileData.html_url, true); userTextElement('.user-repos span', profileData.public_repos); userTextElement('.user-gists span', profileData.public_gists); userTextElement('.user-followers span', profileData.followers); userTextElement('.user-following span', profileData.following); userTextElement('.user-company span', profileData.company); userTextElement('.user-website span', profileData.blog); userTextElement('.user-location span', profileData.location); userTextElement( '.user-member span', new Date(profileData.created_at).toLocaleDateString() ); // 저장소 목록 최대 4개 projectArea.innerHTML = ''; reposData.slice(0, 4).forEach((repo) => { const projectElement = createProjectListElement(repo); projectArea.appendChild(projectElement); }); } else { handleError(); } } catch (error) { handleError(); } }const profileUrl = https://api.github.com/users/${username};const reposUrl = https://api.github.com/users/${username}/repos; Promise.all()을 사용해 프로필 정보와 저장소 목록을 동시에 요청한다. response.ok를 통해 두 요청이 모두 성공했는지 확인하고 .json() 메서드를 호출해 응답된 값을 자바스크립트에서 사용 가능하도록 JSON 형식에서 자바스크립트 객체로 변환해준다.요청이 실패하면 handleError()가 호출되어 에러 메세지가 표시된다. handleError() 함수에는 사용자 정보를 보여주는 UI를 초기화 하는 clearUserProfileAndProjects()함수와 User not found 메세지를 출력하는 toggleActiveClass() 함수가 들어있어 두 함수가 같이 호출된다.function userTextElement(selector, value, isLink = false) { const element = document.querySelector(selector); if (element) { if (isLink) { element.href = value; } else { element.textContent = value || 'N/A'; } } } function userImageElement(selector, src, alt) { const image = document.querySelector(selector); if (image) { image.src = src; image.alt = alt; } }유저의 저장소 목록이 몇 개 있을지 모르기 때문에 하단의 저장소 목록은 createProjectListElement() 함수를 통해 데이터를 전달 받아 DOM을 생성해 보여주고 상단의 유저 정보는 미리 생성된 el에 값을 넣어 보여준다.유저 정보를 보여주기 위해 불러오는 document가 많아서 어떤 곳에 어떤 값이 들어가는지 한눈에 보고 싶어서 userTextElement()와 userImageElement() 함수를 만들고 userTextElement('.user-repos span', profileData.public_repos); 이런식으로 코드를 써봤다. 회고깃허브 API는 비인증 요청의 경우 시간당 60회 요청이 가능하기 때문에 따로 토큰 발급 받는 부분은 생략했다. API를 사용해 데이터를 받아 보여주는 작업이 재미있었다. 주차 회고와 미션에 대한 내용을 같이 쓰다보니 글이 길어졌다. 다음 미션도 힘내서 해야겠다. 🙂 

워밍업클럽

hoonti06

인프런 워밍업 클럽 스터디 2기 백엔드 클린 코드, 테스트 코드 - Day4 미션

 아래 코드와 설명을 보고, [섹션 3. 논리, 사고의 흐름]에서 이야기하는 내용을 중심으로 읽기 좋은 코드로 리팩토링[before]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; } [after]public boolean validateOrder(Order order) { if (order.isItemCountEqualTo(0)) { log.info("주문 항목이 없습니다."); return false; } if (order.isTotalPriceLessThanOrEqualTo(0)) { log.info("올바르지 않은 총 가격입니다."); return false; } if (order.hasCustomerInfo()) { return true; } return false; } SOLID에 대하여 자기만의 언어로 정리해 봅시다.SRP하나의 클래스는 변경의 이유가 하나여야 한다.변경의 파급력이 작아야 한다.OCP수정에는 닫혀 있고, 확장에는 열려 있다.새로운 기능을 추가할 때, 기존 코드의 수정이 최소화되어야 한다. LSP부모 인스턴스가 사용되는 위치에 자식 인스턴스가 와도 의도대로 동작해야 한다.자식 클래스는 선행 조건이 더 까다로우면 안 된다.기존 부모 인스턴스에서는 사전 과정에서 유효했던 것들이 자식 인스턴스에서는 유효하지 않게 될 수 있어, 자식 인스턴스가 왔을 때 의도와 다르게 동작할 수 있다.자식 클래스는 후행 조건이 느슨해선 안 된다.기존 부모 인스턴스에서는 사후 과정에서 통과되었던 범위보다 자식 인스턴스에서 더 큰 범위가 통과되면 클라이언트 입장에서 대응이 어렵다.ISP클래스 자신이 이용하지 않는 메서드에 의존하지 않아야 한다.인터페이스를 잘게 쪼개는 것이 좋다DIP상위 모듈과 하위 모듈은 추상화(인터페이스)에 의존해야 한다.상위 모듈은 하나의 기능이라고 보면, 하위 모듈은     

Taeho

인프런 워밍업 클럽 - CS Day 2

그림으로 쉽게 배우는 자료구조와 알고리즘(기본편)What is Data Structure?자료구조 : 데이터가 어떤 구조로 저장되고 어떻게 사용되는지를 나타낸다.변수 : 가장 단순한 자료구조배열 : 숫자나 문자열 등을 연속적으로 저장하는 자료구조인덱스를 통해 특정 숫자나 문자열에 접근할 수 있다.자료구조에 따라서 결과를 얻기 위한 처리 방법이 달라진다.What is Algorithm?어떤 문제를 해결하기 위한 확실한 방법문제를 해결할 수 있는 알고리즘은 하나만 존재하는 것이 아니라 여러가지 방법이 있을 수 있다.더 좋은 알고리즘이란?사용자에 따라 다를 수 있음메모리 사용률메모리를 더 사용하더라도 속도가 더 빠른 경우일반적으로 알고리즘 성능의 척도를 시간 복잡도로 표현한다.시간 복잡도란?특정 알고리즘이 어떤 문제를 해결하는 데 걸리는 시간Bit-Ω : 최선의 시간 복잡도Big-O : 최악의 시간 복잡도가장 많이 사용된다.Big-θ : 평균의 시간 복잡도코드에서 성능에 많은 영향을 주는 부분코드의 속도를 판가름 하는 부분→ 반복문특정 알고리즘의 성능을 평가할 때는 알고리즘의 반복문을 보고 성능을 평가한다.Big-O선형시간 알고리즘입력의 크기(n)에 대비해 걸리는 시간을 그래프로 그렸을 때 정확히 직선이 된다.시간 복잡도 : O(n)입력의 크기가 증가함에 따라 실행 시간이 일정한 비율로 증가하는 알고리즘상수시간 알고리즘입력의 크기와 관계없이 항상 일정한 시간 내에 실행되는 알고리즘시간 복잡도 : O(1) Big-O 표기법은 성능을 정확하게 표기할 수는 없다.→ 해당 알고리즘의 입력이 늘어날 때 단순히 계산량이 얼마나 늘어나는지를 표현하는 방법이기 때문→ 계산에 가장 많은 영향을 끼치는 연산만 표기한다.그림으로 쉽게 배우는 운영체제OS개인용 컴퓨터 : Windows, MacOS대형 컴퓨터 / 서버 : Linux, Unix스마트폰 / 태블릿 : Android, iOS내비게이션, 스마트 워치, 냉장고, 세탁기 등 : 임베디드 운영체제싱글 스트림 배치 시스템한 번에 하나의 작업만 실행한다.사용자는 컴퓨터와 직접 상호작용하지 않는다.작업은 일괄적으로 처리되며, 순차적으로 실행된다.작업 결과는 나중에 출력된다.시분할 시스템여러 사용자가 동시에 컴퓨터 자원을 공유할 수 있게 해주는 방식CPU 시간을 짧은 시간 단위로 나누어 여러 작업에 할당한다.사용자는 시스템과 상호작용할 수 있다.메모리 침범 이슈가 발생UNIXAT&T벨 연구소에서 탄생한 C언어 기반의 OS멀티 프로그래밍, 다중 사용자, 파일 시스템을 지원한 OSOS가 하는 일프로세스 관리프로세스를 관리하지 않는다면 여러 개의 프로그램들을 동시에 수행할 수 없다.메모리 관리모든 프로그램은 메모리에 올라가서 동작한다.H/W 관리사용자가 H/W에 대한 직접 접근을 막는다.File System 관리OS의 핵심 → Kernel커널은 프로세스와 메모리, 저장장치를 관리하는 핵심적인 기능을 담당한다.사용자는 OS의 커널에 직접 접근할 수 없고, Interface를 통해서 접근할 수 있다.Interface : GUI, CLIGUI(Graphic User Interface)Graphic을 통해서 사용자와 커널이 상호작용한다.CLI(Command Line Interface)Unix, Linux가 기본적으로 제공하는 인터페이스Text를 이용하여 사용자와 커널이 상호작용한다.System CallApplication이 커널과 상호작용하기 위한 인터페이스커널에서 제공하는 write()를 사용한다.→ OS가 저장장치의 빈 공간에 자동으로 저장한다.DriverH/W와 Kernel의 인터페이스각각의 H/W에 대한 프로그램을 커널이 전부 알고 있을 수 없음→ H/W 제조사에서 드라이버를 제작하여 커널에 제공한다.폰 노이만 구조현대 컴퓨터의 기본이 되는 중요한 아키텍처로, 그 단순성과 범용성으로 인해 여전히 널리 사용되고 있다.그 한계를 극복하기 위해 캐시 메모리, 병렬 처리 등 다양한 기술이 개발되어 적용되고 있다.CPU와 메모리를 Bus로 연결한다.Bus : 데이터를 전달하는 통로프로그램 내장 방식프로그램은 메모리에 올려서 실행된다.프로그램을 메모리에 내장했다고 하여 프로그램 내장 방식이라고 한다.주요 구성 요소중앙처리장치(CPU)메모리입출력 장치핵심 특징프로그램 내장 방식: 프로그램과 데이터를 동일한 메모리에 저장한다.순차적 처리: CPU가 메모리로부터 명령어를 순차적으로 읽어 실행한다.단일 버스 구조: CPU와 메모리 사이에 하나의 버스를 사용하여 데이터와 명령어를 전송한다.장점범용성: 하드웨어 변경 없이 소프트웨어만 교체하여 다양한 작업을 수행할 수 있음.편의성: 프로그램 변경이 용이하여 컴퓨터의 활용도를 크게 높임단점폰 노이만 병목 현상: 단일 버스 구조로 인해 CPU와 메모리 간의 데이터 전송에 병목 현상이 발생할 수 있다.순차 처리의 한계: 한 번에 하나의 명령어만 처리하므로 CPU 활용이 비효율적일 수 있다.최근의 컴퓨터 H/W메인보드다른 하드웨어를 연결하는 장치장치 간에 데이터를 전송하는 버스가 존재한다.CPUMemoryCPU(Central Processing Unit, 중앙 처리 장치) 구조Control Unit(제어 장치)모든 장치들의 동작을 지시하고 제어한다.ALU(Arithmetic and Logic Unit, 산술논리 연산장치)실제로 데이터 연산을 수행한다.Register프로그램 카운터메모리 주소 레지스터메모리 버퍼 레지스터명령어 레지스터CPU 내에서 계산을 위해 임시로 데이터를 저장한다.Memory 종류RAM(Random Access Memory)랜덤으로 데이터를 읽어도 저장된 위치와 상관 없이 동일한 읽는 속도를 갖는다.전력이 끊기면 데이터를 잃어버린다.메인 메모리로 사용된다.ROM(Read Only Memory)전력이 끊겨도 데이터를 보관할 수 있다.데이터를 한 번 쓰면 수정할 수 없다.BIOS를 저장하는데 주로 사용한다.Computer의 부팅 과정전원 인가ROM에 저장된 BIOS 실행BIOS가 컴퓨터에 연결된 장치들(CPU, RAM, 키보드, 마우스, 저장장치, etc...)에 이상이 없는지 체크한다.이상이 있으면 오류를 반환하면서 부팅이 이루어지지 않는다.H/W에 있는 마스터 부트 레코드에 저장된 부트로더를 메모리로 가져와서 실행시킨다.OS를 메모리로 올린다.CPU의 I/O 작업CPU는 입출력 작업이 들어오면 입출력 관리자에게 입출력 명령을 내린다.PollingCPU는 입출력 명령이 언제 완료될지 알 수 없기 때문에 입출력 관리자에게 주기적으로 신호를 보내어 종료 여부를 확인한다.→ 주기적으로 CPU가 확인해야 해서 성능이 좋지 않다.InterruptPolling 방식의 단점을 해결한 방식CPU가 입출력 관리자에게 명령을 내리고, CPU는 다른 작업을 수행한다.입출력 관리자는 입출력이 완료되었을 때 CPU에게 신호를 준다. CPU는 해당 신호를 받아서 ISR(인터럽트 서비스 루틴)을 실행시켜 작업을 완료한다.비동기적으로 동작하기 때문에 성능에 이점이 있다.ISR(Interrupt Service Routine)특정 인터럽트가 들어오면 해당 인터럽트를 처리하는 함수Interrupt의 종류H/W Interrupt외부 하드웨어 장치(키보드, 마우스, 타이머 등)에 의해 발생시스템 버스를 통해 CPU에 전달됨예기치 못한 상황에 대응하기 위해 사용S/W Interrupt사용자 프로그램에서 발생한 인터럽트프로그램 실행 중 특정 명령어에 의해 발생주로 시스템 콜(system call)을 구현하는 데 사용됨예외 처리나 오류 상황에 대응하기 위해 사용

알고리즘 · 자료구조워밍업클럽CS전공지식DAY1

박지원

[인프런 워밍업 클럽 스터디] Day 4 미션

1. 아래 코드와 설명을 보고, [섹션 3. 논리, 사고의 흐름]에서 이야기하는 내용을 중심으로 읽기 좋은 코드로 리팩토링해 봅시다.public boolean validateOrder(Order order) { if (order.checkItemsNone()) { log.info("주문 항목이 없습니다."); return false; } if (order.getTotalPrice() <= 0) { log.info("올바르지 않은 총 가격입니다."); return false; } if (order.hasNotCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } return true; } 2. SOLID에 대하여 자기만의 언어로 정리해 봅시다.SOLID객체지향 설계를 더 이해하기 쉽고 유연한 형태로, 유지 보수를 쉽게 만드는 데 도움을 주는 원칙 SRP: Single Responsibility Principal 단일 책임 원칙하나의 클래스가 하나의 책임만 갖도록 설계함객체의 공개 메서드, 필드, 상수 등이 객체의 단일 책임에 의해서만 변경되어야 한다. 상수: 동일한 퍼블릭 상수를 두 가지 객체가 사용하는 경우를 고려한다.관심사의 분리와도 일맥상통높은 응집도(클래스, 모듈 등이 긴밀하게 연결되어 있는 정도), 낮은 결합도(협력 관계의 2개 이상 객체에서, 한 객체가 변경될 때 다른 객체가 영향 받는 정도/ 의존성의 최소화라고도 함)*책임의 경계선을 인식하기 위해서는 계속해서 질문을 던져 보는 경험적 측면이 필요. OCP: Open-Closed Principle 개방-폐쇄 원칙새로운 요구 사항의 추가와 같은 변동 사항 발생 시, 기존 코드 변경 없이 시스템의 기능을 확장한다.추상화와 다형성을 통해 지킬 수 있다.*난이도 조절 기능이 추가된다면> (1) 숫자 변경되었을 때 그 숫자에 맞춰 게임이 정상 진행되도록 한다 (2) 난이도 조절에 대한 요구사항에 대응한다의 순서로 기능을 추가해 나간다. LSP: Liskov Substitution Principle 리스코프 치환 원칙상속 구조에서 부모 클래스 인스턴스를 자식 클래스 인스턴스로 치환할 수 있어야 한다.일반적으로부모 클래스보다 자식 클래스의 기능이 더 많다. 이때 부모 클래스가 기능하는 것을 자식 클래스가 해도 동일하게 동작해야 한다는 것.LSP를 위반하면 상속 클래스 사용 시 예외가 발생하거나, 불필요한 타입 체크가 필요할 수 있다. ISP: Interface Segregation Principle 인터페이스 분리 원칙클라이언트는 자신이 사용하지 않는 인터페이스에 의존해서는 안된다. 즉 인터페이스를 기능 단위로 잘게 나눠야 한다.ISP를 위반하면 결합도가 높아지고, 특정 기능 변경이 여러 클래스에 영향을 미칠 수 있다.  DIP: Dependency Inversion Principle 의존성 역전 원칙상위 수준 모듈이 하위 수준 모듈에 직접 의존하지 않고, 두 개 모두 추상화에 의존해야 한다.상위 수준 모듈: 추상화 레벨이 높은 쪽하위 수준 모듈: 구체에 가까운 쪽 *의존성: 하나의 모듈이 다른 하나 모듈을 알고 있거나 직접 사용하는 모든 것들의존성의 순방향: 고수준 모듈이 저수준 모듈을 참조하는 것의존성의 역방향: (고수준 모듈) 기능을 추상화해서 추상화된 스펙을 만족하는 것을 이용해 요구사항을 해결할 수 있는 것. (저수준 모듈) 인터페이스를 구현한 구현체가 얼마든지 바뀔 수 있는 것.즉, 추상화를 가운데 두고 의존하도록 하는 것 *DIP, DI, IoCDIP(Dependency Inversion Principle): 고수준 모듈과 저수준 모듈은 직접적 의존이 아닌 추상화에 의존해야 한다.DI(Dependency Injection): 필요한 의존성을 외부에서 주입받는다. "3"의 숫자를 기억할 것. 객체 a, b가 있는 상황에서 a가 b를 필요로 할 때 직접 생성자를 통해 주입 받는 것이 아닌, 제3자가 둘 사이의 의존성을 맺어준다. 스프링에서는 스프링 컨텍스트(**IoC 컨테이너)가 한다.IoC(Inversion of Control): 프로그램 제어 주도권이 개발자가 아닌 프레임워크에 있다.**IoC 컨테이너: 객체의 생명주기를 관리하고 의존성 주입까지 해 준다.

인프런워밍업클럽스터디

jin02019

인프런 워밍업 클럽 2기(클린코드/테스트 코드)_day4 미션

1. 아래 코드와 설명을 보고, [섹션 3. 논리, 사고의 흐름]에서 이야기하는 내용을 중심으로 읽기 좋은 코드로 리팩토링해 봅시다.✔ 사용자가 생성한 '주문'이 유효한지를 검증하는 메서드. ✔ Order는 주문 객체이고, 필요하다면 Order에 추가적인 메서드를 만들어도 된다. (Order 내부의 구현을 구체적으로 할 필요는 없다.) ✔ 필요하다면 메서드를 추출할 수 있다.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; }리팩토링 후 public boolean validateOrder(Order order) { if (order.getItems().isEmpty()) { log.info("주문 항목이 없습니다."); return false; } if (order.getTotalPrice() > 0) { if (order.hasCustomerInfo()) { return true; } log.info("사용자 정보가 없습니다."); return false; } if (order.getTotalPrice() <= 0) { log.info("올바르지 않은 총 가격입니다."); return false; } return true; } }!(부정 연산자) 줄이기dept 줄이기공백 라인 추가 2. SOLID에 대하여 자기만의 언어로 정리해 봅시다.단일 책임 원칙하나의 클래스는 하나의 책임만 가져야 한다. 하나의 역할에 집중하면 코드를 수정할 때 다른 부분에 영향을 주지 않고 유지보수가 쉬워진다.개방 - 폐쇄 원칙확장에는 열려 있고 수정에는 닫혀있어야 한다.기존의 코드를 변경하지 않고 새로운 기능을 추가할 수 있어야 한다. 이미 작동하는 코드가 손상될 위험이 줄어들고 확장도 수월하다.리스코프 치환 원칙부모 클래스 대신 자식 클래스를 사용해도 문제가 없어야 한다. 자식 클래스가 부모 클래스의 기능을 대신할 수 있다면 코드의 안정성을 높일 수 있다.인터페이스 분리 법칙인터페이스는 필요한 기능만을 나누어 제공해야 한다.큰 인터페이스보다는 작은 인터페이스 여러 개로 설계해야 한다.불필요한 의존성을 줄이고 코드의 유연성을 높일 수 있다.의존 역전 법칙고수준 모듈은 저수준 모듈에 의존하지 않아야 한다.추상화된 인터페이스에 의존해야 한다.변화에 강한 구조를 만들고 코드의 재사용성을 높일 수 있다. 

프로그래밍 언어읽기좋은코드를작성하는사고법day4미션

bbcc

인프런 워밍업 클럽 스터디 2기 CS 1주차 과제

**운영체제**1.while(true) { wait(1); // 1초 멈춤 bool isActivated = checkSkillActivated(); // 체크 }위 코드는 1초 마다 플레이어가 스킬을 사용했는지 체크하는 코드입니다.이 방식은 폴링방식입니다. 1초마다 체크하기 때문에 성능에 좋지 않습니다.이를 해결하기 위한 방식으로 어떤 걸 이용해야 할까요?: 인터럽트 방식 2. 프로그램과 프로세스가 어떻게 다른가요?프로그램: (컴퓨터가 이해할 수 있는) 명령문의 집합체프로세스: 실행 중인 프로그램 3. 멀티프로그래밍과 멀티프로세싱이 어떻게 다른가요?멀티프로그래밍: 메모리에 여러 개의 프로세스 올라온 것.CPU 사용률을 극대화 시키는 것이 목적.멀티프로세싱: 여러 CPU 코어나 프로세서를 사용하여 동시에 여러 작업을 처리하는 것 4. 운영체제는 프로세스를 관리하기 위해서 어떤 것을 사용하나요?: 정보를 관리하기 위해 프로세스 제어 블록(PCB)을 사용합니다. 프로세스ID, 레지스터 값, 프로세스 상태 등이 저장되어 있습니다. 5. 컨텍스트 스위칭이란 뭔가요?운영 체제가 한 프로세스에서 다른 프로세스로 CPU 할당을 전환하는 과정.기존 프로세스 문맥을 PCB에 백업하고, 새로운 프로세스를 실행하기 위해 문맥을 PCB로부터 복구하여 새로운 프로세스를 실행하는 것.여러 프로세스가 CPU를 번갈아가며 사용하는 '멀티 태스킹' 과정에서, 프로세스끼리 작업이 스위칭되는 것.  **자료구조**1. 여러분은 교실의 학생 정보를 저장하고 열람할 수 있는 관리 프로그램을 개발하려고 합니다. 이 때 여러분이라면 학생의 정보를 저장하기 위한 자료구조를 어떤 걸 선택하실 건가요? 이유를 함께 적어주세요. : 배열. 교실에 있는 총 학생의 수는 예측이 가능하고저장, 열람 기능만 필요하다면 데이터의 삽입/삭제가 이루어지지 않음. 2. 여러분은 고객의 주문을 받는 프로그램을 개발하려고 합니다.주문은 들어온 순서대로 처리됩니다. 이 때 여러분이라면 어떤 자료구조를 선택하실 건가요? 이유를 함께 적어주세요.: 선입선출(FIFO) 구조를 가진 '큐'를 선택하겠습니다.

워밍업 클럽 2기 BE 클린코드&테스트코드 DAY 4 미션

public boolean validateOrder(Order order) { if (hasNoItems(order)) { log.info("주문 항목이 없습니다."); return false; } if (hasInvalidTotalPrice(order)) { log.info("올바르지 않은 총 가격입니다."); return false; } if (hasNoCustomerInfo(order)) { log.info("사용자 정보가 없습니다."); return false; } return true; }SOLID단일 책임 원칙 (Single Responsibility Principle):클래스는 오직 하나의 책임만 가져야 하며, 변경의 이유도 하나여야 합니다.이를 통해 클래스는 더 작고 관리하기 쉬운 단위로 나누어질 수 있습니다.여러 책임을 가진 클래스는 수정 시 영향 범위가 커지고, 유지보수성이 낮아질 수 있습니다.개방-폐쇄 원칙 (Open/Closed Principle):소프트웨어는 기능을 확장할 수 있어야 하지만, 기존 코드를 수정하지 않아야 합니다.이는 주로 인터페이스나 추상화를 통해 달성되며, 코드 수정 없이 새로운 기능을 추가할 수 있게 합니다.이 원칙을 지키면 기존 기능이 안정적으로 유지되고, 새로운 요구사항에 대응하기 쉬워집니다.리스코프 치환 원칙 (Liskov Substitution Principle):자식 클래스는 부모 클래스에서 기대되는 기능을 모두 수행할 수 있어야 합니다.자식 클래스가 부모 클래스 대신 사용되더라도 프로그램의 기능은 변하지 않아야 합니다.이를 지키면 클래스 간 상속 구조에서 예기치 않은 오류를 방지할 수 있습니다.인터페이스 분리 원칙 (Interface Segregation Principle):클라이언트는 자신이 사용하지 않는 인터페이스나 메서드에 의존하지 않아야 합니다.큰 인터페이스를 작게 분리함으로써 클라이언트가 필요하지 않은 기능에 의존하는 것을 피할 수 있습니다.이렇게 하면 불필요한 코드 의존성을 줄이고 유지보수성을 높일 수 있습니다.의존성 역전 원칙 (Dependency Inversion Principle):고수준 모듈은 저수준 모듈에 의존해서는 안 되며, 둘 다 추상화에 의존해야 합니다.이는 구체적인 구현보다는 인터페이스나 추상 클래스를 통해 모듈 간 의존성을 줄이는 방식입니다.이 원칙을 따르면 시스템이 유연하고 확장 가능해지며, 변경에 더 잘 대응할 수 있습니다.

백엔드

[워밍업 클럽 2기] Day4 - 논리, 사고의 흐름 & SOLID

워밍업 클럽 2기 [Clean Code & Test Code](https://www.inflearn.com/roadmaps/5699) 로드맵의 Day4 미션입니다. 1. 코드 리팩토링As-Ispublic 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-Bepublic boolean validateOrder(Order order) { if (order.itemsIsEmpty()) { log.info("주문 항목이 없습니다."); return false; } if (order.customerInfoIsEmpty()) { log.info("사용자 정보가 없습니다."); return false; } if (order.totalPriceIsNegative()) { log.info("올바르지 않은 총 가격입니다."); return false; } return true; }고려한 내용!를 쓰지 않고 부정어구를 사용해서 처리일찍 return할 수 있는 부분은 return을 해서 이전 내용을 신경 쓰지 않아도 된다else 지양분기문 중첩 depth 줄이기 2. SOLID(객체 지향의 5대 원칙)SRP(단일 책임)SRP는 하나의 클래스 또는 모듈은 하나의 책임을 가져야 한다는 원칙이다. Q. 그럼 책임이라는 것은 무엇일까? 여기서 책임은 "변경의 이유"라고 표현할 수 있다. 만약 하나의 클래스가 여러 가지 이유로 변경되어야 한다면, 그 클래스는 여러 가지 책임을 가지고 있다는 뜻이다. 이렇게 여러가지 책임이 하나의 클래스에 존재한다면, 추후에 유지보수하기 어려워질 가능성이 높다. Q. 그러면 책임의 범위를 어떻게 정하는 것이 좋을까?책임의 범위라는 것은 문맥과 상황에 따라 다를 수 있다. 이런 책임의 범위를 잘 정하는 것은 경험적인 영역이 많이 포함된다. (한마디로 책임을 보는 눈을 기르기 위해서는 경험을 많이 쌓자!)확실한 것은 어떤 변경이 있을 때 파급 효과가 적다면 SRP를 잘 따른 것으로 볼 수 있다. 정리하자면 SRP는 변경의 이유를 하나로 만들어서 코드의 응집성을 높이고, 결합도를 낮추면서 유지보수성을 개선하는 것 이다. 이때 책임(변경의 이유)의 범위를 잘 정할수 있는 능력을 기르는 것이 중요하다. OCP(개방 폐쇄)OCP는 소프트웨어가 확장에는 열려있고, 변경에는 닫혀 있어야 한다는 원칙이다. 쉽게 말해서, 새로운 기능이나 요소를 추가할 때 기존의 코드 변경 없이 추가가 가능해야 한다. Q. OCP는 어떻게 구현할까?인터페이스를 구현한 새로운 클래스를 만들어서 새로운 기능을 구현하거나 추가하는 다형성을 활용해서 구현한다. 조금더 자세히 설명하자면, 구현체가 아닌 인터페이스를 의존하도록 하고, 단순히 구현체를 변경하는 방식으로 기능의 변경이 가능하도록 설계하는 것이다. LSP(리스코프 치환)LSP는 프로그램의 객체는 프로그램을 깨트리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다는 원칙이다. 쉽게 말해서 상속 관계에서 자식 클래스의 객체가 부모 클래스의 객체를 완전히 대체해도 정상적으로 동작해야 한다는 의미다. ISP(인터페이스 분리)ISP는 클라이언트는 자신이 사용하지 않는 인터페이스(메서드)에 의존하면 안된다는 원칙이다. 쉽게 말해서, 인터페이스를 명확한 기준을 가지고 더 작은 인터페이스로 분리하자는 원칙이다. Q. 사용하지 않는 인터페이스에 의존하지 말자는 것이 무슨 의미인가?인터페이스가 너무 광범위하면 인터페이스를 구현하는 클래스들이 사용하지도 않을 메서드를 오버라이딩 해야하는 상황이 발생한다. 이를 방지하기 위해서, 명확한 기준을 가지고 인터페이스를 더 작게 분리하자는 것이 ISP 원칙이다. 불필요한 메서드 오버라이딩 외에도, 변경으로 인한 파급 효과를 줄이기 위해서 ISP를 적용할 수 있다.쉽게 말해서, 특정 클라이언트를 위한 인터페이스(좁은 범위의 책임을 가지는 인터페이스) 여러개가 범용적인 인터페이스 하나보다 낫다는 것이다. DIP(의존 관계 역전)DIP는 구체화에 의존하면 안되고, 추상화에 의존해야 한다는 원칙이다. 더 자세히 말하자면 고수준 모듈과 저수준 모듈 모두 추상화에 의존해야 한다는 뜻이다. 쉽게 말해서, 구현 클래스에 의존하지 말고 인터페이스에 의존하라는 뜻이다. Q. 구체적인 요소의 의존을 피하는 이유는?구체적이라는 것은 변동 가능성이 높다는 것이다. 저수준 모듈의 변경 사항이 있을 때 마다 해당 모듈을 사용하는 모듈도 변경이 필요할 가능성이 높아진다. 반면에, 추상화에 의존하게 되면 저수준 모듈이 변경되어도, 고수준의 모듈에는 영향이 가지 않는다(의존 관계의 역전). DIP는 DI(의존성 주입)과 IoC(제어의 역전)이라는 개념과 자주 다루어진다. IoC(제어의 역전)IoC는 프로그래머가 작성한 코드가 프레임워크의 제어를 받게 되는 패턴을 이야기 한다. 전통적인 프로그램에서의 흐름은 프로그래머가 작성한 프로그램이 라이브러리의 코드를 호출해 이용한다. 하지만 제어의 역전이 적용된 구조에서는 프레임워크의 코드가 프로그래머가 작성한 코드를 호출한다.DI(의존성 주입)DI는 클라이언트의 생성에 대한 의존성을 클라이언트의 행위로부터 분리하는 것이다. 쉽게 말해서, 필요한 의존성을 외부로 주입을 받는 것이라고 생각하면 된다. 의존성이라는 것은 동작하기 위해 필요한 클래스 또는 객체이다. Q. 그러면 주입(의존 관계 연결)은 누가 해주는 것인가?주입 받는 쪽이나 주입하는 의존성이 아닌 제 3자가 해준다. 이를 보통 IoC 컨테이너, DI 컨테이너, 등의 표현을 사용한다.스프링을 예시로 들자면, ApplicationContext가 이를 해준다.  

백엔드ReadableCode워밍업클럽2기Day4

워밍업 클럽 2기(클린코드 & 테스트) 2번째 미션(DAY 4)

SOLDS - Single Responsibility Principle (SRP): 클래스는 하나의 책임만 가져야 하며, 변경이 필요할 때 그 책임 하나만 변경되어야 한다는 원칙이며, 해당 원칙을 고수 했을 때 클래스가 더 간단하고 유지보수가 용이해진다.O - Open/Closed Principle (OCP): 확장에 대해서는 열려 있어야 하지만, 수정에 대해서는 닫혀 있어야 한다는 원칙으로 기존 코드를 수정하지 않고도 새로운 기능을 추가할 수 있어야 한다.L - Liskov Substitution Principle (LSP): 자식 클래스는 부모 클래스의 기능을 대체할 수 있어야 한다는 원칙으로 자식 클래스가 부모 클래스를 대체해도 프로그램의 동작에는 문제가 없어야 한다.I - Interface Segregation Principle (ISP): 클라이언트는 자신이 사용하지 않는 인터페이스에 의존하지 않아야 한다는 원칙으로 하나의 인터페이스 보단 여러개의 구체적인 인터페이스로 나눠 사용하는게 더 바람직 하다.D - Dependency Inversion Principle (DIP): 고수준 모듈은 저수준 모듈에 의존해서는 안 되며, 둘 다 추상화에 의존해야 한다는 원칙으로 추상은 구현체에 의존해서는 안 되고, 구현체가 추상에 의존해야 한다.리펙터링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; }해당 코드를 리펙터링 해보자.public class OrderValidator { private static final Logger log = LoggerFactory.getLogger(OrderValidator.class); public boolean validate(Order order) { return hasItems(order) && hasValidTotalPrice(order) && hasCustomerInfo(order); } private boolean hasItems(Order order) { if (order.getItems().isEmpty()) { log.info("주문 항목이 없습니다."); return false; } return true; } private boolean hasValidTotalPrice(Order order) { if (order.getTotalPrice() <= 0) { log.info("올바르지 않은 총 가격입니다."); return false; } return true; } private boolean hasCustomerInfo(Order order) { if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } return true; } }

채널톡 아이콘