개발자의 이상한 애정, 또는 나는 어떻게 걱정을 멈추고 Windows를 사랑하게 되었는가

· · Windows, Windows 앱 개발, 하위 호환성, COM, ActiveX, QA, 철학

1. 먼저 결론

Windows 앱을 만들다 보면, 걱정할 일이 많습니다.

이 PC에서 제대로 실행될까. 관리자 권한이 없는 환경에서도 동작할까. 32bit / 64bit의 차이로 깨지지 않을까. 한국어 경로, 긴 경로, 네트워크 드라이브, 오래된 DLL, COM 컴포넌트, ActiveX, 프린터, 시리얼 통신, 백신 소프트웨어, Windows Update.

생각하기 시작하면, 걱정은 끝이 없습니다.

하지만 어느 순간부터 저는 이렇게 생각하게 되었습니다.

이것은 결점이라기보다, Windows가 현실의 업무를 짊어져 온 증거가 아닐까, 하고요.

Windows는 깔끔한 이상향이 아닙니다. 하지만 현장에서 수십 년째 계속 동작해 온 소프트웨어, 장비, 업무 흐름, 사람들의 익숙함을 끌어안고 있습니다.

그 혼돈이야말로 Windows의 재미이자, 개발자로서 마주할 가치가 있는 부분이라고 생각합니다.

2. Windows 앱 개발은 걱정거리가 많다

Windows 앱 개발에서는 「코드가 옳다」는 것만으로는 부족합니다.

로컬 환경에서는 동작한다. 개발자의 PC에서는 동작한다. 검증용 VM에서도 동작한다.

그래도, 고객의 PC에서 동작한다고는 장담할 수 없습니다.

예를 들어, 다음과 같은 일들이 일어납니다.

  • DLL을 찾을 수 없다
  • Visual C++ 런타임이 설치되어 있지 않다
  • .NET Framework의 버전이 맞지 않는다
  • 32bit DLL을 64bit 프로세스에서 불러오려다 실패한다
  • COM 등록이 깨져 있다
  • regsvr32.exe의 32bit 버전과 64bit 버전을 혼동한다
  • 현재 디렉터리를 전제로 한 코드가 태스크 스케줄러에서 깨진다
  • Program Files 하위에 쓰려다 권한 오류가 난다
  • AppData\RoamingAppData\Local의 구분을 잘못한다
  • 한국어 사용자 이름이나 한국어 폴더 이름에서 죽는다
  • 긴 경로에서 파일을 열지 못한다
  • 네트워크 드라이브에서는 동작하지만 UNC 경로에서는 동작하지 않는다
  • 고 DPI 환경에서 화면이 깨진다
  • 멀티 모니터에서 좌표 계산이 어긋난다
  • 프린터 드라이버에 따라 인쇄 결과가 달라진다
  • USB 기기, 카메라, 계측기, 시리얼 통신이 환경에 따라 인식되지 않는다
  • 백신 소프트웨어가 일부 처리를 막는다
  • Windows Update 이후 동작이 달라진다

이렇게 나열하면, 조금 아득해집니다.

웹 앱이라면 브라우저와 서버 사이에 갇혀 있을 문제가, Windows 앱에서는 PC 전체로 퍼집니다. 파일 시스템, 레지스트리, 사용자 프로필, 프린터, 디바이스, 네트워크, 보안 정책, 설치 프로그램, 런타임.

애플리케이션은 OS 위에서 동작한다기보다, 업무 환경 안에 놓입니다.

그래서 Windows 앱 개발은 어렵습니다. 다만, 그것을 「Windows는 안 되겠다」고 잘라 말하는 것은 조금 다르다고 생각합니다.

거기에 얹혀 있는 것은, 현실 세계의 복잡함입니다.

3. Windows는 “현장의 OS”이다

Windows는 최신 기술만을 위한 OS가 아닙니다.

공장, 병원, 관공서, 학교, 연구실, 방송, 검사 장비, 접수 단말, 서식 단말, 창고, 매장, 회계, 급여, 재고 관리. 그런 곳에서, 지금도 수많은 Windows PC가 동작하고 있습니다.

그곳에는, 최신 웹 서비스만 있는 것이 아닙니다.

