Cloud Modernization 07

DevOps, 벽을 넘어 협력으로: 개발팀과 운영팀 사이의 진짜 이야기

DevOps를 도구 묶음이나 배포 자동화 정도로만 이해하면 조직 문화와 책임 흐름이 보이지 않는다.

근거 · 교안 p24-p26

DevOps가 개발팀과 운영팀 사이의 벽을 허무는 이유 ?? ???

1장: DevOps는 단순히 ‘자동화’가 아니다: 조직 문화와 방법론의 중요성

솔라의 손가락이 노트북 트랙패드 위에서 멈췄다. 화면 가득 여러 색으로 빛나는 코드들이 복잡한 무늬처럼 펼쳐져 있었다. 최근 골머리를 앓던 배포 자동화 스크립트였다. ‘이것만 완성하면 개발팀과 운영팀의 끝없는 줄다리기가 좀 나아질 텐데.’ 솔라는 막연한 기대를 품고 있었다.

“언니, DevOps라는 거 말이야.”

솔라가 화면에서 눈을 떼지 않은 채 투덜거리듯 입을 열었다.

“결국 이런 거 아닐까? 개발자가 만든 걸 운영 서버에 옮길 때 실수하지 않게, 더 빠르고 안전하게 자동화 도구를 잘 쓰는 거. 이 스크립트 하나만 잘 짜두면 ‘네 잘못이다’, ‘내 잘못이다’ 하면서 싸울 일도 줄어들지 않을까?”

옆에서 조용히 책을 읽던 루나가 고개를 들었다. 언니는 솔라의 노트북 화면을 흘깃 보았지만, 복잡한 스크립트 코드에 대해서는 아무 말도 하지 않았다. 대신, 아주 간단한 상상을 제안했다.

“좋은 생각이네. 그럼 그 스크립트가 정말 완벽해서, 클릭 한 번으로 1초 만에 배포가 끝났다고 상상해볼까? 어떤 일이 벌어질까?”

“일단 편해지지!” 솔라가 신나서 대답했다. “개발팀은 배포 기다릴 필요 없이 바로 다음 일에 집중할 수 있고, 운영팀도 수작업하다가 실수할 걱정 없으니까. 모두가 행복해지는 거지.”

“그래, 배포는 성공적이었어. 그런데 한 시간 뒤에, 서비스가 갑자기 느려졌다는 사용자 문의가 빗발치기 시작했어. 장애 알림은 누가 받을까?”

“음… 그건 당연히 운영팀이겠지? 인프라나 서버 안정성을 책임지는 팀이니까.”

솔라의 대답은 망설임이 없었다. 루나는 질문을 이어갔다.

“운영팀은 즉시 서버 상태를 확인했어. CPU, 메모리, 네트워크 전부 다 정상이야. 그럼 운영팀은 뭐라고 할까?”

“‘서버는 문제없으니 새로 배포된 애플리케이션 코드 문제인 것 같다’고 개발팀에 공을 넘기겠지. ‘방금 배포한 것 때문에 그런 거 아니냐’면서.”

솔라가 자기도 모르게 운영팀의 입장을 변호하듯 말했다.

“그럼 개발팀은 뭐라고 대답할까? 특히 방금 솔라 네가 만든 그 ‘완벽한’ 자동화 스크립트로 배포를 마친 참인데.”

“…아.”

솔라의 입에서 작은 탄식이 터져 나왔다. 머릿속에 개발팀 동료의 목소리가 생생하게 들리는 듯했다. ‘제 컴퓨터에선 완벽하게 돌아갔어요. 그리고 배포 스크립트도 아무 오류 없이 성공했다고 로그에 찍혔는데요?’

완벽한 자동화 스크립트는 배포라는 ‘행위’를 빠르고 정확하게 처리했을 뿐이었다. 하지만 문제가 생겼을 때 ‘누가 책임을 질 것인가’를 둘러싼 근본적인 갈등은 전혀 해결하지 못했다. 오히려 ‘자동화는 완벽했으니 내 책임은 끝났다’라는 새로운 방어벽만 만들어준 셈이었다. 도구는 도구일 뿐, 서로를 대하는 방식이나 문제를 함께 해결하려는 태도는 바꾸지 못했다.

