2024년 인프콘 후기 - #5 객체지향은 여전히 유용한가

Joshua_Kim·2024년 8월 11일
21

2024년 인프콘 회고

목록 보기
6/6
post-thumbnail
post-custom-banner

🌱 0. 서론

  • 📣 스피커 : 조영호 - [객체지향의 사실과 오해], [오브젝트] 저자
  • 세션을 선택한 이유
    작년 말 회사에 조영호님이 직접 오셔서 특강을 해주셨는데 나는 그때 라섹 수술이있어서 참여를 못했었다.
    개인적으로 너무너무 아쉬웠었는데, 이렇게 인프콘에서라도 꼭 뵙고 이야기를 듣고싶었다.
    '객체지향' 이라는 단어를 들으면 가장 먼저 생각나는 개발자 조영호님!

✍🏻 1. 세션 정리

"객체지향은 '여전히' 유용한가요?"

아무래도, 조영호님은 객체지향에 대한 책도 쓰셨고, 이 주제로 많은 곳에서 강의를 하시다보니, 객체지향에 대한 질문을 많이 받으신다고 한다.
그런데 많은 질문들 중, 간혹 이런 질문이 들어온다고한다.

🧐 : "객체 지향은 여전히 유용한가요?"

왜 이런 질문을 할까?

아마도, 내가 하고 있는 개발의 방식과 철학이 맞는지 확인받고 싶은 심리 때문일수도 있다.
혹은, 너무나 빠르게 바뀌고 있는 기술의 발전 속도 때문에 내가 개발하고 있는 방법론이 아직도 현역인가를 알고 싶은 것일 수도 있다.

그러나 좀 더 좋은 성장을 하기 위해서는 질문을 조금 바꿀 필요가 있다.

"객체 지향은 '언제' 유용한가?"

이 세션에서는 한가지 예제를 기준으로 '절차적인 방식' 과 객체지향적인 방식'을 비교하면서 '언제' 유용한지 살펴볼 것이다.


예제로 알아보는 절차적인 설계 vs 객체지향적인 설계

👩🏻‍💻 예제 : 장바구니에 할인 프로모션을 적용하는 기능을 개발한다.

case 1> 기본 설계

  • 내 장바구니 (Cart) 에 담긴 모든 상품의 가격이 할인 프로모션의 기준 금액보다 클 경우, 프로모션을 적용하도록 한다.

절차지향적인 코드

// 행위의 속성
public class PromotionProcess {
    public void apply(Promotion promotion, Cart cart) {
        if (isApplicableTo(promotion, cart)) {
            promotion.setCart(cart.getId());
        }
    }

    private boolean isApplicableTo(Promotion promotion, Cart cart) {
        return cart.getTotalPrice() >= promotion.getBasePrice();
    }
}

// Data 의 속성
public class Promotion {
    private Long cartId;
    private Long basePrice;

    public Money getBasePrice() {
        return basePrice;
    }

    public void setCart(Long cartId) {
        this.cartId = cartId;
    }
}

public class Cart {
    private List<CartLineItem> items = new ArrayList<>();

    public Long getTotalPrice() {
        return items.stream().mapToLong(CartLineItem::getPrice).sum();
    }

    public int getTotalQuantity() {
        return items.stream().mapToInt(CartLineItem::getQuantity).sum();
    }
}
  • 위의 코드는 절차지향적으로 코드를 작성한 것이다.
  • PromotionCart 라는 Data 형식의 클래스가 존재한다.
  • PromotionProcess 는 위의 두 Data 형식의 클래스를 활용하여 행위를 진행한다.

객체지향적인 코드

public class Promotion {
    private Cart cart;
    private Long basePrice;

    public void apply(Cart cart) {
        if (cart.getTotalPrice() >= basePrice) {
            this.cart = cart;
        }
    }
}

public class Cart {
    private List<CartLineItem> items = new ArrayList<>();

