fender
24k
2021-11-18 06:17:24
35
3398

객체지향과 함수형 프로그래밍


제목은 거창하게 썼지만 이번에는 그냥 잡담입니다.

함수형 프로그래밍을 접하고 나서 기회가 있을 때 마다 객체지향과 접점을 찾기 위해 이런 저런 시도를 하는 중인데 쉬운 문제는 아닌 것 같습니다.

이번 코틀린/리액트 프로젝트에서도 리덕스 액션에선 제법 그럴듯하게 클래스와 함수형 접근을 조합했다고 생각하는데, 정작 함수형 컴포넌트에 폴리모피즘이 필요한 문제는 하루 종일 고민을 해도 좋은 방법이 떠오르지 않네요.

클래스 컴포넌트를 쓰면 간단히 풀리겠지만, 리액트 자체가 함수형에 강하게 기울어져 있기 때문에 선듯 손이 가진 않는군요.

대략 "구조는 객체지향으로, 구현은 함수형으로" 정도의 방향이 이상적일 것 같다는 생각은 있는데 아직 명확하게 생각이 정리되려면 더 많은 시간이 필요할 것 같습니다.

분명 저만 이런 고민을 하는 것은 아닐 것 같은데, 왠지 저처럼 객체지향에 익숙하지만 시대 흐름에 맞춰 함수형을 시도하는 개발자가 점점 많아지면 언젠가 수렴하는 지점이 보일 것 같기도 합니다.