Excel 매크로가 있습니다. Access가 있습니다. 오래된 VB 앱이 있습니다. .NET Framework 업무 앱이 있습니다. C++로 만들어진 상주 앱이 있습니다. COM 컴포넌트가 있습니다. ActiveX가 있습니다. ODBC 연결이 있습니다. 프린터 드라이버가 있습니다. 바코드 리더기가 있습니다. 시리얼 통신 계측기가 있습니다. 벤더가 제공하는 SDK가 있습니다.

게다가, 그것들은 단독으로 존재하는 것이 아닙니다.

사람이 조작하고, 서식을 인쇄하고, USB 기기를 교체하고, 공유 폴더에 CSV를 두고, 야간 배치가 동작하고, 다음 날 아침 업무가 시작된다. 그런 일련의 흐름 속에서 동작하고 있습니다.

Windows는 단순히 앱을 실행하기 위한 토대가 아닙니다. 현장의 작업, 기존 자산, 주변 기기, 사람들의 익숙함까지 포함해서 받아들이는 플랫폼입니다.

그래서 때로는 낡아 보입니다. 때로는 복잡합니다. 때로는, 왜 아직 이게 남아 있는지 의아한 것도 있습니다.

하지만 그것은, 낡은 것을 대충 버려오지 않았다는 뜻이기도 합니다.

4. 하위 호환성이라는 애정

OS를 아름답게 보이기만 하려면, 낡은 구조를 잘라내는 쪽이 쉽습니다.

낡은 API를 지운다. 낡은 런타임을 지운다. 낡은 설정 화면을 지운다. 낡은 앱은 동작하지 않는 것으로 취급한다.

그렇게 하면, 설계는 깔끔해질지도 모릅니다. 문서도 짧아질지도 모릅니다. 개발자의 기분도 조금 가벼워질지도 모릅니다.

그러나 그 뒤편에서 동작하지 않게 되는 업무 앱이 있습니다. 멈추는 장비가 있습니다. 곤란해지는 현장이 있습니다.

Windows의 하위 호환성은, 기술적으로는 골치 아픕니다. 32bit 앱을 64bit Windows에서 동작시키기 위한 WOW64가 있습니다. 32bit와 64bit에서 레지스트리나 DLL이 보이는 방식이 달라지는 경우가 있습니다. C:\Windows\System32가 64bit 쪽이고, C:\Windows\SysWOW64가 32bit 쪽이라는, 처음 보면 혼란스러운 구조도 있습니다.

COM도 골치 아픕니다. DLL을 두기만 해서는 동작하지 않고, 등록이 필요한 경우가 있습니다. 등록 대상이 사용자 단위인지 머신 단위인지. 32bit COM인지 64bit COM인지. 관리자 권한이 필요한지.

.NET Framework도 마찬가지입니다. 지금이라면 .NET 8 / .NET 9 같은 새로운 .NET을 쓰는 선택지가 있습니다. 하지만 현장에는 .NET Framework 4.x 앱이 지금도 있습니다. 그것은 단순히 낡은 것이 아니라, 그 버전으로 오랫동안 업무를 지탱해 왔다는 뜻입니다.

하위 호환성은, 아름답기만 한 개념이 아닙니다. 오히려 무거운 책임입니다.

낡은 것을 계속 동작시킨다는 것은, 기술적 부채를 안는 것이기도 합니다. 하지만 동시에, 이용자의 업무를 멈추지 않겠다는 성실함이기도 합니다.

저는 여기에 Windows의 사랑스러운 부분이 있다고 생각합니다.

5. Windows는 지층 같은 OS이다

Windows에는 시대별 기술이 지층처럼 쌓여 있습니다.

Win32. COM. ActiveX. Windows Forms. WPF. .NET Framework. UWP. WinUI. Windows App SDK. MSIX. PowerShell. Windows Terminal. WSL.

각각 등장한 시대가 있고, 잘하는 분야가 있고, 쓰여온 현장이 있습니다.

새로운 것만 본다면, 낡은 것은 방해로 보일지도 모릅니다. 하지만 Windows 앱 개발에서는, 낡은 층을 무시할 수 없는 순간이 자주 있습니다.