    public Long getTotalPrice() {
        return items.stream().mapToLong(CartLineItem::getPrice).sum();
    }

    public int getTotalQuantity() {
        return items.stream().mapToInt(CartLineItem::getQuantity).sum();
    }
}
  • 위 코드는 객체지향적으로 변경한 것이다.
  • ProcessCart 는 각자의 책임을 가지고 '행위'를 가진다.

절차지향적인 코드와 객체지향적인 코드의 비교

  • 하나의 요구사항을 두고, 두가지 방법으로 설계를 하면 위와 같이 간단하게 표현할 수 있다.

이제, 위의 기본 예제를 바탕으로 여러가지 변경을 진행해보자. 레츠고!


case 2> 할인 여부 판단의 '데이터를 변경'한다.

요구사항이 변경되었다.
할인 여부 판단하는 데 사용하는 '데이터'가 변경이 되었다.

요구사항 변경

  • 내가 주문하려는 전체 물건의 가격이 프로모션 최소금액보다는 커야하고, 프로모션의 최대금액보다는 작아야한다

절차지향적인 코드의 변경

public class PromotionProcess {
    public void apply(Promotion promotion, Cart cart) {
        if (isApplicableTo(promotion, cart)) {
            promotion.setCart(cart.getId());
        }
    }

    private boolean isApplicableTo(Promotion promotion, Cart cart) {
    	// 변경지점
        return (cart.getTotalPrice() >= promotion.getMinPrice()) &&
               (cart.getTotalPrice() <= promotion.getMaxPrice());
    }
}

public class Promotion {
    private Long cartId;
    // 두 필드가 변경되었다.
    private Long minPrice;
    private Long maxPrice;

    public Long getMinPrice() {
        return minPrice;
    }

    public Long getMaxPrice() {
        return maxPrice;
    }

    public void setCart(Long cartId) {
        this.cartId = cartId;
    }
}

  • 데이터와 데이터를 사용하는 프로세스가 별도의 클래스에 구현되어있기 때문에, 데이터가 변경되면 프로세스가 같이 변경된다.
  • 변경 지점이 많다는 것은 '결합도가 높다' 라는 것을 의미한다.

객체지향적인 코드의 변경

public class Promotion {
    private Cart cart;
    private Long minPrice;
    private Long maxPrice;

    public void apply(Cart cart) {
        if ((cart.getTotalPrice() >= minPrice) &&
            (cart.getTotalPrice() <= maxPrice)) {
            this.cart = cart;
        }
    }
}

public class Cart {
    private List<CartLineItem> items = new ArrayList<>();

    public Long getTotalPrice() {
        return items.stream().mapToLong(CartLineItem::getPrice).sum();
    }

    public int getTotalQuantity() {
        return items.stream().mapToInt(CartLineItem::getQuantity).sum();
    }
}
  • 객체지향은, 데이터와 프로세스를 캡슐화 하고 잇기 때문에, 데이터가 변경될 때, 내부만 변경하면 간단히 구현이 완료된다.
  • 변경 지점이 딱 책임을 가진 곳만 일어난다. 즉 결합도가 낮다.

'데이터'의 변경으로 인한 두 설계의 변경지점 비교

  • 절차적인 설계에서는 변경지점이 전파가 된다.
  • 객체지향적인 설계에서는 변경지점이 캡슐화된 그 객체 내부만 일어나게 된다.

case 3> 할인 여부 판단에 '새로운 조건을 추가'한다.

  • 이번에는 할인 여부를 판단하는 조건에 '새로운 타입을 추가' 함으로, 조건을 추가하게 된다.

요구사항 변경

  • 내가 주문하는 총 금액이 프로모션의 기준 금액보다 높아야한다.
  • 추가된 조건 : 주문하는 물건의 총 수량이 프로모션의 총수량 기준보다 많아야한다

절차지향적인 코드의 변경

