흔한생각 (recording)/Dynamo

다이나모에서 딕셔너리 활용하여 코드 리팩토링 하기

hnanmal 2022. 11. 11. 17:04
300x250

도입: 비주얼 스크립팅의 장점과 한계

다이나모는 작성하기 직관적이고 쉬운 대신에, 목적을 자세히 구현할 수록 코드의 복잡도가 순식간에 증가한다는 단점이 있습니다.

딕셔너리란?

 

“Dictionary” 라는 영단어는 “사전” 이라는 한국어 단어에 대응하는 단어입니다. 이렇게 짝을 지어 대응시킨 정보의 형태를 Dictionary 자료형이라고 하고, 그림처럼 중괄호 안 쪽에 콜론으로 대응시킨 데이터 쌍의 형태로 이루어집니다.

이런 대응되는 정보라는 특징을 이용하면, 하나의 꾸러미로 함께 돌아다니는 데이터를 만들 수 있습니다.

 

저를 규정하는 정보를 한번 나열해 봤습니다. 아까 dictionary에서 보던 자료의 형태와 굉장히 유사하죠? 굉장히 직관적인 형태의 데이터 이기도 합니다.

 

이렇게 중괄호만 양쪽 끝에 붙여주게 되면, 바로 Dictionary의 형식으로 변환됩니다.

 

컴퓨터가 이해하기 쉽도록 한 줄로 쭉 늘여 쓰면 이런 형태가 됩니다.

 

딕셔너리를 이용해서 다수의 정보를 모아두고, 필요한 것만 조회하는 개념을 설명한 그림입니다.

다수의 딕셔너리에도 한꺼번에 이런 질의를 할 수 있겠죠?

 

이러한 딕셔너리는 다이나모에서 크게 두 가지 방향으로 활용할 수 있습니다.

 

1번의 내용은 다이나모에서 구현하는 것이 굉장히 비효율적이지만 가능은 하다는 것에 의의가 있습니다. 저기에 대한 내용은 다음에 포스팅 하도록 하고,

이번 포스트에서는 Data Object로서의 사용이라는 측면에 집중해보도록 하겠습니다.

 

 

스파게티가 되어버린 코드를 아시오

방심하면 이렇게 돼 버린다니까요, 글쎄?

 

흔하게(?) 볼 수 있는 다이나모 코드입니다. 시작은 간단한 코드로 시작하더라도, 프로그램의 작용 범위를 조금씩 늘리고 수정하다 보면, 어느 새 코드 뭉치들이 산더미처럼 불어나서 서로 꼬이고 섞이고 난리를 치기 일쑤입니다.

 

 

쉽게 지저분해지는 이유, 그리고 해결책

 

이렇게 되어버리는 이유는 무엇일까요? 비주얼 스크립팅의 태생적인 한계에서 비롯된 문제입니다.

텍스트 기반 코딩의 경우에는 한 코드에서 생성된 데이터를 전달할 때, 변수 이름을 선언하여 이 이름을 가지고 코드끼리 참조하는 관계성을 바로 만들어 낼 수 있습니다.

하지만 다이나모에서는 한 노드에서 다른 노드로 데이터를 전송하려면 무조건 연결선을 만들어 줄 수 밖에 없는 데다가, 화면에서 보이는 시야 범위 밖에 있는 노드에서 데이터를 가져오려면 휠 버튼을 끊임없이 누르며 화면을 패닝한 뒤에 간신히 멀찍이 떨어진 두 노드를 연결해야 하는 경우가 부지기수 입니다.

 

이런 상황을 조금 정돈하고, 눈에 잘 띄며 복잡성이 덜한 코드로 만들기 위해, 딕셔너리가 유용하게 쓰일 수 있습니다.

 

 

그래서 딕셔너리로 뭘 어떻게 하면 될까?

딕셔너리 노드 기본

 

key 와 value를 짝 지어준다는 개념 아직 잊어버리지 않으셨죠? 실제로 다이나모에서 노드를 사용해 딕셔너리를 만들어주는 방법은 위 그림과 같습니다.

keys 노드와 values 노드에는 단일 데이터 뿐만 아니라, 복수의 데이터로 구성된 리스트를 입력할 수도 있으며, 딕셔너리의 values가 될 수 있는 값은 다른 딕셔너리도 가능합니다.

 

이미 만들어진 딕셔너리에서 key를 빼고 더하는 방법은 위와 같습니다.

오늘 샘플로 보여드릴 코드에서는 우하단의 Dictionary.SetValueAtKeys노드가 핵심 역할을 합니다.

 

 

Dictionary를 해결책으로 쓰는 이유가 뭘까?

 

 

딕셔너리와 리스트의 차이는 무엇일까요? 바로 키가 암시적인지, 명시적인지에 대한 차이가 있습니다. 리스트는 키가 없는데 무슨 말이냐고요?

사실은 리스트의 각 원소에 대응되는 인덱스가 키와 유사한 개념이라고 볼 수 있습니다.

다만 데이터의 순서만 나타내기 때문에 그 이상의 정보를 줄 수 없다는 것이 딕셔너리와는 조금 다른 점이죠.

 

이에 반해 딕셔너리는, key의 이름을 정하는 방식을 미리 사전에 잘 정의해 놓기만 한다면, 매칭된 데이터에 대한 설명을 제공하는 수단이 되기도 합니다.

 

 

샘플 코드

샘플로 작성한 프로그램, 엉망이 된 코드를 한번 리팩토링 해보도록 하겠습니다.

 

이 코드는 레빗 기본 샘플 프로젝트에서 콘크리트 벽체의 거푸집과, 강관 파이프를 자동으로 모델링 해주는 코드입니다. 하지만 이렇게 복잡하고 지저분하면, 기능 추가와 버그 수정 등의 유지 보수를 해야 하는 상황에서 한숨만 나오겠죠?

 