솔라는 아까 스터디 자료에서 무심코 넘겼던 문장을 떠올렸다.

DevOps는 개발(Development)과 운영(Operations)의 합성어로, 개발팀과 운영팀이 협력하여 소프트웨어를 더 빠르고 안정적으로 개발, 배포, 운영하기 위한 조직 문화와 방법론이다.

그저 밋밋한 정의라고 생각했던 ‘조직 문화와 방법론’이라는 단어가 갑자기 망치처럼 머리를 때렸다. 자동화 스크립트를 짜는 기술이 중요한 게 아니었다. 스크립트가 실행되기 전과 후에, 두 팀이 어떻게 함께 계획하고, 함께 문제를 바라보고, 함께 책임지는지가 진짜 핵심이었다.

“알겠다… 자동화는 그냥 ‘더 빨리’ 벽 너머로 무언가를 던지는 방법일 뿐이구나. 벽 자체를 허무는 게 아니었어.”

솔라는 허탈하게 중얼거렸다.

“진짜 DevOps는 스크립트가 아니라 사람과 프로세스, 일하는 방식을 바꾸는 거였네.”

루나는 솔라의 깨달음에 가만히 고개를 끄덕여 주었다. 그러자 솔라의 머릿속에 풀리지 않은 더 근본적인 질문이 떠올랐다.

“그런데 언니, 애초에 왜 그런 ‘벽’이 있는 거지? 개발팀이랑 운영팀은 같은 회사 사람이잖아. 왜 서로 다른 목표를 가지고 싸우는 것처럼 일하게 되는 걸까? 뭔가 구조적인 이유라도 있는 거야?”

2장: ‘내 환경에선 잘 됐는데?’ 벽이 생기는 구조적 이유

솔라의 질문이 거실 공기 속에 잠시 머물렀다. “애초에 왜 그런 ‘벽’이 있는 거지?”

루나는 솔라의 질문에 바로 대답하는 대신, 조용히 자리에서 일어나 서랍에서 메모지와 펜 한 자루를 가져왔다. 그리고는 테이블 위에 놓인 메모지 한가운데에 길게 세로 선을 그었다. 마치 방을 둘로 나누는 가벽을 세우듯. 선 왼쪽 위에 ‘개발팀’, 오른쪽 위에 ‘운영팀’이라고 적었다.

솔라는 언니가 만든 이 작은 분할선을 말없이 지켜보았다. 지난 장에서 자동화만으로는 해결되지 않던 그 ‘벽’이 눈앞에 그려진 것 같았다. 솔라는 여전히 이 갈등이 개인의 태도나 소통 방식의 문제라고 생각했다. “결국 서로 입장을 더 잘 이해해주면 되는 거 아닐까? 개발팀장님이랑 운영팀장님이 좀 더 자주 만나서 이야기하면 풀릴 문제 같은데.”

루나는 펜을 든 채 솔라를 바라보았다.

“그럼 아주 흔한 상황을 하나 가정해보자. 개발팀이 이렇게 말하는 순간을. ‘제 환경에서는 문제없이 잘 동작했어요.’”

루나의 말에 솔라는 자기도 모르게 미간을 찌푸렸다. 회사에서 수십 번은 듣고, 또 해봤던 말이었다.

“그 말을 들었을 때, 운영팀의 진짜 속마음은 어떨까? 솔라 네가 지금 막 장애 알림을 받고 달려온 운영팀 담당자라고 상상해봐.”

솔라는 눈을 감았다. 휴대폰에서 울리는 시끄러운 장애 알림 소리가 귓가에 울리는 듯했다. 새벽 3시. 간신히 원인을 찾아 개발팀 담당자에게 연락했는데, 돌아온 대답은 ‘제 PC에선 잘 됐는데요’이다.