public class PromotionProcess {
    public void apply(Promotion promotion, Cart cart) {
        if (isApplicableTo(promotion, cart)) {
            promotion.setCart(cart.getId());
        }
    }

    private boolean isApplicableTo(Promotion promotion, Cart cart) {
        switch (promotion.getConditionType()) {
            case PRICE:
                return cart.getTotalPrice() >= promotion.getBasePrice();
            // '총 수량' 이라는 조건을 추가한다.
            case QUANTITY:
                return cart.getTotalQuantity() >= promotion.getBaseQuantity();
        }
        return false;
    }
}

// 프로며션의 기준이 되는 Enum 타입을 선언한다.
public class Promotion {
    public enum ConditionType {
        PRICE, QUANTITY
    }

    private ConditionType conditionType;
    private Long cartId;
    private Long basePrice;
    private int baseQuantity;

    public ConditionType getConditionType() {
        return conditionType;
    }

    public Money getBasePrice() {
        return basePrice;
    }

    public int getBaseQuantity() {
        return baseQuantity;
    }

    public void setCart(Long cartId) {
        this.cartId = cartId;
    }
}

  • 절차적인 설계에서는 위와 같은 조건이 추가가 되면 '데이터' 와 '프로세스' 모두 변경이 되어야 한다.
  • 하지만, 위와 같은 절차적인 설계는 앞으로 조건이 추가되더라도 리팩토링의 범위가 적다.

객체지향적인 코드의 변경

public class Promotion {
    private Cart cart;
    private DiscountCondition condition;

    public void apply(Cart cart) {
        if (condition.isApplicableTo(cart)) {
            this.cart = cart;
        }
    }
}

public class Cart {
    private List<CartLineItem> items = new ArrayList<>();

    public Long getTotalPrice() {
        return items.stream().mapToLong(CartLineItem::getPrice).sum();
    }

    public int getTotalQuantity() {
        return items.stream().mapToInt(CartLineItem::getQuantity).sum();
    }
}

// 할인 조건이라는 interface 를 생성한다.
public interface DiscountCondition {
    boolean isApplicableTo(Cart cart);
}

// 조건이 추가될 때마다 DiscountCondition 을 구현한다.
public class PriceCondition implements DiscountCondition {
    private Long basePrice;

    @Override
    public boolean isApplicableTo(Cart cart) {
        return cart.getTotalPrice() >= basePrice;
    }
}

public class QuantityCondition implements DiscountCondition {
    private int baseQuantity;

    @Override
    public boolean isApplicableTo(Cart cart) {
        return cart.getTotalQuantity() >= baseQuantity;
    }
}
  • 객체지향적인 설게는 언뜻 보면 조금 복잡해 보인다.
  • 객체지향의 꽃인 '다형성' 을 이용하여 설게 변경을 풀어냈다.
  • 만약, 프로모션의 조건이 추가가 된다면 조건이 추가될 때마다 DiscountCondition 을 구현하는 클래스를 추가해야 할 것이다.
    - 절차적인 설계에 비해 꽤 리팩토링 범위가 넓다고 볼 수 있다.
  • 하지만, 객체지향적인 설계는 다른 코드를 수정하지 않고 데이터 변경과 타입이 확장 가능하다.
  • 또한 DiscountCondition 이라는 interface 를 구현한다는 강제성을 가지기에, 일관성을 가질 수 있다.

'조건의 추가' 로 인한 두 코드의 변경지점 비교

  • 절차지향은 변경지점이 상대적으로 국소적이지만, 데이터와 프로세스 두 영역이 모두 변경이 된다.
  • 객체지향은 다형성을 사용하여 인터페이스를 구현하는 구조로 변경되어 리팩토링의 범위가 넓어졌으나, 그 이후로는 일관성있는 코드를 작성할 수 있게 된다.

