Mendix로 1년 동안 혼자 만들고 운영한 점검 관리 시스템을 새 플랫폼으로 이관하는 대신 Flask/FastAPI로 재개발하기로 결정했다. 이관할 때 생기는 리스크 6가지, 재개발 판단 기준, DB 테이블을 이관·신규 구현·폐기로 나누는 방법을 정리했다.
이 글의 순서
상황: 혼자 만든 시스템을 옮겨야 했다
점검 결과와 이슈 사항을 관리하는 사내 시스템을 Mendix로 만들어 1년 가까이 혼자 개발하고 운영해 왔다. 파일럿이지만 월평균 130명 정도가 쓰고, 기존 사내 PaaS 위에서 안정적으로 돌고 있었다.
그러던 중 같은 조직의 다른 서비스(Flask)를 새 Kubernetes 플랫폼으로 옮겼고, 이 시스템도 같이 옮기는 게 자연스러운 다음 순서였다. 이관 절차를 점검하다가 방향을 바꿔 재개발하기로 했다. 이 글은 그 판단 과정이다.
그대로 옮기면 생기는 리스크 6가지
Mendix 앱은 소스(MPR)와 실행 환경, DB가 생각보다 단단히 묶여 있다. 새 플랫폼에 같은 앱을 띄우고 운영 DB를 연결하는 순간 아래 문제가 생길 수 있었다.
| 리스크 | 무슨 일이 생기나 |
|---|---|
| 예약 작업 중복 실행 | 두 환경의 앱이 같은 운영 DB를 보면 스케줄 이벤트가 두 번 돈다. 메일이 두 번 나가고 집계가 꼬인다. |
| 기동 시 스키마 변경 | 새 환경 앱이 시작하면서 DB 스키마를 자기 모델에 맞춘다. 버전이 조금만 달라도 기존 환경 앱이 깨질 수 있다. |
| 첨부파일 위치 | 파일은 기존 플랫폼의 공유 스토리지에 있다. DB에는 레코드만 있고 실제 파일은 새 환경에 없다. |
| DB 네트워크 접근 | 새 클러스터의 IP 대역에서 DB 접근이 허용돼 있는지 따로 확인해야 한다. |
| SSO 설정 위치 | SSO 설정 일부가 DB에 저장돼 있어 도메인이 바뀌면 같이 손봐야 한다. |
| 힙 메모리 | 컨테이너 메모리 한도와 JVM 힙 설정을 다시 맞춰야 한다. |
하나하나는 해결할 수 있다. 문제는 이걸 다 해결하고 나도 결과물이 '같은 시스템이 다른 곳에서 도는 것'이라는 점이다. 그동안 쌓인 구조적 불편은 그대로 따라온다.
그래서 재개발: 판단 기준 세 가지
1. AI와 함께 개발하는 속도
가장 큰 이유다. 같은 조직의 Flask 서비스는 AI의 도움을 받아 코드로 개발했는데, 기능 하나를 추가하는 속도가 Mendix와 비교가 안 됐다. Mendix는 도메인 모델과 마이크로플로를 화면에서 손으로 그린다. 텍스트가 아니라서 AI가 직접 만들어 줄 수 없고, 설명을 들어도 결국 사람이 하나씩 클릭해 옮겨야 한다. 코드는 AI가 쓰고 사람이 검토하는 구조가 된다.
기능 하나를 추가할 때
Mendix
코드 + AI
2. 인프라 경로는 이미 검증됐다
재개발의 부담은 대개 인프라다. 이번에는 먼저 옮긴 Flask 서비스로 도메인, TLS 인증서, SSO, CI/CD를 이미 다 뚫어 놓은 상태였다. 같은 플랫폼에 별도 Product를 하나 더 만들면 같은 절차를 반복하면 된다.
3. 서두를 이유가 없다
기존 시스템은 지금 안정적으로 돈다. 그래서 기존 시스템은 그대로 운영하고, 새 시스템은 처음부터 제대로 설계해 완성한 뒤 데이터를 옮겨 전환하기로 했다. 병행 기간에 운영 리스크가 없다는 게 이관과 비교했을 때 가장 큰 차이다.
병행 운영 후 전환
주의로우코드가 나쁘다는 이야기는 아니다. 1년 전에는 Mendix 덕분에 혼자서 시스템을 띄울 수 있었다. 판단이 바뀐 건 개발 방식이 바뀌었기 때문이다. AI가 직접 다룰 수 있는 형태인지가 이제 플랫폼 선택 기준 중 하나가 됐다.
재개발 범위는 DB 테이블에서 시작했다
다시 만들 때 가장 위험한 건 '기존에 있던 기능'을 빠뜨리는 것이다. 화면 목록보다 DB 테이블이 더 정직하다. 한 MPR에 모듈을 몰아 개발하다 보니 안 쓰는 모듈도 많았다. 테이블마다 행 수와 마지막 변경일을 뽑고, 모듈별로 실제 사용 여부를 확인해 세 가지로 나눴다.
-- 테이블별 행 수 (InnoDB는 추정값이라 순서 파악용) SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema = 'app_db' ORDER BY table_rows DESC; -- 정확한 행 수와 마지막 변경일 (Mendix 엔티티에 changedDate를 켠 경우) SELECT COUNT(*) AS n, MAX(changeddate) AS last_changed FROM `inspection$inspectionresult`;
| 구분 | 대상 | 규모 | 처리 |
|---|---|---|---|
| 이관 | 점검 결과 | 약 1만 행 | 그대로 옮김 |
| 이관 | 기준정보(마스터) | - | 그대로 옮김 |
| 이관 | 점검 양식 폼·행·셀 구조 | 약 3,400 행 | 구조 재설계 후 변환 |
| 이관 | 조치 항목·복기 회의 | 약 200 행 | 그대로 옮김 |
| 이관 | 사례 공유(Lessons Learned) | 약 120 행 | 그대로 옮김 |
| 이관 | 온열·한랭 질환 점검 | - | 최근 추가된 도메인 |
| 새로 구현 | 사원정보 복사본 | 약 15만 행 | 복사 대신 실시간 조회 |
| 새로 구현 | 대시보드·목록 캐시 | - | 쿼리로 다시 생성 |
| 새로 구현 | SSO·계정 테이블 | - | 관리자 역할만 추출 |
| 새로 구현 | 메일 발송 이력 | - | 새 로그 구조로 |
| 폐기 | 초기 버전 모듈 | 약 1천 행 | 사용 안 함 |
| 폐기 | 백업 테이블 | 11개 | 사용 안 함 |
| 폐기 | 벤치마킹용 모듈 | - | 사용 안 함 |
| 폐기 | 행이 거의 없는 모듈 | 0~4 행 | 사용 안 함 |
규모는 반올림한 값이다.
'새로 구현'으로 분류한 것들이 재개발의 진짜 이득이다. 사원정보를 매일 통째로 복사해 두던 테이블은 필요할 때 조회하는 방식으로 바꾸면 수십만 행이 사라진다. 캐시 테이블도 쿼리 하나로 대체된다. 이관이었다면 전부 그대로 따라왔을 것들이다.
행이 0인 관계 테이블은 바로 버리지 않는다
Mendix는 엔티티 사이의 관계(association)를 별도 테이블로 저장한다. 그런데 분명히 쓰는 관계인데 테이블이 비어 있는 경우가 두 건 있었다. 관계를 테이블 대신 속성(ID 값)으로 저장했을 가능성이 있어서, 설계 단계에서 스키마를 다시 확인하기로 하고 폐기 목록에서 뺐다. 0행이라는 숫자만 보고 지우면 이런 데이터를 놓친다.
정리
- 이관 리스크가 해결 가능해도, 이관 후 결과물이 '같은 불편을 가진 같은 시스템'이면 재개발을 검토할 만하다.
- AI와 함께 개발한다면 플랫폼이 텍스트(코드)로 다뤄지는지가 생산성을 크게 가른다.
- 기존 시스템이 안정적이면 병행 운영 후 전환해서 리스크를 없앤다.
- 재개발 범위는 화면보다 DB 테이블 목록에서 시작하고, 이관·새로 구현·폐기로 나눈다.