솔라의 입에서 거친 말이 튀어나왔다. “미치고 팔짝 뛸 노릇이네. 당신 PC가 아니라 지금 수만 명이 쓰는 서비스에 불이 났는데! 개발 환경에서 잘 되는 게 무슨 소용이야? 여긴 전쟁터라고!”

순간 솔라는 놀라 입을 다물었다. 너무나 생생한 감정이었다. 개발자의 책임 회피성 발언에 대한 분노, 문제를 함께 해결하려 하지 않는 태도에 대한 좌절감이 한꺼번에 밀려왔다.

“좋아. 그럼 이번엔 역할을 바꿔보자. 네가 바로 그 말을 한 개발자야. 야심 차게 만든 새 기능을 성공적으로 배포했고, 이제 막 퇴근하려는데 전화가 왔어. 서비스가 이상하다는 거야. 넌 왜 ‘내 환경에선 잘 됐다’고 말했을까? 정말 책임을 회피하고 싶어서?”

솔라는 다시 생각에 잠겼다. 개발자의 입장이 되자 다른 풍경이 보였다. 수많은 테스트를 통과했고, 코드 한 줄 한 줄에 확신이 있었다. ‘내 코드 자체에는 논리적 오류가 없다’는 강한 믿음이 있었다.

“…아니, 꼭 그런 건 아닐 거야. 개발자 입장에서는 ‘내 코드의 로직은 문제가 없으니, 아마도 코드가 돌아가는 서버 환경이나 설정, 아니면 다른 쪽 문제일 것이다’라는 뜻으로 한 말이겠지. 내 책임 영역인 ‘코드 작성’은 끝났다는 선언이기도 하고.”

솔라의 말이 끝나자, 루나는 펜을 들어 메모지 위 ‘개발팀’ 아래에 ‘목표: 새로운 기능 빠르게 출시’라고 적었다. 그리고 ‘운영팀’ 아래에는 ‘목표: 서비스의 안정적인 운영’이라고 썼다.

두 개의 다른 목표가 분할선 양쪽에 명확히 자리 잡았다.

“바로 그거야. 이건 개인의 성격이나 태도 문제가 아니야. 두 팀이 서로 다른 ‘목표’를 가지고 있기 때문에 발생하는 구조적인 문제에 가까워.”

루나는 말을 이었다. “개발팀은 변화를 만들어야 인정받아. 새로운 기능을 빨리 시장에 내놓고, 고객의 요구에 신속하게 반응하는 게 그들의 가치지. 반면 운영팀은 변화를 잠재적인 위험으로 봐. 아무 일도 일어나지 않는 ‘안정성’ 그 자체가 그들의 핵심 가치고, 그걸로 평가받거든.”

루나는 메모지에 ‘가치: 변화, 속도’와 ‘가치: 안정성, 예측 가능성’을 추가로 적어 넣었다.

솔라는 두 개의 칸으로 나뉜 메모지를 멍하니 바라보았다. 개발팀과 운영팀. 같은 회사를 위해 일하지만, 마치 서로 다른 규칙이 적용되는 게임을 하고 있는 선수들 같았다. 한쪽은 골을 많이 넣어야 이기고, 다른 한쪽은 실점을 하지 않아야 이기는 게임.

“아…”

솔라의 입에서 작은 탄식이 흘러나왔다.

“개발팀은 액셀을 밟아야 칭찬받고, 운영팀은 브레이크를 밟아야 칭찬받는 구조였구나. 그러니 서로를 비난할 수밖에. 개발팀 눈에는 운영팀이 변화를 가로막는 걸림돌처럼 보일 거고, 운영팀 눈에는 개발팀이 시스템을 망가뜨리는 사고뭉치처럼 보였겠네. 이게 다 개인이 못돼서가 아니라, 처음부터 그렇게 설계된 판이었던 거야.”