객체지향의 강점


  • 위의 사례를 통해 절차지향과 객체지향을 살펴보면 객체지향이 앞도적인 강점을 가진다.
  • 확장성 있는 코드 : 다형성을 통해 책임이 분명한 곳만 변경지점이 명확해진다.
  • 일관성 있는 코드 : interface 를 통해 강제성을 가지게되어 일관성을 지킬 수 있게 된다.

그렇다면, 언제나 객체지향이 짱짱맨 일까?
위의 예시만을 보면 객체지향이 무조건 좋아보인다.
또한, 우리는 언제나 '객체지향적으로 코드를 짜자!' 라는 말을 무수히 들어봤으므로 당연히 '객체지향'이 절차지향보다 우수하다고 생각하기 쉽다.

하지만 정답은

No!!! 🙅🏻

다른 예시를 통해 조금 더 절차지향과 객체지향을 비교해보자.


case 4> '장바구니 항목' 이라는 데이터를 추가하고, 이것을 통해 할인 여부를 판단하는 기능을 추가한다.

요구사항 변경

  • '장바구니 항목' 이라는 데이터가 추가되고, 조건이 이것으로 변경되었다.
  • CartLineItem 이라는 새로운 데이터가 추가되었다.

이 내용은, case3 을 적용하기 전과 후로 나눠서 비교하도록 하겠다.
case 3 의 핵심은 '새로운 조건을 추가' 하는 것이었다.

case 4-1> case 3 적용 전, case 4 를 적용한다.

절차지향적인 코드의 변경

public class PromotionProcess {
    public void apply(Promotion promotion, Cart cart) {
        if (isApplicableTo(promotion, cart)) {
            promotion.setCart(cart.getId());
        }
    }

    private boolean isApplicableTo(Promotion promotion, Cart cart) {
        return cart.getTotalPrice() >= promotion.getBasePrice();
    }
	
    // CartLineItem 이 추가 되었다.
    public boolean isDiscountable(Promotion promotion, CartLineItem item) {
        return item.getPrice() >= promotion.getBasePrice();
    }
}

public class Promotion {
    private Long cartId;
    private Long basePrice;

    public Money getBasePrice() {
        return basePrice;
    }

    public void setCart(Long cartId) {
        this.cartId = cartId;
    }
}
  • 위와 같이 processCartLineItem 관련된 코드가 추가가 된다.

객체지향적인 코드의 변경

public class Promotion {
    private Cart cart;
    private Long basePrice;

    public void apply(Cart cart) {
        if (cart.getTotalPrice() >= basePrice) {
            this.cart = cart;
        }
    }
	
    // 판단 로직은 Promotion 에만 영향을 준다.
    public boolean isApplicableTo(CartLineItem item) {
        return item.getPrice() >= basePrice;
    }
}

public class Cart {
    private List<CartLineItem> items = new ArrayList<>();

    public Long getTotalPrice() {
        return items.stream().mapToLong(CartLineItem::getPrice).sum();
    }

    public int getTotalQuantity() {
        return items.stream().mapToInt(CartLineItem::getQuantity).sum();
    }
}
  • 캡슐화가 되어 판단 로직은 Promotion 에만 영향을 주게된다.

case 4-2> case 3 이 이미 적용된 후에 case 4 요구사항이 추가된 경우

이 경우에는, 객체지향적인 설계에는 interface 가 적용이 된 이후다.

  • 현재 위와 같은 구조에서 case 4 의 요구사항을 처리하는 것이 case 4-2 의 요구사항이다.

절차지향적인 코드의 변경

public class PromotionProcess {
    public void apply(Promotion promotion, Cart cart) {
        if (isApplicableTo(promotion, cart)) {
            promotion.setCart(cart.getId());
        }
    }

    private boolean isApplicableTo(Promotion promotion, Cart cart) {
        switch (promotion.getConditionType()) {
            case PRICE:
                return cart.getTotalPrice() >= promotion.getBasePrice();
            case QUANTITY:
                return cart.getTotalQuantity() >= promotion.getBaseQuantity();
        }
        return false;
    }
	