11
2
  • 댓글 35

  • fender
    24k
    2021-11-18 06:20:19 작성 2021-11-18 06:29:33 수정됨

    여담이지만 코틀린은 좀 더 써보니 조금씩 아쉬운 면도 보이더군요.

    패턴매칭이 약한 것, 셀프 타입이 없는 것, 여러 인터페이스를 트레잇 처럼 조합할 수는 있어도 같은 메서드를 중첩해서 사용할 수 없다는 점 등 스칼라에서 편리하게 쓰던 내용이 안 되서 불편한 점들이 있는 듯 합니다.

    그래도 파이썬을 하고 나니 대부분의 언어는 다 선녀로 보여서 큰 불만은 없긴 합니다.

  • 앙앙이
    4k
    2021-11-18 06:56:06

    먼저 밝힙니다. 저는 react 모릅니다. 사용한적도 없구요. 

    그래도 의문이 들어 적어 봅니다.


     react 사이트(https://reactjs.org/) 들어가 보면 아래와 같은 샘플이 모두 class 로 시작합니다.

    class Timer extends React.Component


    도대체 샘플이 React.Component 를 상속 받은 class 로 시작되는데

    " 리액트 자체가 함수형에 강하게 기울어져 있기 때문에 선듯 손이 가진 않는군요." 라고 말씀을 하시니

    쉽게 납득이 안가네요.

    -5
  • fender
    24k
    2021-11-18 07:21:21 작성 2021-11-18 09:26:20 수정됨

    앙앙이 // 우선 기본적인 내용부터 적고 시작하면, 리액트의 컴포넌트는 클래스와 함수 두 가지 형태로 작성할 수 있습니다. 그리고 아래 기술할 이유로 인해 리액트는 나중에 도입한 함수 컴포넌트에 강하게 무게를 두고 있습니다.

    1) 리액트의 핵심 개념 중 하나인 훅(hook)은 함수 컴포넌트에서만 동작합니다.

    2) 훅을 도입한 이유를 설명하는 문서를 보면 리액트 프로젝트의 방향성을 명확히 알 수 있습니다:

    Classes confuse both people and machines

    In addition to making code reuse and code organization more difficult, we’ve found that classes can be a large barrier to learning React... However, we found that class components can encourage unintentional patterns that make these optimizations fall back to a slower path. Classes present issues for today’s tools, too.

    3) "리액트"라는 이름에서 짐작할 수 있듯, 리액트 역시 다른 여러 현대적 프론트엔드 기술처럼 단방향 데이터 흐름을 강제하는 구조이고, 이는 기본적으로 어느정도 함수형 접근에 더 잘 들어맞는 방향입니다. (아마도 같은 페이지에서 언급한 "Conceptually, React components have always been closer to functions"의 의미와도 일맥상통할 것 같습니다.)

    4) 위와 같은 맥락에서, 리액트의 상태 관리에 널리 쓰이는 리덕스, 리코일 등의 라이브러리는 기본적으로 불변 상태를 받아 불변 상태를 반환하는 함수를 바탕으로 합니다.

    5) 인용하신 문서를 잘 읽어보시면 해당 부분은 함수 컴포넌트를 기본으로 설명하고 ES6 클래스로도 동일한 기능을 작성할 수 있음을 보여주는 내용입니다.

    6) 개인적으로 동의하지 않는 내용이고 오키에선 크게 체감하기 힘들 수 있지만, 요즘은 많은 기술들이 함수형으로 무게 중심을 옮겨감에 따라 객체지향이나 상속을 통한 폴리모피즘 자체를 구닥다리 개념으로 인식하는 편견이 있습니다. 그리고 이런 분위기는 리액트와 관련한 논의나 자료에서도 흔히 감지할 수 있습니다.

  • 앙앙이
    4k
    2021-11-18 08:34:58
      도입한 이유 저는 말도 안되는 주장이라 생각합니다.
    클래스에 반감 갖는 사람의 일반적 주장이라고 생각합니다.

    제 생각이 중요한것이 아니고
    함수혐 중심인  react 사이트  현재 개발중이거나 정식 오픈 되었다면 주소 공유 부탁드립니다.
    베타 사이트 혹은 정식 오픈된 함수형중심  react 사이트 있다면 함수형으로 넘어갔다는 강력한 증거이니깐요.
    -3
  • 하마
    7k
    2021-11-18 08:37:26 작성 2021-11-21 20:16:05 수정됨
    "구조는 객체지향으로, 구현은 함수형으로" 

    매우 공감합니다. 이게 (저 같이 평범한) 객체지향 습관이 몸에 벤 사람이 함수형을 이용하는 최선이지 않을까 싶네요. 

    일단 기본으로 아래와 같이 규정합니다.
    1. 인터페이스/클래스를 베이스로  뼈대를 잡고, 프로퍼티,함수등을 분류 해 놓는다.
    2. 최대한 모든것을 읽기전용으로 만들고, immutable 컬렉션과 value object, object.copy() 를 적극적으로 활용
    3. 람다식, 확장함수, runCatching, map, filter 같은 것을 최대한 활용 


    시나브로 아래와 같은 코틀린 코드가 나오는데, (자사 제품에서 일부 발췌)
    보편적으로 자바로 짰을 때와 비교하면 아래와 같은 변화가 생기는거 같습니다.

    - 라인수는 굉장히 많이 줄어들며, 함수도 굉장히 많이 줄어 든다. 한눈에 더 많은 로직이 보인다. 
    - 근데 시나브로 함수 하나에 너무 많은 일을 하고 있게 될 수 있다. 그래서 저런 표현이 익숙해지기 전까지는 읽는 사람들은 러닝커브가 좀 걸린다. 

    
      override fun execute(executor: Executor, context: ExecutionContext): ExecutionResult {
        logger.debug("Name: {}, Columns: {}, Context: {}", name, columns, context)
        require(canExecute(context))
        val keyColumn = columns.single { it.isKey }
       
        val table = executor.tableStore.create(context.evaluate(name), keyColumn.toDataTableColumn())
        columns.filter { context.evaluate(it.name) != keyColumn.name }
          .map { ledgermaster.DataTableColumn(context.evaluate(it.name), context.evaluate(it.type).toDataTableColumnType()) }
          .forEach { table.addColumn(it) }
    
        val uniques = columns
          .filter { it.unique }
          .mapIndexed { i, column -> AddConstraint(name + "_" + column.name + "_unique", name, "classpath:///ledgermaster/ethereum/UniqueConstraint.json", listOf(Arg("int", i.toString()))) }
          .map { addConstraint -> addConstraint.execute(executor, context) }
          .takeIf { it.isNotEmpty() }
          ?.fold(emptyList<Variable>()) { acc, m -> acc + m.changes }
          ?: emptyList()
    
        val constraintVariables = constraints.map { constraint -> AddConstraint(constraint.name, name, constraint.byteCode) }
          .map { addConstraint -> addConstraint.execute(executor, context) }
          .takeIf { it.isNotEmpty() }
          ?.fold(emptyList<Variable>()) { acc, m -> acc + m.changes }
          ?: emptyList()
    
        val tableVariables = listOf(Variable(context.evaluate(name), table.address))
    
        return ExecutionResult(uniques + constraintVariables + tableVariables)
      }


  • fender
    24k
    2021-11-18 08:38:44

    앙앙이 // 스스로 리액트를 모르고 써본 적이 없다고 하셨다면 주장 이전에 공부가 우선일 것 같습니다.

    리액트에서 훅이라는 개념이 얼마나 유용한지, 앞으로 비중이 늘어날지 줄어들지 같은 문제가 궁금하시면 저에게 '증거'를 내놓으라고 하실 것이 아니라 공식 문서를 읽어보시거나 예제 프로젝트라도 한 번 만들어 보시길 바랍니다.

  • fender
    24k
    2021-11-18 08:55:28 작성 2021-11-18 08:56:58 수정됨
    나중에 바쁘면 그냥 함수형으로 짜는 경우 다반사... ㅎㅎㅎ

    전 바쁠 때 아무 생각없이 함수형으로 코드를 짤 수준이 되면 좋겠습니다. 함수형부터 배운 개발자는 객체지향보다 함수형으로 더 빠르게 코딩이 가능한지 모르겠지만 말입니다.

  • 앙앙이
    4k
    2021-11-18 08:59:53

    없으면 없다 하시면 됩니다.

    남보고 공부하라기전에  카더라통신과 차이점 좀 벌리세요.

    -11
  • neverlish
    71
    2021-11-18 09:21:28 작성 2021-11-18 09:27:08 수정됨

    앙앙이 // 


    위 댓글에서 궁금해하신 `함수혐 중심인  react 사이트  현재 개발중이거나 정식 오픈 되었다면 주소 공유 부탁드립니다.` 에 대해 나름대로의 지식을 담아 공유 드립니다.


    1.

    현재 react에서 제공하는 공식문서에서, hook 에 대한 설명을 볼 수 있습니다.

    - https://ko.reactjs.org/docs/hooks-intro.html : hook의 개요. 위에 fender님이 인용한 `훅을 도입한 이유를 설명하는 문서를 보면 리액트 프로젝트의 방향성을 명확히 알 수 있습니다` 에 대한 자세한 설명을 한글로 읽을 수 있습니다.

    - https://ko.reactjs.org/docs/hooks-faq.html hook에 대한 faq. 기존에 제공되던 class 기반의 기능들을 deprecate 시키지는 않을 예정이지만, 애플리케이션 내에서 새로 작성되는 코드들은 hook을 사용하길 권장하고 있습니다.


    2. 

    https://beta.reactjs.org/

    - 리액트에서 재작성중인 공식문서를 볼 수 있는 페이지입니다. 대부분의 예시코드가 클래스가 아닌 함수형 으로 작성되었습니다

    - 위 주소의 유효성에 https://twitter.com/dan_abramov/status/1451349199082213378 에서 찾을 수 있습니다. dan_abramov는 redux 를 만들었고, 현재는 facebook에서 react 팀에 재직중인 것으로 알려져 있습니다.

  • 김카프
    185
    2021-11-18 09:37:37 작성 2021-11-18 09:40:39 수정됨

    그냥 몇가지 생각 덧붙여보자면

    1.

    하스켈에서 유래한 함수형 프로그래밍이 너무 유명한 나머지 보통 함수형 프로그래밍이라 하면 그쪽 계통을 떠올리기 쉬운데, 사실 ML계통 언어 디자인이 본문에서 이야기하는 프로그래밍 방식과 유사합니다. 모듈이 객체지향의 싱글톤처럼 동작하고 펑터는 모듈을 인자로 받는 모듈이죠. OCaml같은 경우 include 키워드 등을 통해서 한 모듈에 다른 모듈을 포함하는 등 유연하게 디자인이 가능합니다. 많이 안 쓰이다보니 모르는 분들이 많죠. 이쪽 계통 언어 중에서는 ReScript가 접근성이 괜찮습니다.

    2.

    반론도 있겠지만, Structural typing이 함수형에서 폴리모피즘에 대응하신다고 봐도 됩니다. OCaml에서 Row Polymorphism이란 이름으로 객체 지향을 도입하면서 함수형 언어 중에서는 처음 도입했던 걸로 압니다. 사실 얘기하자면 비슷한 거 더 얘기할 수도 있지만 너무 저쪽 세계 얘기라...

  • 심심한사부
    1k
    2021-11-18 09:46:02

    양쪽다 완전한 상황이 아니기 때문에

    상황에 따라 골라쓰는게 중요한듯...



  • fender
    24k
    2021-11-18 09:47:37 작성 2021-11-18 09:53:30 수정됨

    김카프 // 구조적 타이핑을 함수형과 연관시켜서 생각해본 적은 없었는데, 어쩌면 말씀하신대로 제가 ML이나 OCaml을 포함한 여러 함수형 언어를 접한 경험이 없어서 그런지 모르겠습니다.

    반면 함수형과 관련해서 전통적인 자바 같은 객체지향 언어와 다른 형태의 라면 전 암묵변환을 통한(ad hoc) 폴리모피즘 정도가 먼저 떠오릅니다. 스칼라를 쓰면서부터 함수형에 본격적으로 입문해서 그런지 몰라도 코틀린 같은 언어에서 그런 개념을 지원하지 않는 것은 아쉬울 때가 많더군요.

  • 김카프
    185
    2021-11-18 09:53:44 작성 2021-11-18 09:54:09 수정됨

    fender 사실 함수형 프로그래밍을 얘기하기에 앞서서 함수형 프로그래밍에 대한 정의가 선행돼야한다고 생각하는데요, 역사가 길어지다보니 이론이 발전하면서 그냥 "함수형"이라고 하기엔 너무 종류가 많아져서...

    댓글에서 말씀하시는 프로그래밍은 제 관점에서는 조금 하스켈쪽이 아닌가 싶고요, 요즘 대부분 언어들은 OCaml 스타일 정도는 다들 지원하니 그냥 시야를 좀 넓게 잡으셔도 될 거 같습니다.

    누가 저한테 함수형 프로그래밍이 뭐냐고 물어보면 전 그냥 함수가 1급 시민인 언어라고 하겠는데, 이론적으로 제가 이걸 설명하더라도 이럼 C++도 함수형 언어가 되니 전 화형당하겠죠(...)

  • fender
    24k
    2021-11-18 09:56:29 작성 2021-11-18 10:00:00 수정됨

    김카프 // 

     요즘 대부분 언어들은 OCaml 스타일 정도는 다들 지원하니 그냥 시야를 좀 넓게 잡으셔도 될 거 같습니다.

    항상 그러려고 의도하긴 하는데 쉽지가 않네요, 코틀린 시작한지도 얼마 안 되서요 ㅎㅎ; 이 동네는 뭔가 알 만 하면 모르는 것이 끝도 없이 나오는 것 같습니다.

  • 김카프
    185
    2021-11-18 10:03:35

    fender // 제가 키배에서 한 번 지고 좀 쉬엄쉬엄하면서 3년인가 기반지식 없이 이론 공부를 했는데요, 지금 아시는 수준에서 좀 더 하시면 arxiv에서 아티클을 찾으셔야 하지 않을지...

    전 이것만 너무 했더니 정작 지난 3년간 엔지니어링 분야 발전을 거의 못 따라잡아서 걱정이네요...

  • 김카프
    185
    2021-11-18 10:06:23

    걱정하시는 부분에 대해서는 ReScript를 해보시길 추천드리는데요, 누가 뭐래도 너무 자명한 함수형 언어면서 생각하시는 대로 프로그래밍이 가능하니 아마 즐겁게 프로그래밍하실 수 있지 않을까 합니다.

  • fender
    24k
    2021-11-18 10:12:06 작성 2021-11-18 10:12:43 수정됨

    김카프 // 추천 감사합니다. 지금은 여차하면 버리고 타입스크립트로 갈 생각으로 코틀린으로 프론트까지 구현해보고 있는데, 그런 일이 생기면 ReScript도 진지하게 선택지에 넣고 고민해보겠습니다.

    사실 트랜스파일러 기반 프론트 기술들은 언어 자체 특성 보다는 기존 유명 라이브러리 래퍼 존재 여부나 연동을 얼마나 잘 지원하는지가 더 큰 고민인 것 같습니다. ReScript는 첫 머리 설명부터 비슷한 내용을 강조하는 것을 보니 그런 면에서도 기대가 되네요.

  • fender
    24k
    2021-11-18 10:17:07

    근데 새벽에 코딩하다 막혀서 푸념삼아 쓴 글인데 제목이 너무 거창(?)해서인지 20플이 달리는군요;

  • 하마
    7k
    2021-11-18 10:37:01

    fender //

    여유되실 때 따로 글을 파셔서 "스칼라에 비해 코틀린이 아쉬운점" 이라는 제목으로 글을 올려주시면 많은 것을 배울 수 있을 거 같습니다. 아마 거기에 "자바" 도 포함된 글이라면 우리 커뮤니티의 많은 개발자들이 큰 흥미를 가질 수 있지 않을까 싶구요. 

  • fender
    24k
    2021-11-18 10:47:57 작성 2021-11-18 10:49:27 수정됨

    하마 // 아마 코틀린은 저보다 오래 쓰셨을 것 같은데, 전 아직 그런 글을 쓰기에는 해당 언어를 제대로 접해봤다고 생각하진 않습니다 ㅎㅎ;

    나중에, 예컨대 위임 같은 코틀린의 특장점 같은 것도 "이런 것이 있구나"를 넘어서 설계에 자유자재로 쓸 수 있게 되면 좀 더 긍정적으로 고민해볼 것 같습니다.

    다만 간결한 for-comprehension이나 강력한 패턴 매칭, 부분 함수를 Arrows 같은 걸 동원하지 않고도 부분 함수를 간결하게 표현할 수 있는 점, 트레잇(인터페이스)을 믹스인 할 대상 유형을 강제할 수 있는 점 등 스칼라에는 있지만 코틀린에 없어 아쉬운 기능들은 당장 쓰면서 어쩔 수 없이 눈에 밟히는 것 같습니다.

  • kingofkj
    1k
    2021-11-18 12:35:40

    오랜만에 옼히 들어왔는데 펜더님은 여전하군요

    오늘따라 기분이 안좋으신가. ㅎ

    -4
  • 앙앙이
    4k
    2021-11-18 12:38:21

    // nerverlish

    친절한 답변 감사합니다.

    차기  버전은 함수형 확정이군요.



    -3
  • fender
    24k
    2021-11-18 12:38:28

    kingofkj // 아무리 봐도 여기서 예의 없거나 크게 시비 거는 덧글을 쓴 적이 없는 것 같은데, 무슨 말씀을 하시는지 모르겠습니다. 기분 안좋은 일이 있으신가요?

  • neatCat911
    120
    2021-11-19 14:04:23

    fender
    응원하는 사람이 더 많다는것만 알아주세요~ 화이팅 ^^

  • 비둘기야밥먹장
    246
    2021-11-19 14:35:58

    글도 제대로 못읽고 이상한 소리 하는 사람도 많은데

    항상 좋은글 올려주셔서 잘 읽고 있습니다~

  • 레옹개발
    292
    2021-11-19 22:27:56


    리액트 조금만 구글링 해도 외국에선 클래스 < 함수형 더 많다는 것을 알게 될텐데

    공식 문서만 봐도 훅을 권장하는 문장이 많더라구요

    장기적으로 우리는 Hook이 사람들이 React 컴포넌트를 작성하는 주요 방법이 될 것으로 기대합니다.


  • fender
    24k
    2021-11-20 03:57:55 작성 2021-11-20 04:07:32 수정됨

    일단 아래와 같은 인터페이스 기반으로 믹스인을 통해 컴포넌트를 조합하는 방식으로 동작하게 만들긴 했습니다:

    sealed interface Renderer {

    val prefix: String

    fun supports(item: DesignItem): Boolean

    val component: ComponentType<ItemProps>

    val controls: ComponentType<ItemProps>

    fun transform(props: ItemProps): List<String> = listOf()

    fun refs(props: ItemProps): Array<(Element?) -> Unit> =
    arrayOf(useHoverBehavior(props))

    val renderContent: RBuilder.(ItemProps, ref: Ref<*>) -> Unit

    val renderControls: RBuilder.(ItemProps) -> Unit

    val renderComponent: RBuilder.(ItemProps) -> Unit
    get() = { props ->
    val refs = refs(props)

    val ref = useCallback(*refs) { node: SVGGraphicsElement? ->
    refs.forEach { it(node) }
    }.unsafeCast<Ref<*>>()

    g {
    attrs {
    className = if (props.selected == true) "selected" else ""
    transform = transform(props).joinToString(" ")
    }

    renderContent(props, ref)
    }
    }
    }

    abstract class AbstractRenderer : Renderer {

    override val component: ComponentType<ItemProps> = fc(renderComponent).also {
    it.displayName = prefix
    }

    override val controls: ComponentType<ItemProps> = fc(renderControls).also {
    it.displayName = "${prefix}Controls"
    }
    }

    근데 아무리 봐도 뭔가 프랑켄슈타인스럽고, 훅만 아니었으면 클래스 구조로 풀었으면 훨씬 깔끔했겠다는 생각을 지울 수가 없네요.

    액션 관련해서 시도했던 내용은 제가 봐도 함수형과 객체지향이 나쁘지 않게 조합된 것 같은데, 이 부분은 뭔가 억지로 이어 붙인 것 같다는 생각이 강하게 듭니다.

    생성자에서 속성 참조해서 경고나는 것부터 그렇고 (함수로 대체하면 컴포넌트가 스테이블 하지 않아서 불필요한 리렌더링을 초래합니다), 대체로 리액트 고계 컴포넌트 개념을 억지로 클래스로 구현한 느낌입니다.

    개인적으로 리액트 문서에 나오는 클래스 구조의 단점에 대한 부분은 절반은 이해를 하지만 어느 정도는 편향된 시각도 감지할 수 있는데, 훅 때문에 어느 한 쪽 접근을 지양하게 된다면 저에겐 상당히 불편한 제약으로 다가옵니다.

  • ISA
    5k
    2021-11-20 19:04:02
    글과 댓글을 쭈욱 읽어보고나니 제가 보기에는 함수형에 접근하는 방법부터 조금 다른거 같아 보이는데 이게 객체지향에 덜 익숙해서 그래보이는건지 의문이긴합니다.
    무엇보다 리액트의 경우  훅이 생기고 객체지향이 제한된다기 보다는 훅이 클래스 스타일 에서 지원 해주던 것들을 함수 스타일에 지원해주는걸로 알고 있어요.
    즉, 기존 클래스 컴포넌트의 무거운걸 덜어내고 유용한 기능을 hook으로 쓴다에 가깝습니다.
    리렌더링 관해서는 경우에 따라 다르겠지만
    보통 클래스 스타일 컴포넌트가 함수 스타일보다 성능이 떨어져서 리렌더링을 감안해도 함수 스타일이 유리하다는 자료를 본 적 있긴합니다...
  • fender
    24k
    2021-11-20 19:26:10 작성 2021-11-20 19:28:58 수정됨

    ISA // 말씀하신대로 저도 훅은 클래스 없이 재사용을 쉽게하기 위한 용도라고 이해하고 있습니다. 문제는 제 경우엔 컴포넌트로 다루고자 하는 모델이 명백한 객체지향적 계층 구조를 가지고 있다는 점인데, 이를 기능으로 분리해서 훅으로 재조합을 시도하니 어떻게 해도 코드 중복을 피할 수 없더군요.

    예를들어, 계층 중에 'Movable'에 해당하는 모델은 드래그 이동이 가능해야하고, 'Resizable'에 해당하는 경우 크기 조절을 위한 핸들이 표시되어야 하는 식의 트레잇과 기능의 조합으로 구성된 요구 조건이 있는데, 말단 모델은 이러한 트레잇을 임의로 부분적으로 구현을 할 수 있습니다 (예를들어 Movable인 동시에 Resizable이거나, Resizable이지만 Movable이 아니라던가 등등...). 그리고 그런 트레잇은 대략 4-5 가지 정도 종류가 되는 것 같습니다.

    처음에는 드래그 동작 등을 커스텀 훅으로 뽑아서 말단 컴포넌트 마다 수작업으로 "useMoveBehavior()" 하는 식으로 추가했는데, 이건 아무리 생각해도 마치 객체지향에서 클래스로 설계 할 것을 조건문에 분기를 잔뜩 달아 처리하는 식의 안티 패턴으로 보였습니다.

    결정적인 문제는 말단 모델마다 연관된 컴포넌트가 한 쌍이 나온다는 것인데, (하나는 HTML, 다른 하나는 SVG) 제가 리액트를 많이 안써봐서 그런지 어떻게 해도 깔끔하게 코드 중복을 최소화 하면서 이를 처리할 방법이 떠오르지 않았습니다.

    그래서 그냥 모델의 계층 구조를 미러링 하는 렌더러 클래스 구조를 만들고 렌더러에서 이 두 가지 리액트 컴포넌트를 생성하는 접근을 시도한 것이 위의 모습입니다.

    동작은 대충 하는데 이래저러 모양은 마음에 들지 않아 고민 중에 있습니다. 이런 방식이 함수형 접근이 아니지만 좋은 객체지향 설계도 아니라고 생각합니다.

    한 편, 함수와 리렌더를 이야기한 것은 함수형 컴포넌트 이야기가 아니라 방금 언급한 접근 방법의 구현상 제약에 대한 내용이 었습니다.

    위 덧글의 내용은 훅의 기능 자체가 객체지향을 방해한다기 보다는, 위에서 설명한대로 같은 재사용이라도 클래스로 접근하는 경우가 더 잘 맞는 경우가 있는데 리액트의 발전 방향이 훅/함수형을 중심으로 갈 경우 클래스를 쓰기가 꺼려진다는 정도로 이해해주시면 될 것 같습니다.

  • 꿈의연봉1800
    349
    2021-11-24 13:59:12 작성 2021-11-24 14:40:06 수정됨

    리액트 컴포넌트의 정의를 함수로 하냐 클래스로 하냐는 OOP FP와는 전혀 관련이 없어요

    그냥 표기의 문제입니다 차라리 effect와 그 외의 것들 아니면 redux 미들웨어에서 사이드이펙트 제어를 얘기하면 그나마 FP와 그렇지 않은 부분을 분리해서 얘기라도 할 수 있지 컴포넌트 표기 방식이나 hook에 대해 이야기하는건 프로그래밍 패러다임이랑 전혀 별개죠

    애초에 글에서 얘기하고 싶던것도 표기에 대한 것 보다는 여기에 어떻게 다형성을 예쁘게 먹이는지에 대한 것 같은데 댓글로 자꾸 이상한 주제 들고오시는 분들이 보여서 안타깝네요

    OOP, FP에 대한 글이라기 보단 코드 중복과 다형성에 대한게 아닐지 싶습니다

    언급했듯 클래스 컴포넌트 함수 컴포넌트 비교는 의미가 없구요

  • 꿈의연봉1800
    349
    2021-11-24 14:10:54 작성 2021-11-24 14:41:33 수정됨

    기존에 OO로 짜던 습관이 있으면(보통 자바 C# 개발자겠죠) 다형성으로 제어 역전 걸면서 코드 구조를 잡는 습관이 있을텐데 리액트 컴포넌트는 그런 구조와는 거리가 있으니까 기존의 방식대로 하려면 무언가 계속 어긋날 수 밖에 없어요

    상태나 effect를 컴포넌트랑 분리하면 (연결을 리덕스로 하건 훅으로 붙이건) 컴포넌트 외적인건 어떤 설계라도 적용할 수 있는데(MV*분리 후 모델 정의와 비슷) 정작 컴포넌트는 리액트에서 OOP 방식의 다형성을 쓰긴 힘들죠 props를 가능한 얕게 가져가면서 컴포넌트를 투명하게 관리해야 하는데 거기다가 은폐를 걸어버리기에는 좀 그러니까요

  • 꿈의연봉1800
    349
    2021-11-24 14:15:52 작성 2021-11-24 14:38:40 수정됨
    리액트는 props 타입으로 분기해서 다형성 비슷한걸 하고 (ML계열 매칭이랑 비슷)
    그나마 이것도 테스트하기 번거로워서 페이지나 컨테이너 단위로 범위를 제한하구요
  • 꿈의연봉1800
    349
    2021-11-24 14:27:14 작성 2021-11-24 14:35:55 수정됨

    위의 Movable 같은 케이스를 기존 OO방식으로 생각하면 useMoveBehavior의 인자로 Movable의 구현에 필요한 최소한의 인터페이스를 받고 컴포넌트에서 가져가 쓸 때 인터페이스에 대한 구현을 전달, hook 내부 구현 외의 중복은 helper 모듈로 관리하는 방법이 있겠고


    react 스타일은 그냥 래퍼 컴포넌트 만들고 거기에 movable구현한다음에 children으로 원래 컴포넌트를 전달해주는 것이겠죠

  • 매운만두맥주
    1k
    2021-11-24 21:17:03

    안녕하세요 fender님 본문과는 다소 벗어난 질문이지만 vue에 대해서는 어떻게 생각하시나요

    리액트 하고 싶었는데 회사 프로젝트 때문에 어쩔 수 없이 vue하고 있습니다.

    도태될까봐 걱정됩니다..

  • 로그인을 하시면 댓글을 등록할 수 있습니다.