예를 들어, WPF 앱을 만들고 있어도, 인쇄에서는 GDI나 프린터 드라이버 문제를 마주치는 경우가 있습니다. C#으로 작성하고 있어도, 벤더 SDK가 네이티브 DLL이라면 P/Invoke나 비트 수 문제를 마주칩니다. 새로운 화면을 만들고 있어도, 기존 COM 컴포넌트나 Excel 연동을 남겨야 할 필요가 있는 경우가 있습니다.

Windows는, 완전히 정리된 정원이 아닙니다. 오히려, 증개축을 반복해 온 거대한 도시에 가깝습니다.

큰길도 있습니다. 지하도도 있습니다. 낡은 골목도 있습니다. 새로운 고층 빌딩도 있습니다.

헤매기 쉽습니다. 하지만 그 골목 안쪽에서, 지금도 중요한 업무가 돌아가고 있습니다.

개발자에게 필요한 것은, 「낡았으니 불필요하다」고 판단하는 것이 아닙니다. 어느 층의 기술이, 어느 업무를 지탱하고 있는지를 가려내는 것입니다.

6. 번거로움을, 설계로 바꾸다

제목에서는 「걱정하는 것을 멈추고」라고 썼습니다.

다만, 걱정을 멈춘다는 것은 대충 하게 되는 것이 아닙니다. 문제를 못 본 척하는 것도 아닙니다.

걱정을 멈춘다는 것은, 걱정을 설계로 바꾸는 것입니다.

예를 들어, 실행될지 불안하다면, 실행 확인을 스모크 테스트로 만듭니다.

Start-Process .\MyApp.exe

단순히 실행되는지만 보는 것이 아니라, 설정 파일이 없는 상태, 로그 폴더가 없는 상태, 표준 사용자 권한, 네트워크 미연결, 프린터 미설정, 고 DPI, 긴 경로, 한국어 경로에서도 시도합니다.

DLL이 불안하다면, 의존 관계를 확인합니다. Visual C++ 런타임이 필요하다면, 설치 프로그램에 포함할지, 사전 조건으로 명기할지를 결정합니다. 네이티브 DLL을 쓴다면, x86 / x64 / AnyCPU의 관계를 모호하게 두지 않습니다.

COM이 불안하다면, 등록 절차를 매뉴얼로 만들고, 검증용 PC에서 처음부터 재현합니다.

# 64bit COM DLL 등록 예시
C:\Windows\System32\regsvr32.exe .\SomeComponent64.dll

# 32bit COM DLL 등록 예시
C:\Windows\SysWOW64\regsvr32.exe .\SomeComponent32.dll

권한이 불안하다면, 관리자 권한이 있어야만 동작하는 설계를 피합니다. 사용자 설정은 AppData에 두고, 전체 설정은 ProgramData에 둡니다. Program Files 하위에 로그를 쓰는 것 같은 설계는 피합니다.

경로가 불안하다면, 한국어, 공백, 긴 폴더 이름, UNC 경로를 테스트에 포함시킵니다.

New-Item -ItemType Directory -Path "C:\테스트 용\아주 긴 폴더 이름\더 깊은 폴더" -Force

DPI가 불안하다면, 100%, 125%, 150%, 200%에서 확인합니다. 멀티 모니터에서, 배율이 다른 디스플레이를 넘어가도 무너지지 않는지 봅니다. WinForms, WPF, WinUI에서는 각각 DPI 대응 방식이 다르기 때문에, 화면 기술마다 확인합니다.

메모리나 핸들이 불안하다면, Application Verifier, WinDbg, ProcDump, Process Explorer 등을 사용합니다. 크래시가 불안하다면, 이벤트 로그, 덤프, 애플리케이션 로그를 남깁니다.

Get-EventLog -LogName Application -Newest 20

또는 새로운 환경이라면, 다음과 같이 이벤트 로그를 확인합니다.

Get-WinEvent -LogName Application -MaxEvents 20

현장에서 재현되지 않는 버그가 불안하다면, 로그의 세밀함을 높입니다. 「오류가 발생했습니다」로는 부족합니다. 어느 파일을 열려고 했는지. 어느 디바이스를 찾았는지. 어느 사용자로 실행되었는지. 어느 경로에 쓰려고 했는지. 어느 DLL을 불러오지 못했는지.

걱정을, 관찰할 수 있는 형태로 바꾼다.

