Vue.js & Pinia 기반 Kafka Kopanda Frontend 흔들림 없는 서비스개발 하기

궁금하면 500원·2024년 6월 7일
0

Kafka Kopanda Frontend: 안정성과 사용자 경험을 위한 여정

🚀 Kafka Kopanda Frontend, 무엇이 문제였을까?

Kafka 클러스터 모니터링을 위한 프런트엔드 애플리케이션인 Kafka Kopanda를 개발하며, 사용자 경험과 시스템 안정성을 저해하는 몇 가지 문제에 직면했습니다. 초기 개발 단계에서는 발견하지 못했던 이 문제들은 실제 사용 환경에서 예측 불가능한 오류와 불편함을 야기했죠.

주요 문제점은 다음과 같았습니다:

🚨 1. Vue 컴포넌트 초기화의 덫: ReferenceError 발생

ConnectionForm.vue 컴포넌트에서 폼 데이터를 초기화하는 resetForm 함수가 정의되기 전에 호출되는 JavaScript 호이스팅(Hoisting) 문제가 발생했습니다. 이는 예측 불가능한 런타임 오류로 이어져 사용자에게 혼란을 주었습니다.

에러 메시지:

Uncaught (in promise) ReferenceError: Cannot access 'resetForm' before initialization
    at watch.immediate (ConnectionForm.vue:144:5)

🚨 2. 라우팅 시스템의 오작동: 잘못된 Pinia Store 사용

애플리케이션의 핵심 기능 중 하나인 라우팅 시스템에서도 문제가 발견되었습니다. 특정 페이지 접근 시 연결 상태를 확인하기 위해 라우터 가드(Router Guard) 내에서 Pinia Store(useConnectionStore())를 직접 사용하려 했으나, 이는 Vue Router와 Pinia의 초기화 시점 차이로 인해 올바르게 동작하지 않았습니다. 결과적으로 사용자가 페이지 이동 시 불필요하게 차단되는 현상이 발생했습니다.

🛠️ 문제 해결을 위한 여정: 코드 개선 과정

발견된 문제점들을 해결하고 Kafka Kopanda Frontend의 안정성을 높이기 위해 다음과 같은 개선 작업을 진행했습니다.


1. ConnectionForm.vue: 호이스팅 문제 해결

resetForm 함수가 watch 구문보다 먼저 정의되도록 코드 순서를 변경하여 호이스팅 문제를 근본적으로 해결했습니다.

💡 Before (문제 코드):

// watch 구문들...
watch(() => props.connection, (connection) => {
  // ...
  else {
    resetForm() // ❌ 함수가 정의되기 전에 호출
  }
}, { immediate: true })

const resetForm = () => { // ❌ 나중에 정의됨
  // 폼 초기화 로직
}

✅ After (개선 코드):
resetForm 함수를 watch 구문 위로 이동시켜 정의 시점을 앞당겼습니다.

const resetForm = () => { // ✅ watch보다 먼저 정의
  form.value = { /* ... 초기화 로직 */ }
  formRef.value?.clearValidate()
}

// watch 구문들...
watch(() => props.connection, (connection) => {
  // ...
  else {
    resetForm() // ✅ 이제 안전하게 호출 가능
  }
}, { immediate: true })

개선 효과:

  • 런타임 오류 제거: ReferenceError 없이 컴포넌트가 안정적으로 초기화됩니다.
  • 코드 예측 가능성 향상: JavaScript 호이스팅에 대한 이해를 바탕으로 더욱 견고한 코드를 작성할 수 있게 되었습니다.

2. 라우팅 시스템: 유연하고 강력하게

라우터 가드에서 Pinia Store를 사용하는 대신, 각 뷰(View) 컴포넌트 내에서 개별적으로 연결 상태를 확인하고 처리하도록 구조를 변경했습니다. 이는 라우팅 시스템의 복잡성을 줄이고 더 유연한 네비게이션 흐름을 가능하게 합니다.

💡 Before (문제 코드):
라우터 가드에서 useConnectionStore()를 사용하여 오류가 발생했습니다.

// src/router/index.ts
import { useConnectionStore } from '@/stores/connection' // ❌ 잘못된 import

router.beforeEach((to, from, next) => {
  const connectionStore = useConnectionStore() // ❌ 오류 발생
  
  if (to.meta.requiresConnection && !connectionStore.currentConnection) {
    next('/connections')
  } else {
    next()
  }
})

✅ After (개선 코드):
라우터 가드를 제거하고, 라우트 정의를 단순화했습니다.

// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
// ...

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      name: 'Dashboard',
      component: Dashboard // ✅ 간단한 라우트 정의
    },
    // ...
  ]
})

export default router // ✅ 라우터 가드 제거

개선 효과:

  • 페이지 이동 차단 문제 해결: 라우터 가드로 인한 불필요한 페이지 이동 차단이 사라졌습니다.
  • 유연한 네비게이션: 각 컴포넌트가 자신의 책임 하에 연결 상태를 관리하여 더욱 유연하고 예측 가능한 네비게이션 흐름을 제공합니다.