    // 해당 부분이 추가 되었다. 
    public boolean isApplicableTo(Promotion promotion, CartLineItem item) {
        switch (promotion.getConditionType()) {
            case PRICE:
                return item.getPrice() >= promotion.getBasePrice();
            case QUANTITY:
                return item.getQuantity() >= promotion.getBaseQuantity();
        }
        return false;
    }
}

public class Promotion {
    public enum ConditionType {
        PRICE, QUANTITY
    }

    private ConditionType conditionType;
    private Long cartId;
    private Long basePrice;
    private int baseQuantity;

    public ConditionType getConditionType() {
        return conditionType;
    }

    public Money getBasePrice() {
        return basePrice;
    }

    public int getBaseQuantity() {
        return baseQuantity;
    }

    public void setCart(Long cartId) {
        this.cartId = cartId;
    }
}
  • 위의 코드는 절차지향적으로 코드가 변경되었다.
  • 새로운 기능이 추가된다면 추가될 때 마다 중복코드가 있겠지만 썩 나빠보이지는 않는다.

객체지향적인 코드의 변경

public class Promotion {
    private Cart cart;
    private DiscountCondition condition;

    public void apply(Cart cart) {
        if (condition.isApplicableTo(cart)) {
            this.cart = cart;
        }
    }
	
    // 추가 되었다.
    public boolean isApplicableTo(CartLineItem item) {
        return condition.isApplicableTo(item);
    }
}

// interface 에 함수를 하나 더 추가한다.
public interface DiscountCondition {
    boolean isApplicableTo(Cart cart);
    boolean isApplicableTo(CartLineItem item);
}

// 구현한 클래스 마다 추가된 함수를 구현해야한다.
public class PriceCondition implements DiscountCondition {
    private Long basePrice;

    @Override
    public boolean isApplicableTo(Cart cart) {
        return cart.getTotalPrice() >= basePrice;
    }

    @Override
    public boolean isApplicableTo(CartLineItem item) {
        return item.getPrice() >= basePrice;
    }
}

// 구현한 클래스 마다 추가된 함수를 구현해야한다.
public class QuantityCondition implements DiscountCondition {
    private int baseQuantity;

    @Override
    public boolean isApplicableTo(Cart cart) {
        return cart.getTotalQuantity() >= baseQuantity;
    }

    @Override
    public boolean isApplicableTo(CartLineItem item) {
        return item.getQuantity() >= baseQuantity;
    }
}
  • 객체지향적으로 코드를 변경해보았다.
  • 이렇게 된다면, 타입 계층 전체가 수정이 불가피해진다.

객체지향적인 코드 - 타입 계층 전체의 수정이 필요

  • 이렇게 된다면 코드는 불필요한 일을 할 가능성이 커진다.
  • 즉, 다형성과 기능 추가 사이에 긴장을 가지게 된다.

즉, 상황에 따라 절차지향적인 설계가 더 좋을 수 있다!! 💡


case 5> 데이터의 변환이 필요한 경우

절차지향적인 코드

public class PromotionProcess {
    public CartWithPromotion convertToCartWithPromotion(
            Promotion promotion, Cart cart) {
        CartWithPromotion result = new CartWithPromotion();
        result.setTotalPrice(cart.getTotalPrice());
        result.setTotalQuantity(cart.getTotalQuantity());
        result.setPromotionBasePrice(promotion.getBasePrice());
        result.setPromotionBaseQuantity(promotion.getBaseQuantity());
        return result;
    }
}

public class Promotion {
    public enum ConditionType {
        PRICE, QUANTITY
    }

    private ConditionType conditionType;
    private Long cartId;
    private Long basePrice;
    private int baseQuantity;

    // getter & setter
    // ...
}
  • 절차지향적인 코드에서는 데이터계층이 분리되어있다.
  • 그렇기 때문에, 이 데이터가 변환이 되는것도 매우 간편하게 할 수 있다.

