[인프런 워밍업 클럽 3기 - 백엔드] 발자국 1주차
일주일 간 학습내용 정리 섹션 2. 추상추상 & 구체적절한 추상화 = 해당 도메인의 문맥안에서, 중요한 핵심개념만 남겨서 표현하는 것이름 짓기 - 단순하면서 중요한 고도의 추상적 사고행위추상적 사고 표현하고자 하는 구체에서 중요한 핵심개념만을 추출하여 잘 드러내는 표현우리 도메인의 문맥안에서 이해되는 용어이름 짓기 단수와 복수 구분하기 - 끝에 '-(e)s' 붙이기과도하게 줄이지 않기은어/방언 사용하지 않기좋은 코드를 보고 습득하기 - 자주 사용되는 단어,개념 습득하기 메서드와 추상화 - 잘 쓰여진 코드라면, 한 메서드의 주제는 하나이다추상화 레벨은 주변과 동등하게 섹션 3. 논리, 사고의 흐름Early return 으로 else,case 의 사용을 지양하자공백 라인을 대하는 자세사고의 depth 줄이기 '무조건 1 depth로 만들기' 가 아닌 추상화를 통한 사고 과정의 최소 depth로 줄이기사용할 변수는 가깝게 선언 Tip - 메소드를 리팩토링 한다면 메소드를 복사해 복사된 메소드2를 리팩토링 한 후에 메소드2를 사용되는 부분마다 적용시켜 에러를 점검하고 기존메서드 삭제후 메서드2의 이름을 변경해준다.(컴파일 에러 등 확인위해)공백라인은 복잡한 로직의 의미 단위를 나눠주어 읽는사람에게 추가적인 정보 전달 가능하다.부정어(!)를 대하는 자세 - 부정연산자의 가독성 때문 부정어구 쓰지 않아도 되는지 체크부정의 의미 담은 다른단어 존재하는지 고민해피케이스와 예외처리 예외가 발생할 가능성 낮추기어떤 값의 검증이 필요한 부분은 주로 외부 세계와의 접점의도한 예외와 예상하지 못한 예외를 구분하기해피케이스와 예외처리 - Null을 대하는 자세 항상 NullPointException을 방지하는 방향으로 경각심 가지기메서드 설계 시 return null을 자제한다Optional에 관하여Optional은 비싼 객체이다. 꼭 필요한 상황에서 반환타입에 사용함Optional을 파라미터로 받지 않도록 한다. 분기 케이스가 3개나 된다Optional을 반환받았다면 최대한 빠르게 해소한다Optional을 해소하는 방법분기문을 만드는 isPresent() - get() 대신 풍부한 API 사용orElse(),orElseGet(),orElseThrow()의 차이 숙지 섹션 4. 객체 지향 패러다임절차지향: "위에서 아래로 순차대로 실행하는 방식"객체지향: "객체 단위로 설계하는 방식"함수형: "함수를 1급 객체로 다루는 방식" 관심사의 분리(높은 응집도, 낮은 결합도)객체로 추상화 하기비공개 필드(데이터),비공개 로직(코드)공개 메서드 선언부를 통해 외부 세계와 소통 - 각 메서드의 기능은 객체의 책임을 드러내는 창구객체의 책임이 나뉨에 따라 객체 간 협력 발생 객체가 제공하는 것절차 지향에서 잘 보이지 않던 개념 가시화관심사가 한 군데로 모이기 때문에, 유지보수성 높아짐(객체 내부에서 데이터 유효성 검증 책임)여러 객체를 사용하는 입장에서, 구체적인 구현에 신경쓰지 않고 보다 높은 추상화 레벨에서 도메인 로직을 다룰 수 있다새로운 객체 만들 때 주의점 1개의 관심사로 명확하게 책임 정의가 되었는지 확인 메서드 추상화와 비슷 객체를 만듦으로써 외부 세계와 어떤 소통을 하려는지 생각생성자, 정적 팩토리 메서드에서 유효성 검증이 가능하다 도메인에 특화된 검증 로직이 들어갈 수 있다setter 사용 자제 데이터는 불변이 최고이다, 변하는 데이터이더라도 객체가 핸들링 할 수 있어야한다 객체 내부에서 외부 세계의 개입 없이 자체적인 변경/가공으로 처리 가능한지 확인 만약 외부에서 가지고 있는 데이터로 데이터 변경 요청을 해야하는 경우('set~'이라는 단순한 이름보다는 'update~'같이 의도를 드러내는 작명 고려)getter도 처음에는 사용 자제, 반드시 필요한 경우에 추가하기 외부에서 객체 내 데이터가 필요하다고 getter를 남발하는 것은 무례한 행동이다필드의 수는 적을수록 좋다 불필요한 데이터 많을수록 복잡도가 높아지고 대응할 변화가 많아진다 필드 A를 가지고 계산할 수 있는 A필드가 있다면 메서드 기능으로 제공(단, 미리 가공하는 것이 성능 상 이점이 있다면 필드로 가지고 있는 것이 좋을 수도 있다)SRP:Single Responsibility Principle하나의 클래스는 단 한가지 변경이유만을 가져야함('변경이유' = 책임)객체가 가진 공개 메서드,필드,상수 등은 해당 객체의 단일 책임에 의해서만 변경 되는가?관심사의 분리높은 응집도, 낮은 결합도OCP:Open-Closed Principle확장에는 열려있고, 수정에는 닫혀 있어야 한다(기존코드 변경없이, 시스템의 기능을 확장할 수 있어야 한다)추상화와 다형성을 활용해서 OCP를 지킬 수 있다.LSP:Liskov Substitution Principle상속 구조에서, 부모 클래스의 인스턴스를 자식클래스의 인스턴스로 치환할 수 있어야 한다(자식클래스는 부모클래스의 책임을 준수하며, 부모클래스의 행동을 변경하지 않아야 한다)LSP를 위반하면, 상속클래스를 사용할 때 오동작, 예상밖의 예외가 발생하거나, 이를 방지하기 위한 불필요한 타입체크가 동반될 수 있다ISP:Interface Segregation Principle클라이언트는 자신이 사용하지 않는 인터페이스에 의존하면 안 된다.(인터페이스를 잘게 쪼개라!)ISP를 위반하면, 불필요한 의존성으로 인해 결합도가 높아지고, 특정 기능의 변경이 여러 클래스에 영향을 미칠 수 있다.DIP:Dependency Inversion Principle상위 수준의 모듈은 하위 수준의 모듈에 의존해서는 안 된다. 둘 모두 추상화에 의존해야 한다. 의존성의 순방향: 고수준 모듈이 저수준 모듈을 참조하는 것 의존성의 역방향: 고수준,저수준 모듈이 모두 추상화에 의존하는 것 (저수준 모듈이 변경되어도, 고수준 모듈에는 영향이 가지 않는다)DIP:Dependency Inversion Principle의존성 역전 원칙DI:Dependency Injection - "3"의존성 주입(제 3자 필요)IoC:Inversion of Control제어의 역전 섹션 5. 객체 지향 패러다임상속과 조합 : 상속은 결합도가 높기 때문에 조합을 활용하는 것이 더 좋은 설계이다.Value Object, EntityVO는 불변성, 동등성, 유효성을 보장해야하며 도메인의 개념을 추상화한 객체이다. (ex. Money 객체)Entity는 식별자가 존재한다. 식별자가 같으면 동등한 객체로 취급한다.일급 컬렉션 : 컬렉션을 Wrapping한 객체를 뜻한다. 컬렉션을 추상화하여 의미를 담을 수 있고, 가공 로직의 보금자리가 생긴다. (VO와 비슷하다.)Enum : 상수의 집합, 상수들에 대한 로직을 담을 수 있다.추상화와 다형성 활용하여 반복되는 if문 제거 -> OCP 지키기변하는 것 : 조건 & 행위 (구체)변하지 않는 것 : 조건을 만족하는가? / 행위를 수행한다. (추상) 변하는 것과 변하지 않은 것을 구분해서 보는 훈련이 필요하다.숨겨져 있는 도메인 개념 도출하기 : 변경이 많이 일어날 것 같은 미래를 예견하고 이런 것을 도입해보면 어떨까? 하고 숨겨진 도메인 개념을 도출도메인 지식은 만드는 것이 아니라 발견하는 것이다.객체지향은 흉내내는 것이다.미래를 예견하고 도메인 개념을 도출해보자. 강의 회고사람마다 같은 기능을 구현하더라도 코드 스타일이 저마다 다를 것이다. 하지만 클린 코딩을 실천하면 코드가 더욱 직관적이고 명확해져서 협업과 소통이 훨씬 원활해질 것이라고 생각했다. 이러한 이유로 이번 강의를 신청하게 되었다.이번 강의를 통해 클린 코딩의 장점뿐만 아니라 추상의 개념과 그 반대 개념인 구체에 대해서도 배울 수 있었다. 강의에서는 지뢰찾기 게임의 코드를 클린 코드로 개선하는 과정을 예제로 보여주며 개념을 설명해 주었고, 이를 통해 클린 코드가 실제 코드에서 어떻게 적용되는지 더 쉽게 이해할 수 있었다.다만, 아직 코딩 실력이 부족하다 보니 직접 따라 하거나 혼자서 구현해보는 것이 쉽지는 않았다. 하지만 수업을 들으며 내가 이전에 작성했던 코드들을 다시 살펴보니, 개선할 점들이 보이기 시작했다. 앞으로는 이런 점들을 하나씩 고쳐 나가며 실력을 키워야겠다고 다짐했다.처음에는 클린 코딩이 정해진 규칙이나 규율을 따라야 하는 것이라고 생각했지만, 강의를 들으며 그것이 단순한 형식적 규칙이 아니라 소속된 팀이나 협업하는 사람들 간의 원활한 소통을 위한 과정이라는 점을 깨닫게 되었다. 결국 클린 코딩은 단순히 코드 스타일을 개선하는 것이 아니라, 코드를 읽는 사람을 배려하고, 보다 쉽게 이해할 수 있도록 만드는 작업이라는 점이 가장 인상적이었다. 앞으로는 더 좋은 코드 작성법을 고민하며 클린 코딩을 실천해 나가야겠다. 미션 회고 [미션 Day 2 회고] "추상과 구체" 개념을 학습하며, 스마트폰 충전 과정을 예시로 들어 미션을 수행했다.처음에는 단순히 "스마트폰을 충전했다"라는 한 문장으로 표현할 수 있는 일이었지만, 이를 구체적인 단계로 풀어 쓰면서 우리가 일상적으로 당연하게 여기는 행동들이 얼마나 많은 세부 과정으로 이루어져 있는지 다시 한번 깨닫게 되었다.이 과정에서 추상이란 복잡한 개념을 간결하게 표현하는 것이며, 구체란 그 개념을 더 세부적으로 풀어 설명하는 것이라는 점을 실감했다. 예를 들어, "충전기를 꽂는다"라는 간단한 표현도 실제로는 케이블을 찾고, 포트를 확인하고, 어댑터에 연결한 뒤, 충전 여부를 확인하는 과정을 포함하고 있었다.이번 미션을 통해 추상화가 얼마나 중요한 개념인지, 그리고 개발에서도 이처럼 필요한 수준에서 적절한 추상화를 적용하는 것이 왜 중요한지 다시금 생각해보는 계기가 되었다. 앞으로 코드 작성 시에도 너무 구체적으로 표현하여 복잡도를 높이지 않으면서도, 필요한 핵심 개념이 잘 드러나도록 추상화하는 연습을 해야겠다고 다짐했다. [미션 Day 4 회고]이번 미션에서는 가독성이 좋은 코드 작성과 SOLID 원칙을 이해하는 것이 핵심이었다.1. 코드 리팩토링기존 코드에서 getter 최소화, 부정 연산자 제거, Early return 적용을 통해 코드의 가독성을 개선했다.특히, order.getItems().size() == 0 대신 order.isEmpty(), order.getTotalPrice() > 0 대신 order.hasInvalidTotalPrice() 등의 메서드를 추가하여 객체가 스스로 판단할 수 있도록 책임을 분리했다. 이를 통해, 코드의 의도가 명확해지고 유지보수가 쉬워지는 효과를 얻었다.리팩토링을 하면서 객체지향적인 사고방식이 얼마나 중요한지 다시 한번 실감했다. 기존의 validateOrder 메서드는 여러 개의 조건문이 중첩되어 있어 읽기 어려웠지만, 조금만 분리하고 정리해도 코드가 한눈에 들어오는 것을 경험할 수 있었다. 앞으로 코드 작성 시 "내가 짠 코드가 명확한가?"를 더 자주 고민해야겠다고 다짐했다.2. SOLID 원칙 정리SOLID 원칙을 정리하면서, 이론적인 내용만 외우는 것이 아니라 일상적인 예시를 들어 직접 설명해 보는 과정이 재미있었다.특히, 예시로 들면서 원칙이 왜 필요한지 더욱 쉽게 이해할 수 있었다.이처럼 코드뿐만 아니라 개념도 직접 예시를 들어 설명하면 더 깊이 이해할 수 있다는 점을 느꼈다.이번 미션을 통해 "읽기 좋은 코드가 좋은 코드다"라는 사실을 다시금 깨닫게 되었다. 앞으로 코드 작성 시 단순히 기능 구현에 집중하는 것이 아니라, 다른 사람이 봤을 때도 쉽게 이해할 수 있는 코드인지 고민하는 습관을 길러야겠다.