블로그

hhw0850

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

Readable Code: 읽기 좋은 코드를 작성하는 사고법 수강 후 작성한 DAY 4 미션입니다.  1. 아래 코드와 설명을 보고, [섹션 3. 논리, 사고의 흐름]에서 이야기하는 내용을 중심으로 읽기 좋은 코드로 리팩토링해 봅시다.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; }사용자가 생성한 '주문'이 유효한지를 검증하는 메서드.Order는 주문 객체이고, 필요하다면 Order에 추가적인 메서드를 만들어도 된다. (Order 내부의 구현을 구체적으로 할 필요는 없다.)필요하다면 메서드를 추출할 수 있다.  풀이과정validateOrder 메서드에서 수행하는 기능을 간단하게 정리하면,주문 항목이 없는지 체크총 가격이 0보다 작은 수인지 체크사용자 정보가 없는지 체크총 3단계로 정리하였다. 그리고 각 단계에서 Early Return을 적용하여 불필요한 else를 없애고 depth를 줄였다.public boolean validateOrder(Order order) { // 1. 주문 항목이 없는지 체크 if (order.getItems().size() == 0) { log.info("주문 항목이 없습니다."); return false; } // 2. 총 가격이 0보다 작은 수인지 체크 if (!(order.getTotalPrice() > 0)) { log.info("올바르지 않은 총 가격입니다."); return false; } // 3. 사용자 정보가 없는지 체크 if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } return true; } 위 코드에서 부정 연산자(!)를 긍정어로 수정하고 get~ 같은 직접적인 메소드명 대신 Order 객체에게 의도된 메세지를 전달하여 가독성 좋게 if문을 수정하였다.public boolean validateOrder(Order order) { // 1. 주문 항목이 없는지 체크 if (order.hasNoneItem()) { log.info("주문 항목이 없습니다."); return false; } // 2. 총 가격이 0보다 작은 수인지 체크 if (order.isTotalPriceLessThenZero()) { log.info("올바르지 않은 총 가격입니다."); return false; } // 3. 사용자 정보가 없는지 체크 if (order.hasNoneCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } return true; }2. SOLID에 대하여 자기만의 언어로 정리해 봅시다.SRP: Single Responsibility PrincipleSRP는 하나의 클래스, 하나의 객체는 하나의 책임만을 가져야 한다는 원칙이다. 우리는 코드를 작성할 때 응집도가 높게, 결합도가 낮게 동작하도록 구현하여야 하는데 SRP를 지키게 되면 높은 응집도, 낮은 결합도를 가지게 된다. 응집도란 클래스나 모듈 내에 있는 요소들이 연관되어 있는 정도를 말하며 SRP를 지키면 이 연관되어 있는 정도가 낮아지므로 응집도는 높아진다. 결합도는 두 개 이상의 객체가 협력한다고 했을 때 하나의 객체가 변경될 경우 다른 객체가 영향 받는 정도를 의미한다. SRP를 지키면 두 객체간 의존성을 최소화시킬 수 있으므로 결합도를 낮출 수 있다. OCP: Open-Closed PrincipleOCP는 확장에는 열려있고, 수정에는 닫혀있어야 한다는 원칙이다. 우리는 코드를 한 번 작성하게 되면 끝이 아니라 지속적으로 코드를 수정하게되는 상황이 발생한다. 만약 코드 작성 후 새로운 요구사항이 발생하면 기존 코드를 수정해야하는데 기존 코드의 변경 없이 새로운 요구사항을 적용시킬 수 있어야 한다. 그렇게 하기 위해서는 인터페이스와 같은 추상을 통해 개방-폐쇄 원칙을 지킬 수 있으며 항상 기능의 확장을 고려하여 코드를 작성해야 한다. LSP: Liskov Substitution PrincipleLSP는 상속 구조를 설계할 때 부모 클래스를 자식 클래스로 변경해도 동일 결과를 낼 수 있도록 설계해야한다는 원칙이다. 자식 클래스는 부모 클래스의 기능 + @로 구현되어야 하고 부모 클래스의 기능이 변경되면 안 된다. 만약 LSP를 위반한다면 상속 구조에서 오동작이 발생할 수 있으므로 LSP를 지켜 상속 구조를 설계해야 한다. ISP : Interface Segregation PrincipleISP는 기능 단위로 인터페이스를 분리하라는 원칙이다. 하나의 인터페이스 안에 기능이 여러가지 들어있다면 인터페이스 사용 시 사용하지 않는 기능이 생길 것이다. 이렇게 되면 불필요한 의존성이 발생하므로 결합도가 높아지게 된다. 또한 인터페이스에 기능 변경이 생겼을 때 여러 클래스에 영향을 끼칠 수 있다. 이를 방지하게 위해서 인터페이스는 기능 단위로 잘게 쪼개서 사용해야한다. DIP: Dependency Inversion PrincipleDIP는 상위 수준의 모듈은 하위 수준의 모듈에 의존하면 안되며 모두 추상화에 의존해야한다는 원칙이다. 상위 수준의 모듈은 추상화 레벨이 높은 모듈을 의미하고, 하위 수준의 모듈은 추상화 레벨이 낮은 모듈을 의미한다. 만약 상위 수준의 모듈이 하위 수준의 모듈을 참조하게되면 문제가 발생할 수 있다. 하위 수준 모듈은 구체에 가깝기 때문에 변경될 가능성이 높다. 변경 가능성이 높다면 상위 수준 모듈에도 영향을 줄 수 밖에 없다. 그래서 인터페이스와 같은 추상을 통해 상위수준, 하위수준 모듈 모두 직접 서로 의존하는게 아니라, 추상화에 의존하도록 하는 의존성 역전이 필요하다.  

백엔드

인프런 스터디 미션 4

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; }해당 코드는 주문이 유효한지 판단하는 코드인 것 같다.의미 단위로 보면1. 주문항목이 존재하는지 판단하는 부분이다.getter를 사용하는 부분을 hasNoItems() 메서드로 변경하고 항목이 존재하지 않는다면 false를 리턴하도록 리팩토링한다.그 뒤 else 부분은 필요 없으므로 else는 제거한다.2. 총 가격이 유효한지 판단하는 부분이다.사용자 정보 유효성을 판단하는 if문까지 같이 있기 때문에 우선 이 부분을 분리하고getter를 사용하는 부분을 wrongTotalPrice() 메서드로 변경한다. 그 뒤의 else if와 else 또한 필요 없으므로 제거한다.3. 사용자 정보가 유효한지 판단하는 부분이다.두 번째에서 분리한 if문을 !가 사용되고 있는데 이것을 부정의 의미를 가진 hasNotCoustomerInfo() 메서드로 변경한다.마지막으로 이 3개의 if문들을 의미 단위로 공백을 준 뒤, 마지막에 if문에 걸리는 것이 없는 경우 true를 리턴 할 수 있도록 return true를 한다.변경 후public boolean validateOrder(Order order) { if (order.hasNoItems()) { log.info("주문 항목이 없습니다."); return false; } if (order.wrongTotalPrice()) { log.info("올바르지 않은 총 가격입니다."); return false; } if (order.hasNotCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } return true; }   2. SOLID에 대하여 자기만의 언어로 정리해 봅시다.SRP : Single Responsiblity Principle단일 책임 원칙 말 그대로 책임을 하나만 갖는다는 것이다. 하나의 책임은 하나의 역할을 갖는다는 의미와 같다.ex) 옛날 레노버 키보드를 보면 빨콩이라고 키보드에서 마우스 역할을 하는 트랙 포인터가 달려 있다. 현재는 키보드와 마우스를 따로 분리한 것이 더 효율적이다.OCP : Open-Closed-Principle개방-폐쇄 원칙으로 확장에는 열려 있고 변경에는 닫혀 있다.ex) 기능의 확장은 한 클래스 내의 메서드 추가로 가능하지만 기능의 변경은 클래스 내에 존재하는 메서드의 내용을 변경하는 일이기 때문에 기존의 코드가 변경된다.LSP : Liskov Substitution Principle리스코프 교체 원칙으로 상속 구조에서 부모 클래스의 인스턴스를 자식 클래스의 인스턴스로 치환할 수 있다.ex) 부모 클래스 내에 잡기, 때리기, 뛰기 3개의 기능을 하는 메서드가 있을 때 어떤 한 자식 클래스에서 잡기, 때리기, 눕기라는 부모 클래스와는 다른 메서드가 존재할 경우 예외가 발생할 수 있다.ISP : Interface Segregation Principle인터페이스 분리원칙으로 클라이언트는 자신이 사용하지 않는 인터페이스에 의존하면 안 된다.ex) 어떤 인터페이스를 구현한 구현체가 2개가 있다. 그런데 한 구현체에서는 인터페이스 내의 기능들을 모두 사용하지만, 나머지 한 구현체는 인터페이스 내의 기능 중 단 한 가지 기능만을 사용한다. 이를 해결하기 위해 인터페이스를 필요한 기능 단위로 분리한 뒤 구현체에 필요한 인터페이스들을 상속시켜주면 된다.DIP : Dependency Inversion Principle의존성 역전 원칙으로 상위 모듈은 하위 모듈에 의존하면 안 되며, 둘 다 추상화에만 의존해야 한다.하위 모듈이 변경되어도 상위 모듈에는 영향이 가지 않는다.ex) 스마트폰이라는 상위 모듈이 존재할 때 스마트폰은 어플이라는 인터페이스를 통해 다양한 기능의 어플들을 사용할 수 있다.지도 어플, 금융 어플, 게임 어플 등의 하위 모듈은 어플이라는 인터페이스를 통해 구체화된다.    

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