객체지향적인 코드

public class Promotion {
    private Cart cart;
    private DiscountCondition condition;
    // ...

    public CartWithPromotion convertToCartWithPromotion() {
        CartWithPromotion result = new CartWithPromotion();
        result.setTotalPrice(cart.getTotalPrice());
        result.setTotalQuantity(cart.getTotalQuantity());

        if (condition instanceof PriceCondition) {
            result.setPromotionBasePrice(
                ((PriceCondition) condition).getBasePrice());
        }

        if (condition instanceof QuantityCondition) {
            result.setPromotionBaseQuantity(
                ((QuantityCondition) condition).getBaseQuantity());
        }

        return result;
    }
}

public interface DiscountCondition {
    boolean isApplicableTo(Cart cart);
    boolean isApplicableTo(CartLineItem item);
}

public class PriceCondition implements DiscountCondition {
    private Long basePrice;
    // ...
}

public class QuantityCondition implements DiscountCondition {
    private int baseQuantity;
    // ...
}
  • 상당히 뭔가 불편하다.
  • 데이터를 변환하는 상황에서 객체지향적으로 코드를 짜려고하면 상당히 어색한 것을 확인할 수 있다.

절차지향적 코드의 장점

  • 절차지향적인 코드는 '데이터 처리' 를 하는 영역에서 매우 적합하게 사용된다.

예제로 알아본 절차지향 vs 객체지향 정리

위의 예제로 절차지향과 객체지향에 대해 알아봤다.
이제는 두개의 역할과 장단점에 대해 정리를 해보자.

절차지향적 설계

  • 데이터를 변환하고 포매팅하는 것에 매우 유리하다.
  • 기능 추가에 유리하다.
  • 데이터 중심적 이다.
  • 데이터의 응집도에 따라 설계를 해야한다.

객체지향적 설계

  • 다형성을 활용하여 일관된 규칙에 기반하여 상태를 변경할 수 있다.
  • 데이터는 캡슐화 되어 있다.
  • 행동 중심 이며, 타입 확장에 유리하다.
  • 행동의 응집도에 따라 설계를 해야한다.

레이어드 아키텍쳐로 확인해보는 절차지향과 객체지향의 쓰임새

레이어드 아키텍쳐

  • 백엔드 엔지니어라면 너무나도 익숙한 레이어드 아키텍쳐 구조다.
  • 각각의 레이어에서는 어떤 관점으로 코드를 작성해야 할까?

도메인 레이어 - 객체지향

  • 어플리케이션의 핵심 로직이 있는 도메인 레이어는 '객체지향' 으로 코드를 작성해야한다.
  • 행위와 규칙 기반으로 코드를 설계해야한다.

프리젠테이션 레이어 - 절차지향

  • Controller 로 대부분 이해되는 프리젠테이션 레이어는 '절차지향'적이다.
  • 서비스레이어를 통해 요청된 데이터를 알맞는 그릇(DTO)로 변환해서 클라이언트에 반환을 시켜주는 역할을 수행한다.
  • 절차지향에 매우 적합한 '데이터 변환' 의 역할을 수행한다.

서비스 레이어 - 절차지향

  • 서비스 레이어 역시 '절차지향'적이다.
  • 서비스 레이어는 퍼시스턴스 레이어를 통해 찾아온 데이터를 도메인 레이어에 넘겨서 로직을 수행하고, 그 수행된 로직을 프리젠테이션 레이어로 넘겨준다.
  • 즉, 서비스레이어는 전체적인 어플리케이션의 '플로우' 를 제어하는 역할을 한다.
  • 그러므로, '절차지향'적으로 로직을 설계하게된다.

퍼시스턴스 레이어 - 절차지향

  • 퍼시트턴스 레이어 역시 '절차지향'적이다.
  • 데이터베이스를 통해 데이터를 가져오고, 이것을 어플리케이션에서 사용할 수 있도록 변환시켜서 서비스 레이어로 반환하기 때문이다.