이것이 Windows 앱 개발에서는 매우 중요합니다.

7. 「고객의 PC에서 동작한다」가 최종 목표이다

개발 환경에서 동작하는 것은 중요합니다. CI에서 테스트가 통과하는 것도 중요합니다. 깨끗한 VM에서 동작하는 것도 중요합니다.

하지만 Windows 앱의 경우, 마지막에 가로막는 것은 「고객의 PC에서 동작하는가」입니다.

그 PC에는, 이미 무언가가 설치되어 있습니다. 오래된 프린터 드라이버가 설치되어 있을지도 모릅니다. 독자적인 보안 소프트웨어가 설치되어 있을지도 모릅니다. 네트워크 드라이브가 할당되어 있을지도 모릅니다. 사용자에게 관리자 권한이 없을지도 모릅니다. Windows Update를 바로 적용할 수 없는 사정이 있을지도 모릅니다. 인터넷에 나갈 수 없는 환경일지도 모릅니다.

그래서 배포 방법도 중요해집니다.

단순히 exe를 전달하면 되는지. MSI로 만들지. ClickOnce로 만들지. MSIX로 만들지. winget으로 배포할 수 있는지. 사내 배포 시스템에 올릴지. 오프라인 설치 프로그램이 필요한지. 코드 서명이 필요한지. SmartScreen이나 백신 소프트웨어에서 막히지 않는지.

애플리케이션 본체뿐 아니라, 설치, 업데이트, 제거, 로그 수집, 복구 절차까지 포함해야, 겨우 「현장에서 쓸 수 있다」에 가까워집니다.

Windows 앱 개발에서는, 소프트웨어는 납품으로 끝나지 않습니다. 고객의 환경에서, 오늘도 내일도 실행되어야 합니다.

8. 그래도 Windows를 사랑하는 이유

Windows에는 번거로운 부분이 있습니다. 이것은 사실입니다.

DLL. COM. 레지스트리. UAC. DPI. 프린터. 런타임. 32bit / 64bit. 네트워크 드라이브. 긴 경로. 한국어 환경. 보안 소프트웨어. Windows Update.

번거로운 것을 꼽으라면, 얼마든지 나옵니다.

하지만 그 번거로움의 대부분은, Windows가 현실의 업무를 오랫동안 짊어져 온 데서 옵니다.

낡은 자산을 버리지 않고, 새로운 기술도 받아들이고, GUI도 CLI도 갖고, 로컬 앱도 웹도, 주변 기기도 업무 단말도, 개인 PC도 기업 PC도 받아들인다.

그것은 아름다운 단일 사상이 아닙니다.

하지만, 강합니다.

그리고, 개발자로서는 도전할 가치가 있습니다.

Windows 위에서 확실히 동작하는 소프트웨어를 만든다는 것은, 단순히 API를 호출하는 것이 아닙니다. 현장의 제약을 읽고, 기존 자산을 이해하고, 부서지기 쉬운 부분을 찾아내고, 테스트하고, 관찰하고, 필요한 부분을 고쳐나가는 것입니다.

그것은 소박합니다. 하지만, 가치가 있습니다.

9. 정리

Windows 앱 개발에서는 걱정거리가 끝이 없습니다.

하지만 그 걱정의 대부분은, Windows라는 OS가 오랜 시간을 들여 현실의 업무, 현장, 장비, 사람들의 조작을 받아들여 온 결과이기도 합니다.

그래서 저는, Windows를 단순한 낡은 OS라고는 생각하지 않습니다.

그것은, 현실과 타협하면서 계속 동작해 온, 거대하고 복잡하며, 조금 서투른 플랫폼입니다.

그리고, 그 위에서 확실히 동작하는 소프트웨어를 만드는 데에는, 지금도 큰 가치가 있습니다.

걱정하는 것을 멈춘다.

다만, 방심하는 것은 아닙니다.

걱정을, 설계와 테스트와 관찰로 바꾼다.

그렇게 하여 저는, 조금씩 Windows를 사랑하게 되었습니다.

참고 링크

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

ActiveX 이관

COM / ActiveX / OCX 자산을 유지할지, 감쌀지, 교체할지의 단계적 판단을 정리한 토픽 페이지입니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기