3. 뷰 컴포넌트: 사용자 친화적인 조건부 렌더링

연결 상태에 따라 대시보드 콘텐츠를 조건부로 렌더링하도록 Dashboard.vue 컴포넌트를 개선했습니다. 연결이 없는 경우 사용자에게 명확한 안내와 함께 '연결 관리' 페이지로 이동할 수 있는 버튼을 제공하여 사용자 경험을 크게 향상시켰습니다.

💡 Before (문제 코드):
연결 상태 확인 없이 바로 컴포넌트를 렌더링했습니다.

<template>
  <div class="dashboard">
    <MetricsDashboard :connection-id="currentConnection.id" />
      </div>
</template>

✅ After (개선 코드):
v-if를 사용하여 연결 상태에 따른 조건부 렌더링을 구현했습니다.

<template>
  <div class="dashboard">
        <div v-if="!currentConnection" class="no-connection">
      <el-empty description="연결된 클러스터가 없습니다">
        <el-button type="primary" @click="$router.push('/connections')">
          연결 관리로 이동
        </el-button>
      </el-empty>
    </div>

    <div v-else class="dashboard-content">
      <MetricsDashboard :connection-id="currentConnection.id" />
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { useConnectionStore } from '@/stores/connection'
import MetricsDashboard from '@/components/metrics/MetricsDashboard.vue'

const connectionStore = useConnectionStore()
const currentConnection = computed(() => connectionStore.currentConnection)
</script>

개선 효과:

  • 사용자 친화적인 안내: 연결이 없을 때 사용자에게 명확한 피드백을 제공합니다.
  • 직관적 네비게이션: 필요한 경우 사용자가 쉽게 '연결 관리' 페이지로 이동할 수 있도록 안내합니다.
  • 안정적인 렌더링: 유효하지 않은 데이터로 인한 컴포넌트 오류를 방지하고, 안정적인 사용자 경험을 보장합니다.

📈 개선의 결과: 더 강력해진 Kafka Kopanda Frontend

이번 문제 해결 및 개선 과정을 통해 Kafka Kopanda Frontend는 다음과 같은 긍정적인 변화를 맞이했습니다.


📊 성능 및 안정성 향상

  • 런타임 오류 100% 제거: 개발 과정에서 발견되었던 모든 런타임 오류를 성공적으로 해결했습니다.
  • 페이지 로딩 속도 개선: 불필요한 라우터 가드 로직 제거 및 효율적인 컴포넌트 렌더링으로 페이지 로딩 속도가 향상되었습니다.

📜 코드 품질 향상

  • 견고한 에러 처리: 예방적 코딩을 통해 애플리케이션의 에러 처리 로직이 더욱 견고해졌습니다.
  • 높아진 코드 가독성 및 유지보수성: 명확한 책임 분리와 일관된 코딩 스타일로 코드 가독성과 유지보수성이 크게 향상되었습니다.

🌟 사용자 경험 개선

  • 명확하고 직관적인 피드백: 사용자에게 필요한 정보와 가이드를 적시에 제공하여 혼란을 줄였습니다.
  • 예측 가능한 동작: 예기치 않은 오류 없이 안정적으로 동작하여 전반적인 사용자 만족도가 높아졌습니다.

💡 이번 여정에서 얻은 교훈

이번 Kafka Kopanda Frontend 개선 프로젝트는 단순한 코드 수정 이상의 의미를 가집니다. 개발 과정에서 얻은 중요한 교훈들은 앞으로 더 나은 소프트웨어를 만드는 데 큰 자산이 될 것입니다.

  1. Vue 3 Composition API의 깊이 있는 이해: 함수 정의 순서와 생명주기의 중요성을 깨달았습니다.
  2. Pinia Store의 올바른 활용: 상태 관리 라이브러리의 올바른 사용법과 라우터 가드 내에서의 제한사항을 명확히 인지하게 되었습니다.
  3. Vue Router의 유연성: 라우터 가드 외에도 각 컴포넌트에서 필요한 로직을 처리하는 유연한 접근 방식의 중요성을 배웠습니다.
  4. 사용자 경험을 위한 조건부 렌더링: 조건부 렌더링이 단순한 기능 구현을 넘어 사용자에게 제공하는 정보의 질과 경험에 얼마나 큰 영향을 미치는지 체감했습니다.
  5. 예방적 코딩의 중요성: 개발 초기 단계에서부터 잠재적 오류를 예측하고 방지하는 코딩 습관의 중요성을 다시 한번 상기했습니다.

이러한 개선을 통해 Kafka Kopanda Frontend는 더욱 안정적이고 사용자 친화적인 애플리케이션으로 거듭났습니다. 앞으로도 사용자들의 피드백에 귀 기울이며 지속적으로 발전시켜 나갈 예정입니다.

profile
꾸준히, 의미있는 사이드 프로젝트 경험과 문제해결 과정을 기록하기 위한 공간입니다.

0개의 댓글