레이어드 아키텍쳐의 4개의 레이어 중 3개가 절차지향적이다.

  • 스프링 기반 백엔드 엔지니어가 가장 익숙한 아키텍처인 레이어드 아키텍처.
  • 스프링 기반 백엔드 엔지니어가 가장 많이 듣는 단어인 '객체지향'
  • 하지만, 정작 레이어드 아키텍처에서 객체지향의 관점으로 코드를 작성하는 지점은 하나의 레이어뿐이다.
    - 물론, 도메인 레이어가 핵심이긴하다 😅

여기서 알 수 있는 것은 모든 도구와 관점은 각자의 쓰임새가 있다 는 것이다.


"객체지향은 '언제' 유용한가요?"

"객체지향은 '여전히' 유용한가요?" 라는 질문으로 시작했다.

이제는 질문을 바꾸자.
"객체지향은 '언제' 유용한가요?"

하나의 기술, 하나의 패러다임으로 프로그램을 만들 수 없다.
우리는 이미, 다양한 기술과 패러다임을 결합하여 코딩을 하고 있다.
우리가 사용하고 있는 것들 또한, 여러가지가 결합되어서 만들어진 것들이다.

모든 기술과 설게는 다 용도가 있다.
단지, 무엇이 좋다 무엇이 나쁘다 라고 하는 기준은 절대적일 수 없다.
지금 내가 어떤 상황인지, 어떤 문제를 해결하는지에 대한 고민이 정말 중요하다.
그렇기에 항상, '언제' 유용하고 좋은지 를 고민해야한다.

단순히 '안좋아', '좋아' 라고 이야기할 수 없다.

??? : 절차지향은 안좋아요!! 무조건 객체지향 만세!!

  • 이젠 위와 같은 말을 하는 개발자를 만난다면 피하자.. 😅

다양한 도구들을 배우고, 그 도구를 적절하게 사용하는 것이 중요하다.
정말 많은 패러다임과 도구들이 있는데, 그것을 적합하게 사용해야한다.

즉, 코드의 목적과 변경의 방향성에 따라 언제 어떤 기술을 사용할지 결정하는 것이 중요하다!

유용하지 않은 기술은 없다.
단지, 언제 어떻게 사용하는 것이 좋은 것인지에 대한 시각으로 접근하는 것이 옳다.

🙏🏻 2. 글을 마치며

백엔드 엔지니어로서, 객체지향의 장점과 코드를 객체지향적으로 짜야하다는 말은 무수히 들었다.
어느 순간부터 아주 단순하게 '절차지향은 별로, 객체지향만 최고' 라는 생각이 자리 잡았었다.
그리고, 이 세션을 통해 아주 철저하게 그 생각이 부서졌다.
개발은 결코 '은탄환'이 없는데, 객체지향을 내가 어느 순간 '은탄환' 으로 여기고 모든 것에 다 접목하려고 잣대를 들이밀었던 것 같다.
(그래 놓고서는 사실 객체지향적인 코드가 뭔지도 잘 모른채 개발을 하고 있기도 하다... 😅)

정말 너무 유익하고 귀한 세션이었다.

profile
인문학 하는 개발자 💻
post-custom-banner

6개의 댓글

comment-user-thumbnail
2024년 8월 13일

얼마나 객체지향적으로 개발해야하는가에 대해 고민 했었는데 너무 깔끔하게 정리된 것 같아요! 감사합니다 😊

1개의 답글
comment-user-thumbnail
2024년 8월 20일

정말 변태같이 꼼꼼하게 적었네요...

1개의 답글
comment-user-thumbnail
2024년 8월 24일

제 포지션으로 인한 이데아가 있어서 그런지,
FE에서 OOP를 하기 어려운 이유를 읽고 있는 느낌이었네요.

정리한 글 잘 읽었습니다.

1개의 답글