1. 아래 코드와 설명을 보고, [섹션 3. 논리, 사고의 흐름]에서 이야기하는 내용을 중심으로 읽기 좋은 코드로 리팩토링해 봅시다.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; }섹션 3에서 강조하는 것은 뇌 메모리 적게 쓰기. 즉, 코드를 읽는 사람으로 하여금 생각을 많이하지 않도록 하는 것이다. 그 방법에는 여러가지가 있는데, 순서대로 수정하면서 알아보자.if (order.getItems().size() == 0) { log.info("주문 항목이 없습니다."); return false; }우선 첫 줄부터 마음에 들지 않는다. 코드의 의도를 보니 주문(Order ) 내의 상품(Item) 컬렉션의 요소 개수가 0개인 지 확인하는 것으로 추측된다. 해당 코드에 Order , Item 객체에 대한 내용은 없으니 해당 클래스도 수정한다는 가정하에 진행하겠다. Items를 꺼내지 말고, Order 클래스에 Item 컬렉션이 비었는 지확인하는 메시지인hasNoItems() 을 만들어 다음과 같이 수정해보자.if (order.hasNoItems()) { log.info("주문 항목이 없습니다."); return false; }좀 더 직관적이고 객체지향적으로 수정되었다. 하지만 아직 마음에 들지 않는 것이 있는데, 바로 다음에 나올 else이다. 주문 항목이 없다면 return false 로 해당 메서드를 빠져나가기 때문에 다음 else가 있을 필요가 없다. 메서드에서 if와 else 가 공존하려면 if-else 뒤에 해당 if문에서 분기된 코드가 if-else 뒤에서 사용되는 경우밖에 없다. Early Return을 해보자. 사실 이미 Early Return이긴 하다.. else만 없애보자.public boolean validateOrder(Order order) { if (order.hasNoItems()) { log.info("주문 항목이 없습니다."); return false; } // 주문 항목이 없으면 Early Return! if (order.getTotalPrice() > 0) { // (1) if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } else { return true; } } else if (!(order.getTotalPrice() > 0)) { // (2) log.info("올바르지 않은 총 가격입니다."); return false; } return true; }else 문이 한 레벨 사라졌기 때문에 전체적인 depth가 1 줄었다. 하지만 depth가 최대 2이므로 직관적인 사고를 하기에는 피곤하다. 남은 코드들도 depth를 줄여보자. 코드(사고)의 depth를 줄이는 데에는 Early Return이 최고다. 위에서도 봤지만, Early Return을 하면 굉장히 직관적으로 코드를 읽을 수 있게 된다. (1), (2) 분기문이 있는데, (1)은 아직 2 depth 이기 때문에 (2) 부터 Early Return 하는 게 쉽겠다.public boolean validateOrder(Order order) { if (order.hasNoItems()) { log.info("주문 항목이 없습니다."); return false; } // 주문 항목이 없으면 Early Return! if (!(order.getTotalPrice() > 0)) { // (2) log.info("올바르지 않은 총 가격입니다."); return false; } if (order.getTotalPrice() > 0) { // (1) if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } else { return true; } } return true; }(2)를 Early Return을 하고 보니 분기 조건이 굉장히 거슬린다. 부등호를 굳이 Not 연산을 사용해서 한 것부터 약간 킹받는다. getter로 객체를 조회하여 비교하지말고, 메시지를 보내보자. if (order.isTotalPriceNegative()) { // (2) log.info("올바르지 않은 총 가격입니다."); return false; }주문이 음수인 지 확인하는 메서드(메시지)를 만들어 Order 객체로부터 정보를 얻자. 이제 (1)을 손볼 차례다. 우리가 (2)를 Early Return 하면서 (1)의 가장 최상위 분기는 의미 없어졌다. (2)를 통해 Early Return 되었다면 Order의 Total Price는 0 이상이라는 것이기 때문이다. if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } else { return true; }이제 (1)도 depth가 1이 되었다. 하지만 여기서도 Early Return으로 else 를 없앨 수 있다. depth를 최소화하면서 Early Return을 적용한 코드를 확인해보자.public boolean validateOrder(Order order) { if (order.hasNoItems()) { log.info("주문 항목이 없습니다."); return false; } // 주문 항목이 없으면 Early Return! if (order.isTotalPriceNegative()) { log.info("올바르지 않은 총 가격입니다."); return false; } // 총 가격이 0 이하이면 Early Return! if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } // 사용자 정보가 없으면 Early Return! return true; }정리하면서, 각 if문 사이에 공백을 한 줄씩 추가했다. 이렇게 논리 사이에 공백을 주는 것은 생각의 컨텍스트를 분리시킬 수 있는 좋은 방법이다. 예를들어 주문 항목이 없는 것과 가격이 0 이하인 것은 전혀 다른 문제이기 때문에 굳이 줄을 붙여서 사고를 연결할 필요가 없다.거의 다 마무리 됐다 싶었는데 부정 연산 `!` 하나가 거슬린다. 부정 연산은 읽는 사람으로 하여금 한 번 더 생각하게 만든다. if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; }이 코드의 분기 조건을 읽자하면, 주문에 사용자 정보가 있는 지 확인하고 그것을 뒤집어서 사용자가 없는 지를 확인하는 게 되는데.. 이미 말로만 해도 복잡하고 귀찮다. ! 는 될 수 있으면 최대한 사용하지 않고 메서드명으로 추상화하자. if (order.hasNoCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; }모든 작업이 완료되었다. 1번 미션의 최종 코드를 확인해보자.public boolean validateOrder(Order order) { if (order.hasNoItems()) { log.info("주문 항목이 없습니다."); return false; } if (order.isTotalPriceNegative()) { log.info("올바르지 않은 총 가격입니다."); return false; } if (order.hasNoCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } return true; }2. SOLID에 대하여 자기만의 언어로 정리해 봅시다.Robert.C.Martin의 SOLID는 어쩌면 캡추상다 보다 중요한 객체지향 이론이 되었다. 하나씩 살펴보자.SRP (Single Responsibility Principle)단일 책임 원칙. 하나의 객체는 하나의 책임만을 가져야한다는 뜻이다. SRP에서 가장 중요한 것은 객체를 변경해야할 사유가 단 하나라는 것이다. 개인적으로 SOLID 원칙 중에 가장 직관적이고 쉬운 원칙이라고 생각한다. 하지만 실제로 개발하다보면 가장 지키기 어려운 것이 또 SRP이다. 객체지향프로그래밍은 여러 객체가 각각의 책임을 가지고 협력하는 시스템이다. 책임을 각각 가져야한다. 내 책임이 아니면 다른 객체에게 이관하자.OCP (Open-Closed Principle)개방 폐쇄 원칙. 확장에는 열려있고 수정에는 닫혀있다는 원칙이다. OCP는 추상화를 통해 코드의 변경이 아닌 확장이 중요하다. 뒤에 나올 DIP와 OCP가 꽤 맞물려 있다고 생각한다.LSP (Liskov Substitution Principle)리스코프 치환 원칙. 상속 관계에서 자식클래스는 부모 클래스의 역할을 할 수 있어야 한다. 예를 들어, 부모 클래스의 run()은 스레드를 실행시키는 메서드인데, 자식 클래스의 run()은 육상 경기를 시작하는 메서드이면 안 된다. 그렇게 되면 해당 클래스를 참조하는 클라이언트 코드 입장에서 더 이상 그 클래스의 모든 족보를 신뢰하지 못하고 난처해진다.ISP (Interface Segregation Principle)인터페이스 분리 원칙. 어떤 인터페이스의 구현체는 사용하지 않는 메서드까지 구현할 필요가 없다. 그 말은 즉, 인터페이스가 쓸 데 없이 너무 광범위한 메서드까지 추상메서드로 가지고 있다는 것이다. 추상화는 구현으로 부터 공통 개념을 뽑아내는 것이다. 그렇다면 구현이 우선일까 추상이 우선일까? 메서드를 누구에게 맞춰야할까?DIP (Dependency Inversion Principle)의존성 역전 원칙. 구현(저급 모듈)이 아닌 추상(고급 모듈)에 의존하라는 것이다. OCP와 맞물려 Spring 프레임워크에서 매우 중요한 원칙이라고 생각한다. A 객체가 B 객체를 의존할 때, B 객체의 저수준인 구현체를 의존하게 되면 구현체를 바꿀 때 마다 A 객체의 코드를 수정해야 한다. 이 행위는 OCP를 지키지 못하는 모습도 된다. DIP를 위해 B 객체의 추상화된 고수준 모듈(인터페이스, 추상클래스, 부모 클래스)을 의존하고, 외부에서 A 객체를 생성할 때 B 객체의 실제 구현체에 대한 의존성을 주입(DI)하게 되면 A 객체를 B 객체 때문에 변경할 일은 없을 것이다.

Seul Ki Lee

워밍업 클럽 2기 BE 클린코드&테스트 day4 과제

Readable Code: 읽기 좋은 코드를 작성하는 사고법(링크)아래 내용은 위의 인프런 강의를 들으면서 과제 및 내용을 정리해봤습니다. 아래 코드 리팩토링 하기public boolean validateOrder(Order order){ if(order.getItems().size() == 0){ log.info("주문 항목이 없습니다"); }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; }본 코드의 문제는 아래와 같다if, else if, else 그리고 중접 if 등으로 인하여 주문의 유효성 조건이 한 눈에 들어오지 않는다=> early return을 사용해보자 무분별한 getter의 사용(if(order.getItems().size() == 0))=> 주문에 담긴 상품이 있는지 확인하는 내용인데 굳이 getter를 써야할까?=> 오히려 order에 item 항목이 있다고 세부 내용을 노출해버리고 있다=> 의미있는 이름의 메소드를 order에서 그 역할을 책임하도록 해보자 부정어의 사용 if(order.hasCustomerInfo()) / !(order.getTotalPrice() > 0)=> 부정어를 사용하면 코드의 가독성을 해친다 => 1순위 긍정어를 사용하여 메소드 만들 수 있는지 확인=> 2순위 긍정어를 사용할 수 없다면 메소드명으로 부정을 나타내서 만들어보자 위의 내용을 고려한 최종 코드는 아래와 같다public boolean validateOrder(Order order){ if(order.isEmptyOrderItem()){ log.info("주문 항목이 없습니다"); return false; } if(order.isLessThanOrEqualToZero()){ log.info("올바르지 않은 총 가격입니다"); return false; } if(order.isEmptyCustomerInfo()){ log.info("사용자 정보가 없습니다"); return false; } return true; }public class Order{ private List<Item> items; public boolean isEmptyOrderItem(){ return order.getItems().size() == 0; } public boolean isLessThanOrEqualToZero(){ return order.getTotalPrice() <= 0 }; public boolean isEmptyCustomerInfo(){ return !hasCustomerInfo(); } public double getTotalPrice(){...} public boolean hasCustomerInfo(){...} }SOLID에 대하여 자기만의 언어로 정리SRP클래스가 변경될 이유는 단 하나다!!클래스 설계 시, 하나의 관심사로 응집하여 구현하도록 하자OCP기존 코드의 변경 없이, 기능 추가하도록 설계가 되어야 한다 다형성을 이용하여 클라이언트 코드의 변경 없이 구현체를 쉽게 변경이 가능하다LSP부모 클래스에서 정의한 스펙을 자식 클래스에서도 지켜야 한다instance of로 타입 체크하여 특정 타입에 대해서만 처리가 필요하다는 건 LSP를 위반한 사례이다!!ISPSRP와 비슷하게 인터페이스 또한 한 가지 책임을 가지도록 분리를 잘해야 한다DIP클래스 참조 시, 추상화 레벨이 높은 인터페이스, 추상클래스, 상위 클래스를 참조하도록 하자코드에 구현체가 드러나게 되면 기능 변경시, 클라이언트 코드의 변경이 생기므로추상화 레벨이 높은 인터페이스 등을 메소드 파라메터, 필드, 리턴타입으로 활용하도록 하자

백엔드ReadableCode워밍업클럽2기

seonman.kim

워밍업 클럽 2기(클린코드, 테스트코드) 과제

Readable Code: 읽기 좋은 코드를 작성하는 사고법(링크)이 글은 위의 강의중 제가 중요하다고 생각한 부분과, 저만의 의견을 덧붙여서 정리해보았습니다.모든 내용과 정확한 내용을 보고싶다면 위의 강의를 수강하여 들으시는 것을 제안 드립니다. SOLIDSRPSingle Responsibility Principle (단일 책임의 원칙)하나의 객체는 하나의 역할만 해야 한다. 하나의 객체에서 하나의 역할만 처리하기 때문에 높은 응집도와 낮은 결합도를 유지하게 된다.하나의 기능을 하나의 객체에서만 처리하기 때문에 처리에 필요한 요소는 하나의 클래스에 존재하여 응집도가 향상된다.하나의 객체에서만 처리하기 때문에 다른 클래스와의 결합도는 약해진다. OCPOpen-Closed Principle (개방 폐쇄 법칙)(기능)확장에는 열려있고, (코드) 수정에는 닫혀있는 방식, 즉, 코드를 수정하지 않고 기능 추가를 할 수 있는 방식인터페이스와 다형성을 이용하여 구현한다.LSPLiskov Substitution Principle상속 관계에서 자식이 부모 클래스의 역할을 변경하거나 영향을 주면 안된다.ISPInterface Segregatin Principle (인터페이스 분리 원칙)인터페이스의 구현한 클래스는 인터페이스의 모든 메소드를 사용해야 한다.문법 상으로 전부 사용해야 하지만, 사용하면 예외(Unsupport Opeartion Exception)를 발생시키는 방식으로 사용하지 않을 수 있다.DIPDependency Inversion Principle (의존성 역전 방식)높은 추상화 객체에서 낮은 낮은 추상화 객체로 의존해야 하지만, 모든 객체는 높은 추상화 객체를 의존해야 한다.낮은 추상화 객체를 참조하면, 구현이 달라졌을 경우 의존하는 모든 객체에 영향이 생긴다.

kimusvita

Readable Code (1) : 읽기 좋은 코드를 작성하는 사고법 (Day2)

추상강사님이 최대한 더럽고 시간 복잡도가 높은 최악의 코드를 골라오셨고, 우리는 이번 시간을 통해 이 코드를 읽기 좋은 코드로 거듭나기 위한 순서를 따라갔다. 1. 직관적으로 변수이름을 바꾸기를 실행하자.예를 들어, for loop에서 단순히 i, j로 두던 것을 row, col로 바꾸는 등의 refactoring을 진행했다.Refactoring Variable# for (int i = 0; i < 8; i++) { # for (int j = 0; j < 10; j++) { # board[i][j] = "□"; # } # } //수정 사항: 변수 이름 직관적으로 짓기 for (int row = 0; row < 8; row++) { for (int col = 0; col < 10; col++) { board[row][col] = "□"; } }   2. 잘 쓰여진 메서드는 주제가 하나다.한 가지를 실행하는데 집중한다. 코드를 읽고 이 메서드가 하는 일이 여러 개라면 작은 메서드로 나누는 게 좋다.기본적이지만 처음엔 어려웠던 부분인데 다시 짚고 넘어가봐서 좋았다. 3. 메서드 선언부- void 대신 충분히 반환할 값이 있는지 고민해보는 습관을 가지자. 반환값이 있다면 테스트도 용이해진다. 물론 void가 더 깔끔한 순간도 많으나, 한번쯤 고민해보자.- 구체화된 타입을 반환받는다.- 의미가 명확한 변수 이름을 사용한다._사용하는 입장에서도 더 편하게 쓸 수 있고, 후손 개발자 입장에서도 어떤 것을 넣어야하는 변수인지 알기 쉽다._  4. 추상화 레벨method를 추출한다는 것 자체가 외부 세계와 내부 세계의 경계를 만든다는 뜻이다. 하나의 세계 안에서는 추상화 레벨이 동등해야 한다.추상화 레벨이 맞지 않아 일어나는 문제가 꽤나 잘 들어난다.추상화 레벨이 맞지 않는 상황이 나타나면 클린코드라 하기 어렵다. 자세한 사항은 개인 블로그에 기재하였습니다.https://velog.io/@dhlee47-l/Readable-Code-%EC%9D%BD%EA%B8%B0-%EC%A2%8B%EC%9D%80-%EC%BD%94%EB%93%9C%EB%A5%BC-%EC%9E%91%EC%84%B1%ED%95%98%EB%8A%94-%EC%82%AC%EA%B3%A0%EB%B2%95-Day2

웹 개발CleanCode박우빈강사님추상JAVA발자국

seonman.kim

인프런 워밍업클럽 2일차

Readable Code: 읽기 좋은 코드를 작성하는 사고법(링크)이 글은 위의 강의중 제가 중요하다고 생각한 부분과, 저만의 의견을 덧붙여서 정리해보았습니다.모든 내용과 정확한 내용을 보고싶다면 위의 강의를 수강하여 들으시는 것을 제안 드립니다. 논리 사고의 흐름정리 시스템에서 중요한 과제는 최소의 인지적 노력으로 최대의 정보를 제공하는 것이다.정보를 제공하는 것은 공통된 특징을 추상화하고 범주화하여 정리 시스템을 만드는 것이다.인지적 경제성 : 최소한의 인지로 최대한 성능을 내는 것핵심은 뇌의 메모리를 적게 쓰는 것이다.1. Early returnif-else 절을 사용할 때 두 조건을 동시에 기억해야 하기 때문에 코드 분석하기 복잡해진다.if 조건을 참일 경우 리턴함으로써 else 를 사용하지 않아도 된다. 2. depth 줄이기여러 depth를 메소드로 분리하여 줄이는 방법보이는 depth를 줄이는 것이 아니라 사고 과정의 depth을 줄여야 한다.무작정 1 depth로 만드는 것이 정답이 아니다. 3. 사용할 변수는 가깝게 선언4. 공백라인복잡한 의미 단의를 공백으로 분리5. 부정어는 자제한다.!연산자는 머리 속에서 한번 더 생각해야 하기 떄문에 복잡해진다.부정할 경우 대표할 수 있는 경우 메소드 이름을 변경하고, 대표할 수 없다면 메소드 명에 부정어구를 추가한다.6. 해피 케이스와 예외처리예외값의 유효성을 체크할 경우 외부 세계에서 값이 들어올 경우 접점에서 검사한다.사용자 입력, 객체 생성자, 외부 서버등내가 처리하지 않은 예외는 추후 분석이 가능하도록 콜스택을 출력해둔다.널을 대하는 자세변수에 null이 들어오지 않도록 하는 것이 가장 좋다.return null은 사용하지 않는다. 개발자는 메소드가 null을 리턴하지 않을 경우를 가정하고 메소드를 사용한다.optional을 사용하지 말하야하는 이유호출 비용이 크다.포함한 값의 널값 여부와 자체가 널인지도 확인해야 한다.optional을 사용할 때는 아래 메소드를 최대한 사용한다.orElseGet(), orElseThrow(), ifPresent(), ifPresentOrElse()

seonman.kim

인프런 워밍업클럽 1일차

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이 글은 위의 강의중 제가 중요하다고 생각한 부분과, 저만의 의견을 덧붙여서 정리해보았습니다.정확한 내용과 더 많은 내용을 듣고싶다면 위의 강의를 수강하여 들으시는 것을 제안 드립니다. 시작하며..지금까지 회사를 다니면서 간단한 CRUD 작업만 하다보니 스프링 프레임워크에서 제공해주는 기본적인 구조로만 작업을 해왔다. 나름 객체지향, 클린코드를 지향하며 코드를 작성했다고 생각했는데 객체지향은 개뿔.. 아무것도 사용하지 않았더라.. 물론 코드는 간단했고, 가독성도 있어보였고, 가독성도 좋더라.왜냐하면 로직 자체가 간단했으니까.. 그래서 이번 기회에 인프런 워밍업 클럭 밴엔드 과정을 진행하면서 매일마다 간단 후기를 작성하고자 한다. 읽기 좋은 코드코딩 작업의 대부분은 코드를 작성하는 시간보다 코드를 읽는 시간이 압도적으로 많다.내가 작성한 코드는 작성하는 순간 레거시 코드가 된다. 다른 개발자가 볼 수 있지만, 내가 될 수도 있수도 있고..!! (내가 작성한 코드는 내가 가장 많이 본다 ㅋㅋㅋㅋ)읽기 좋은 코드는 유지보수 하기 편하고, 내가 업무하기 편해지고, 월급이 올라간다!! 프로그램의 정의프로그램 : 데이터 + 코드잘 추상화된 데이터는 코드로 다루기가 쉬워진다. 추상추상 : 사물을 정확하게 이해하기 위해서 사물이 지니고 있는 여러가지 측면 가운데서 특정한 측면만을 가려내어 포착하는 것 (위키)즉, 중요한 정보는 남기고, 중요하지 않은 정보는 생략하는 것추상의 반대는 구체이다.구체 -> 추상 : 추상화, 추상 -> 코드 : 구체화타입도 데이터의 추상화이다. 이진수 -> 바이트 -> 문자, 숫자 -> 구조체 -> 객체기계어 -> 프로그래밍 언어하드웨어 -> 운영체제 -> 애플리케이션OSI 7계층변수의 이름을 짓는 행위메소드의 추상화 추상화 레벨하나의 영역 안에서 추상화 레벨은 동등해야 한다. 같은 영역(메소드, 블럭 등) 안에서 추상화 레벨이 동일해야 가독성이 좋아진다.

백엔드

Kenzie8

AI 시대 '서비스 기획자'는 어떤 형태로 진화할까?

 이제 우리가 이용하는 많은 서비스들에 크던 작던 AI기술들이 적용되고, 업무 현장에서도 챗GPT와 같은 AI도구들이 심심치 않게 활용되고 있습니다. 분명 지금 우리가 살고 있는 시대는 2~3년 전과 확연히 달라졌고, 앞으로 2~3년 뒤에는 지금까지의 변화와는 비교도 안되게 많은 변화들을 체감하게 될 것이라고 많은 전문가들이 입을 모아 얘기합니다. 앞으로 AI가 좀 더 우리 삶 깊숙히 개입하게 되면 서비스를 기획하는 서비스 기획자라는 직업의 성격도 바뀌게 될 것이고 그에 걸맞게 요구되는 능력도 조금 달라지지 않을까요? 그래서 한 번 제 나름의 생각을 정리해 보았습니다.AI 시대의 서비스 기획자는 단순히 서비스의 외형만 설계하는 것이 아니라, AI와 데이터를 기반으로 사용자 경험을 보다 정교하게 설계하는 역할을 하게 될 것으로 예상합니다. 항목별로 서비스 기획자에게 요구될 역량을 살펴보시죠!1. AI 이해 및 활용 능력서비스 기획자는 AI 기술의 기본 원리와 이를 서비스에 어떻게 적용할 수 있을지에 대한 깊은 이해가 필요합니다. AI가 고객 데이터를 어떻게 처리하고, 사용자의 행동 패턴을 분석하며, 개인화된 경험을 제공하는지에 대해 숙지해야 합니다. AI 모델을 직접 설계하지 않더라도 이를 적절히 활용할 수 있는 전략을 세우는 능력이 중요해집니다.2. 데이터 분석 및 해석 능력AI는 방대한 데이터를 처리하고 분석하는 데 강점을 가지고 있습니다. 서비스 기획자는 AI가 처리한 데이터를 바탕으로 사용자 요구와 행동을 파악하고, 이를 토대로 더 나은 서비스 경험을 설계할 수 있어야 합니다. 데이터를 읽고 해석하여 적절한 인사이트를 도출하는 능력은 필수입니다.3. UX와 AI를 결합하여 사용자 경험을 설계하는 능력사용자 경험(UX) 설계는 AI가 발전함에 따라 더욱 개인화되고 예측 가능한 형태로 변화할 것입니다. 기획자는 AI가 제공하는 데이터와 기술을 바탕으로 사용자의 요구를 미리 예측하고, 사용자와 상호작용하는 방식을 최적화해야 합니다. 예를 들어 챗봇이나 추천 시스템을 통해 사용자의 흐름을 매끄럽게 유도하는 등, AI와 UX를 결합한 새로운 사용자 경험을 설계하는 능력이 중요해집니다.4. 창의적 문제 해결 능력AI가 많은 작업을 자동화하고 효율화할 수 있지만, 인간 기획자는 창의적인 문제 해결과 혁신적인 아이디어 창출에 여전히 중요한 역할을 합니다. AI의 한계를 보완하고 새로운 서비스를 구상하며, 사람들의 실제 니즈와 감정적인 요구를 이해하고 이를 해결할 수 있는 서비스를 기획하는 것이 필요합니다.5. 협업 및 커뮤니케이션 능력AI 개발자, 데이터 과학자, 디자이너 등 다양한 전문가들과 협업하는 능력은 필수적입니다. AI와 데이터를 효과적으로 활용하려면 기술 팀과의 원활한 소통이 중요하며, 기술적 이해와 비즈니스적 목표를 연결할 수 있는 역량이 요구됩니다.6. 지속적인 학습AI와 관련된 기술은 빠르게 발전하고 있기 때문에, 서비스 기획자는 끊임없이 새로운 기술 동향을 학습하고 이를 서비스 기획에 적용할 수 있는 능력을 갖추어야 합니다. 머신러닝, 데이터 사이언스, 사용자 행동 분석 등의 분야에서 최신 트렌드를 따라가는 것이 필수입니다.결론위의 내용을 딱 한 문장으로 요약해서 AI시대 서비스 기획자를 정의하자면 "기술적 이해를 바탕으로 창의적이고 전략적인 사고를 통해 AI가 가진 잠재력을 최대한 활용하여 새로운 사용자 경험을 설계하는 사람." 정도이지 않을까요? AI 시대를 준비하려는 여러분들을 위해 서비스 기획자에게 요구되는 역량중에 하나이고, 갈수록 점점 더 그 중요성을 더해가고 있는 데이터 분석과 해석 능력을 키울 수 있는 콘텐츠를 준비하였습니다. 제가 심혈을 기울여 만든 저의 콘텐츠를 활용해서 AI시대가 찾는 서비스 기획자가 되어보는 건 어떨까요?인프런 강의 주소: https://inf.run/2RbLo[ESTsoft] WASSUP EST AI서비스 기획자 양성과정 5기 모집 (※마감 임박!): https://estfamily.career.greetinghr.com/o/121077  ※ 틈틈이 남는 시간을 활용해서 공부 하셔야 하는 분들은 인프런 강의를,하루 8시간 이상 수업에 할애하실 수 있는 분들은 WASSUP 과정을 추천 드립니다. 참고로 두 개 모두 100% 온라인으로 진행됩니다.  

데이터 분석AI인공지능데이터서비스기획UX프로덕트Product기획POPM

채널톡 아이콘