<클릭해서 크게 보세요>

아까의 복잡한 코드를 딕셔너리를 활용한 구조로 리팩토링하면 위와 같이 아주 아주 심플한 흐름의 코드가 됩니다. 너무 길어서 개별 노드의 이름은 보이지 않지만 흐름은 아주 명확하게 하나의 흐름으로 이어지는 코드라는 것이 보이죠?

조금 확대해서 보겠습니다.

 

코드의 초반부에서는 Wall 객체들을 가져와서, 빈 딕셔너리에 “elem”이라는 key와 함께 value 로서 Wall 객체들 각각을 대응시켜, 나만의 규칙으로 커스터마이징 된 새로운 데이터 오브젝트를 만들어내고 있습니다. 맨 우측 노드의 데이터를 살펴보면 하얀색 박스에 들어있는 것이 “elem”이라는 key이고, 그 우측에 배치된 Wall은 레빗 벽체 객체임을 알 수 있습니다.

 

그 다음에는, 각 벽체의 객체들을 딕셔너리에서 다시 꺼내서, 면적 값을 조회하고(필요한 작업을 하고), 그 값을 각 딕셔너리에 “area”라는 key와 함께 다시 저장하는 모습을 볼 수 있습니다.

이제 제가 코드를 정리하는 패턴을 눈치채셨나요?

화면에 보이는 영역 안에서 모든 작업을 끝내기 위해서 데이터의 보따리 역할을 하는 딕셔너리를 계속 가지고 다니면서,

필요한 데이터를 “다시 꺼내고” →

데이터를 활용해 “필요한 작업을 한 뒤” →

결과값을 “key와 함께 다시 딕셔너리에 저장”

하는 흐름으로 계속 반복하며 코드를 정리하는 패턴입니다.

이렇게 반복하다 보면, 아까처럼 길이는 길지만 아주 단순한 한 줄 짜리 흐름의 프로그램으로 리팩토링 되는 것이죠!

그림에서 우하단에 보이는 노드의 결과는 “elem” 과 “area” 두 가지의 key가 들어있는 딕셔너리들(각 벽체 별)이 집합해 있는 리스트 인 것을 확인할 수 있습니다.

그런데, “저렇게 길어서 어떻게 하냐, 처음 부터 끝까지 훑어보려면 저것도 마우스 부지런히 놀려야 하는데 불편하지 않겠냐.” 라는 의견이 있을 수 있습니다.

그 점을 해소하기 위해서, 딕셔너리 기반의 리팩토링 된 코드는 접는 기능이 추가되어 있습니다.

 

바로 이렇게 말이죠.

길게 늘어진 코드를 차곡차곡 접어서 배치하면, 기존 처럼 캔버스의 공간에 노드들이 효율적으로 배치되면서도, 파악하기 쉬운 흐름은 그대로 유지하는 코드로 재탄생 됩니다.

 

[ 필요한 데이터를 “다시 꺼내고” → 데이터를 활용해 “필요한 작업을 한 뒤” → 결과값을 “key와 함께 다시 딕셔너리에 저장” 하는 흐름 ] 이 계속 반복되면서 프로그램을 형성해나가는 모습이 보이시죠?

 

 

결론

최종적으로 내용을 다시 정리하면 이렇습니다.

 

위 그림에서 보는 것처럼 딕셔너리를 꾸려가면서 코드를 진행하는 것이, 전체적인 코드의 흐름을 산개 시키지 않고, 일관적인 하나의 흐름으로 유지해 나갈 수 있다는 점에서 큰 장점이 있습니다.

기본 노드로 구현하려면 왼쪽과 같이 짜면 됩니다.

만약 동일한 내용을 하나의 노드로 축약해서 편하게 관리하려면 우측처럼 파이썬 스크립트 노드로 구현하면 됩니다.

 

파이썬 코드 스크립트는 이렇게 짜면 됩니다. 기본 노드와 완전히 동일한 내용입니다.

자, 이제 초록색의 딕셔너리 관리 노드를 이용해서 하나의 코드 유닛을 만들 수 있습니다.

 

붉은색의 1점 쇄선으로 둘러싸인 영역이 하나의 코드 유닛인데, 이 코드 유닛 안쪽의 논리 흐름은 사용자가 목표하는 신규 파생 데이터 연산을 한 후, 결과물을 딕셔너리에 돌려주는 흐름이라는 것을 명확하게 볼 수 있습니다.

 

코드 유닛의 내부는 다음과 같이 ㄱ, ㄴ, ㄷ 세 개의 부분으로 구성되어있습니다. ㄱ과 ㄷ은 변하지 않고(딕셔너리에 추가할 key 이름만 계속 바뀝니다), ㄴ 만 계속 알고리즘이 교체되면서 코드가 진행되는 것이죠.

 

리팩토링된 코드를 잘 보면, 그림처럼 10개의 코드 유닛의 연쇄로 이루어진다는 것을 볼 수 있습니다!

그리고 개별 벽체에서 파생된 데이터들을 각각 딕셔너리로 분리해 관리하기 때문에, 벽체 별로 각각 거푸집 및 강관 파이프만 형상화하는 코드로 바꾸는 것도 아주 용이합니다. 쉽게 말해 프로그램의 기능 추가를 위한 코드 수정이 꽤 편리해 지는 것이죠.

 

코드의 복잡도를 관리하는 것은 코드의 유지 보수, 개선을 위해서는 반드시 필요한 일이란 것이라는 말씀을 드리고 싶었습니다! 그 수단으로 딕셔너리가 유용하다는 것도 꼭 기억하시면 좋겠습니다.

반응형