‘벽’의 정체는 단순한 소통 부재나 감정의 골이 아니었다. 그것은 조직의 목표, 가치, 그리고 책임 소재가 명확하게 분리되어 만들어진 단단한 구조물이었다. ‘내 환경에선 잘 됐는데’라는 말은 그 구조의 균열이 드러나는 상징적인 외침일 뿐이었다.

솔라는 이제 그 벽이 왜 그렇게 높고 단단했는지 이해할 수 있었다. 그렇다면 이 근본적으로 다른 목표를 가진 두 팀을 어떻게 한 방향으로 나아가게 할 수 있을까?

“알겠어, 언니. 벽이 왜 생겼는지는 이제 확실히 알겠어. 개개인을 탓할 문제가 아니었네. 그럼 DevOps는 도대체 이 구조 자체를 어떻게 바꾼다는 거야? 그냥 ‘우리 이제부터 협력합시다!’ 하고 구호를 외치거나 회의만 늘린다고 해결될 문제가 아니잖아. 목표가 다른데.”

3장: 협력과 책임 공유로 ‘벽’을 허물다: DevOps의 문제 해결 방식

솔라의 시선은 테이블 위에 놓인 메모지에 못 박혀 있었다. 언니가 그어놓은 선명한 세로선. 그 선은 개발팀과 운영팀을 갈라놓는 단순한 경계를 넘어, 서로 다른 목표와 가치를 지닌 두 세계를 단절시키는 거대한 벽처럼 느껴졌다. 액셀을 밟아야 하는 팀과 브레이크를 걸어야 하는 팀. 이 구조적 모순을 어떻게 해결할 수 있단 말인가.

‘그냥 회의를 더 자주 하면 될까? 매일 아침 개발팀장과 운영팀장이 만나서 커피라도 마시면 좀 나아지려나?’ 솔라는 속으로 고개를 저었다. 그런다고 해서 개발팀의 목표가 ‘안정성’이 되거나, 운영팀의 목표가 ‘빠른 출시’가 될 리는 없었다. “우리 이제부터 협력합시다!” 구호를 외치는 건 공허한 메아리가 될 뿐이다. 근본적인 충돌은 그대로인데. 솔라의 미간에 깊은 주름이 잡혔다.

그 모습을 지켜보던 루나는 말없이 펜을 다시 들었다. 하지만 메모지에 무언가를 더 적는 대신, 펜 끝으로 개발팀과 운영팀 사이에 그어진 세로선을 가볍게 톡톡 두드렸다.

“이 벽을 허무는 가장 효과적인 방법은, 벽 너머를 볼 수 있는 ‘창문’을 다는 거야. 그것도 아주 크고 투명한 창문을, 양쪽에서 함께.”

루나는 솔라의 노트북 화면을 가리켰다. 거기에는 솔라가 며칠째 씨름하던 배포 자동화 스크립트가 떠 있었다.

“다시 한번 상상해보자. 네가 만든 완벽한 스크립트로 새 기능을 배포했고, 한 시간 뒤 서비스가 느려졌어. 그런데 이번에는 장애 알림이 운영팀에게만 가지 않아. 그 코드를 작성한 개발팀, 바로 너에게도 똑같은 알림이 온 거야. 그리고 너는 운영팀과 완전히 똑같은 모니터링 대시보드에 접속할 수 있어.”

“제가요? 운영 환경의 실시간 지표를요?”

솔라는 자신도 모르게 반문했다. 개발자가 운영 서버의 CPU 사용량, 메모리 점유율, 네트워크 트래픽을 직접 들여다보는 것은 흔한 일이 아니었다. 그건 운영팀의 ‘영역’이었으니까.

“그래. 네 화면에는 지금 어떤 데이터베이스 쿼리가 유독 많은 시간을 잡아먹고 있는지, 어떤 API 호출에서 응답 시간이 급증했는지 그래프로 선명하게 보이고 있어. 그걸 본 너는 뭐라고 말할까? 여전히 ‘제 컴퓨터에선 잘 됐는데요’라고 할 수 있을까?”

