알고리즘에서 에이전트까지: 클러스터링 연구가 자동화 로직을 형성하는 방식
Source: Dev.to

핵심 인사이트
- 연구가 사고를 형성한다 – 학문적 원칙이 자동화 문제에 접근하는 방식을 좌우한다.
- 노이즈 = 불안정 – 공간 노이즈를 필터링하는 동일한 사고 모델이 테스트 안정성에도 적용된다.
- 효율성은 중요 – 알고리즘적 사고가 대기 전략 및 요소 선택의 최적화를 이끈다.
- 패턴 인식 – “혼돈 속에서 질서를 찾는다”는 마인드셋이 자체 복구 프레임워크에 적용된다.
“이걸 클릭하고, 저걸 입력하고, 이것을 확인한다.”
이렇게 테스트 자동화를 생각한다면, 당신은 카드 탑을 쌓고 있는 겁니다.
대부분의 자동화 엔지니어는 동작에 집중합니다—무엇을 클릭하고, 무엇을 입력하고, 무엇을 검증할지. 자동화를 단순히 동작의 연속으로만 보면 UI가 하나의 클래스 이름만 바뀌어도 부서지는 깨지기 쉬운 스크립트가 됩니다.
저는 자동화를 스크립팅이라고 보지 않습니다. 데이터 문제로 바라봅니다.
왜냐고요? 제가 파이썬으로 자동화 프레임워크를 만들기 훨씬 전에, 공동 저자인 Hrishav와 저는 공간 데이터베이스에서 알고리즘 효율성을 연구하고 있었기 때문입니다. 2012년에 발표된 그 연구는 Selenium에 바로 복사‑붙여넣기 할 수 있는 구체적인 기술을 가르쳐 주지는 않았지만, 복잡한 데이터 문제를 어떻게 생각해야 하는지를 근본적으로 형성했습니다.
기반: TDCT 알고리즘
2012년, Hrishav와 저는 *“다각형 접근법을 이용한 대규모 공간 데이터에 대한 밀도 기반 클러스터링 기법”(TDCT)*이라는 논문을 공동 저술했습니다.
우리가 해결한 문제
거대한 혼돈 데이터셋에서 의미 있는 패턴(클러스터)을 노이즈에 압도되지 않고 어떻게 찾을 수 있을까?
기존 알고리즘인 DBSCAN은 좋았지만 다음과 같은 한계가 있었습니다:
- 임의 형태 – 실제 데이터는 깔끔한 원형이 아니다.
- 계산 비용 – 모든 점을 서로 비교하는 방식은 확장성이 떨어진다.
- 노이즈 민감도 – 이상치가 클러스터 경계를 왜곡한다.
우리의 해결책: 삼각형 밀도
DBSCAN이 원형 이웃을 사용하는 대신, 우리는 데이터를 삼각형 다각형으로 매핑했습니다. 이를 통해 다음을 가능하게 했습니다:
- 방사형 스캔보다 효율적으로 밀도를 계산.
- 임의의 비볼록 형태 클러스터를 탐지.
- 핵심 클러스터를 손상시키지 않고 노이즈 포인트를 격리.
핵심 인사이트
문제의 기하학을 (원 → 삼각형) 바꿈으로써 계산 복잡도를 낮추면서 클러스터 탐지 정확도를 향상시켰습니다. 이 협업 작업은 오늘날까지도 복잡한 데이터 문제에 접근하는 기반이 됩니다.
다리: 품질 엔지니어링에 왜 중요한가
“Dhiraj, 공간 클러스터링이 Selenium과 무슨 관계가 있나요?”
코드가 아니라 마인드셋입니다.
| 연구 마인드셋 | 자동화 적용 사례 |
|---|---|
| 노이즈가 실제 패턴을 가린다 | 불안정한 테스트가 실제 버그를 가린다 |
| 무차별 스캔은 확장되지 않는다 | 선형 폴링과 하드 슬립은 확장되지 않는다 |
| 효율성을 위한 기하학이 중요 | 프레임워크 구조가 회복력을 결정한다 |
| 안정적인 코어와 노이즈 구분 | 신뢰할 수 있는 요소 속성과 동적인 속성을 구분한다 |
문제 프레이밍에 관한 것
복잡한 자동화 과제에 직면하면 저는 즉시 “어떤 Selenium 명령이 필요하지?”라고 생각하지 않습니다. 대신 다음을 묻습니다:
- 여기서 데이터 구조는 무엇인가? (DOM은 트리, 테스트 결과는 시계열 데이터)
- 노이즈와 신호는 어디에 구분되는가? (어떤 요소 속성이 안정적인가? 어떤 실패가 진짜 버그인가?)
- 복잡성을 어떻게 줄일 수 있는가? (TDCT가 했던 것처럼 문제의 “기하학”을 최적화할 수 있는가?)
알고리즘 연구를 통해 길러진 이 사고 모델은 제가 내리는 모든 프레임워크 결정에 영향을 미칩니다.
마인드셋 적용: 실용 예시
예시 1: 다중 속성 요소 찾기와 폴백 로직
무차별 접근 (단일 실패 지점):
# ID가 바뀌면 모든 것이 깨진다
element = driver.find_element(By.ID, "checkout-btn-v3")
알고리즘적 접근 (신뢰도에 따라 여러 속성을 클러스터링):
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException
def find_element_with_fallback(driver, strategies: list[tuple]) -> WebElement:
"""
신뢰도 순으로 정렬된 여러 '데이터 포인트'(속성)를 분석한다.
클릭 가능해지는 첫 번째 요소를 반환한다.
"""
for strategy, locator in strategies:
try:
element = WebDriverWait(driver, 2).until(
EC.element_to_be_clickable((strategy, locator))
)
return element
except TimeoutException:
continue
raise NoSuchElementException("All strategies exhausted")
checkout_strategies = [
(By.CSS_SELECTOR, "[data-testid='checkout']"), # 가장 안정적인: 테스트 ID
(By.CSS_SELECTOR, "button[aria-label='Checkout']"), # 접근성 속성
(By.XPATH, "//button[contains(text(), 'Checkout')]"), # 텍스트 내용
(By.CSS_SELECTOR, ".cart-section button.primary"), # 구조적 폴백
]
checkout_btn = find_element_with_fallback(driver, checkout_strategies)
첫 번째 전략이 “밀도 코어” 역할을 한다. 실패하면 덜 안정적이지만 여전히 유효한 “이웃”으로 부드럽게 폴백한다.
예시 2: 자체 복구 요소 찾기
정적 접근 (깨지기 쉬운, 노이즈에 민감):
driver.find_element(By.ID, "submit-btn-v3") # ID가 바뀌면 깨진다
적응형 접근 (클러스터와 같은 회복력):
def self_heal_find(driver, primary_locator, fallback_locators):
"""
기본 로케이터를 시도하고 실패하면 속성 안정성과 알려진 앵커와의 유사성을 기반으로 폴백 로케이터를 평가한다.
"""
try:
return driver.find_element(*primary_locator)
except NoSuchElementException:
for loc in fallback_locators:
candidates = driver.find_elements(*loc)
if candidates:
# 간단한 휴리스틱: 가장 안정적인 속성을 가진 요소 선택
return max(candidates, key=lambda e: evaluate_stability(e))
raise NoSuchElementException("Element could not be healed")
def evaluate_stability(element):
# 실제 점수 함수의 자리표시자(예: data‑testid, ARIA 라벨, 안정적인 앵커와의 상대 위치 등)
score = 0
if element.get_attribute("data-testid"):
score += 3
if element.get_attribute("aria-label"):
score += 2
# 필요에 따라 더 많은 휴리스틱 추가
return score
primary = (By.ID, "submit-btn-v3")
fallbacks = [
(By.CSS_SELECTOR, "[data-testid='submit']"),
(By.XPATH, "//button[contains(text(),'Submit')]"),
(By.CSS_SELECTOR, "button.primary")
]
submit_btn = self_heal_find(driver, primary, fallbacks)
이 접근법이 TDCT를 문자 그대로 구현한 것은 아니지만, 사고 방식은 동일합니다: 여러 데이터 포인트를 평가하고 가장 신뢰할 수 있는 조합을 선택한다.
이 철학을 반영한 도구들
제가 Lumos ShadowDOM이나 Visual Guard 같은 패키지를 만들 때는 클러스터링 알고리즘을 의식적으로 구현한 것이 아닙니다. 그러나 설계 결정은 같은 원칙을 반영합니다:
- Shadow DOM을 효율적으로 탐색 → 무차별 탐색 전에 구조를 이해한다.
- SSIM을 이용한 비주얼 회귀 → 픽셀‑대‑픽셀 노이즈 대신 의미 있는 차이를 찾는 수학 모델을 사용한다.
- 프레임워크 내 자체 복구 → 요소 속성을 신뢰도에 따라 “데이터 포인트”로 취급한다.
연구는 복사‑붙여넣기 가능한 솔루션을 주지는 않지만, 자동화를 스크립팅이 아닌 데이터 문제로 보는 시각을 제공합니다.
결론: 자동화는 단순한 코드가 아니라 논리다
수년 전 발표된 TDCT 알고리즘이든, 오늘날 제가 구축하는 자동화 도구와 라이브러리이든 목표는 동일합니다:
혼돈에 질서를 부여한다.
DOM은 혼돈이다. 연구‑주도 마인드셋으로 접근한 테스트 자동화는 구조를 만들고, 불안정을 줄이며, 우아하게 확장될 수 있습니다.