솔라는 잠시 눈을 감았다. 상상 속에서 그녀는 더 이상 자신의 방어적인 개발 환경 뒤에 숨어 있지 않았다. 운영팀 담당자와 나란히 서서, 불타고 있는 서비스의 계기판을 함께 보고 있었다. 화면 한구석에서 낯익은 함수 이름과 함께 치솟는 붉은색 그래프가 보였다. 바로 어제 자신이 추가한 코드 조각이었다.

입에서 탄식이 터져 나왔다. “아… ‘이거 제가 짠 코드 쪽 문제인 것 같네요. 이 쿼리가 이렇게 부하를 줄 줄은 몰랐어요. 일단 이전 버전으로 되돌리고 바로 수정하겠습니다.’ 라고 말하겠지.”

‘내 잘못’을 인정하는 차원이 아니었다. 더 이상 ‘내 문제’와 ‘네 문제’의 구분이 무의미해졌다. 눈앞에 있는 것은 그저 ‘우리의 문제’일 뿐이었다. 비난과 책임 전가는 사라지고, 문제의 원인을 가리키는 데이터만이 남았다.

“바로 그거야.”

루나가 말했다.

“DevOps가 벽을 허무는 방식은 구호나 회의가 아니야. ‘책임의 공유’를 통해 벽 자체를 무의미하게 만드는 거지. 그리고 그 책임 공유는 ‘도구와 정보의 공유’를 통해 가능해져. 개발팀과 운영팀이 같은 데이터를 보고, 같은 도구로 문제를 분석하고, 같은 목표(빠르고 안정적인 서비스)를 향해 움직이게끔 시스템을 설계하는 거야.”

솔라는 그제야 깨달았다. 1장에서 생각했던 ‘자동화’의 진짜 역할은 단순히 무언가를 빨리 던지는 게 아니었다. 오히려 이런 ‘공유된 창문’을 만들고, 양쪽 팀에 정보를 투명하게 전달하며, 문제가 생겼을 때 함께 대응할 수 있는 시스템을 구축하는 데 있었다. CI/CD 파이프라인, 통합 모니터링, 자동화된 테스트 같은 기술들은 모두 이 ‘공유 책임 모델’을 구현하기 위한 구체적인 방법론이었던 것이다.

솔라의 머릿속에서 스터디 자료의 첫 문장이 다시 떠올랐다. 하지만 이번에는 전혀 다른 무게로 다가왔다.

DevOps는 개발(Development)과 운영(Operations)의 합성어로, 개발팀과 운영팀이 협력하여 소프트웨어를 더 빠르고 안정적으로 개발, 배포, 운영하기 위한 조직 문화와 방법론이다.

‘협력하여’는 막연한 구호가 아니었다. ‘운영하기 위한’이라는 말은 더 이상 운영팀만의 일이 아니었다. 개발자가 운영 지표에 책임을 지고, 운영팀이 개발 초기 단계부터 참여하는 것. 그것이 바로 DevOps의 문화이자 방법론이었다.

솔라는 고개를 들어 자신의 노트북 화면을 바라보았다. 복잡하게만 보였던 배포 스크립트가 이제는 다르게 보였다. 이것은 단순히 일을 편하게 만드는 도구가 아니었다. 개발팀과 운영팀을 연결하고, 서로의 세계를 비추는 ‘창문’을 만드는 첫걸음이 될 수도 있었다.

“알겠다… 우리 팀 다음 주 회의 때, 배포 자동화만 이야기할 게 아니었어.”

솔라는 결심한 듯 입을 열었다.

“장애가 났을 때 개발팀이랑 운영팀이 같이 볼 수 있는 통합 대시보드를 만들자고 제안해봐야겠다. ‘누구 잘못인가’를 따지는 회의 대신, ‘어디가 아픈가’를 다 같이 볼 수 있는 창문을 만드는 것부터 시작하자고.”