네트워크 애플리케이션 성능은 Latency(지연 시간), Bandwidth(대역폭), 그리고 모바일 기기에서의 전력 소모라는 세 가지 주요 요소로 나눌 수 있다. HTTP/2와 HTTP/3는 기존 HTTP/1.1의 한계를 극복하기 위해 설계되었으며, 각 프로토콜이 이러한 성능 측면에서 어떻게 개선되었는지 살펴보자.

 

HTTP/2: Multiplexing과 Header 압축을 통한 효율성[1]

  • Multiplexing: HTTP/1.1은 하나의 연결에서 하나의 요청-응답만 처리할 수 있는 문제점(Head-of-Line Blocking)을 가지고 있다. HTTP/2는 단일 TCP 연결에서 여러 요청과 응답을 동시에 처리할 수 있도록 개선하여 Latency를 크게 줄였다.
  • Header Compression: HTTP/2는 HPACK을 사용하여 헤더를 압축한다. 이는 반복적인 헤더 전송에 소요되는 Bandwidth를 절약하는 데 유리하다.
  • Push Promise: 서버에서 클라이언트가 요청하지 않은 리소스를 미리 전송할 수 있는 HTTP/2의 기능으로 페이지 로드 속도를 향상시킨다.

HTTP/3: UDP 기반의 QUIC 프로토콜로 Latency 최적화 [3]

  • UDP 기반: HTTP/3는 TCP 대신 QUIC(Quick UDP Internet Connections) 프로토콜을 기반으로 설계되었습니다. QUIC는 연결 설정 속도가 빠르고 패킷 손실에도 연결이 유지되므로 Latency를 최소화한다.
  • TLS 통합: QUIC는 TLS 1.3을 통합하여 보안을 강화하면서도 연결 수립 단계를 줄여 초기 Latency를 줄인다.
  • 멀티플렉싱 개선: HTTP/2는 단일 TCP 연결에서 발생하는 Head-of-Line Blocking 문제를 해결했지만, TCP 수준에서 여전히 동일한 문제가 발생했다. HTTP/3는 QUIC을 통해 이 문제를 해결하였다.
  • 모바일 기기 친화적: 모바일 환경에서 네트워크 변경(예: Wi-Fi에서 LTE로 전환) 시 연결을 유지할 수 있어 전력 소모와 재연결 Latency가 줄어든다.

 

성능 측면 분석

  1. Latency
    • HTTP/2: TCP의 3-way handshake로 인한 초기 연결 지연이 존재.
    • HTTP/3: QUIC의 0-RTT Handshake로 초기 연결 Latency 최소화.
  2. Bandwidth
    • HTTP/2: 데이터 압축 및 멀티플렉싱으로 대역폭 효율 증가.
    • HTTP/3: 패킷 재전송 감소와 멀티플렉싱으로 Bandwidth 활용 최적화.
  3. 전력 소모
    • HTTP/2: 다수의 연결 유지 시 전력 소모가 증가 가능.
    • HTTP/3: 네트워크 변화 시 연결을 유지하므로 전력 소모 감소.

 

모바일 환경에서의 성능 최적화

  • HTTP/2HTTP/3 모두 모바일 친화적인 특성을 가지지만, HTTP/3는 특히 고속 네트워크 변경 및 불안정한 환경에서 강력한 성능을 제공한다.
  • QUIC의 효율성 덕분에 스트리밍 및 게임 같은 애플리케이션에서 HTTP/3 채택이 증가하고 있다.

참고자료

[1] IETF RFC 7540, https://datatracker.ietf.org/doc/html/rfc7540

[2] IETF RFC 9000, https://datatracker.ietf.org/doc/html/rfc9000

 

 

 

웹을 이루는 수많은 기술 중에서 진짜 뼈대라 할 수 있는 것이 바로 HTTP이다. 브라우저에서 URL을 입력하면 그 뒤에서 움직이는 가장 핵심적인 프로토콜이 이 HTTP이다. HTTP가 어떻게 발전해 왔는지, 왜 계속 진화해야 했는지를 살펴보자.

1. HTTP 0.9: 한 줄로 시작된 혁명

1991년 팀 버너스 리가 만든 HTTP 0.9는 믿기 어려울 만큼 단순했다.

  • 클라이언트는 단 한 줄짜리 요청(GET /index.html)을 보냄
  • 서버는 HTML 문서만 반환
  • 헤더도 없고, 연결도 요청마다 끊김

지금 관점에선 너무 부족해 보이지만, 이 단순함 덕분에 웹이 빠르게 확산될 수 있었다. 흥미로운 건 아직도 telnet 명령으로 HTTP 0.9 방식 요청을 실험해볼 수 있다.

2. HTTP 1.0: 웹 대중화의 기반

1990년대 초, 모자익(Mosaic) 브라우저의 등장과 함께 HTTP는 대중에게 본격적으로 노출되기 시작했다. 이 시점에 등장한 HTTP 1.0은 다음과 같은 변화가 있었다.

  • 요청/응답에 헤더가 추가됨 (User-Agent, Content-Type 등)
  • 다양한 MIME 타입 지원
  • 여전히 요청마다 연결을 끊는 구조

RFC 1945로 정리되긴 했지만, 이건 공식 표준이라기보단 ‘정보 제공용 문서(Informational)’였다. HTTP 1.0의 가장 큰 한계는 매번 새로운 TCP 연결을 생성해야 한다는 점이다. 느린 시작(slow start)과 3-way 핸드셰이크 비용을 생각하면, 성능 측면에서 효율적이지 않았다.

3. HTTP 1.1: 커넥션 재사용으로의 전환

1997년 등장한 HTTP 1.1은 웹 성능을 획기적으로 끌어올린 버전이다. 핵심은 ‘Keep-Alive’를 기본으로 채택했다는 점이다.

주요 기능:

  • Persistent Connections (기본적으로 연결 유지)
  • Chunked Transfer-Encoding (스트리밍 전송 지원)
  • Pipelining (연속 요청)
  • 캐시 제어 및 콘텐츠 협상

여기서부터 웹은 단순한 텍스트 문서를 넘어서 하이퍼미디어 전송 플랫폼으로 진화하기 시작했다. 이미지, 동영상, 다양한 언어와 문자셋, 쿠키 기반 상태 관리 등도 이때 본격적으로 쓰이기 시작했다.

4. HTTP/2: 성능 재도약

웹의 무게가 점점 더 커지자, HTTP/1.1으로는 버티기 힘든 시대가 왔다. 그래서 2012년, HTTPbis 워킹 그룹이 HTTP/2 개발을 시작했다.

HTTP/2의 목표:

  • 낮은 레이턴시
  • 높은 처리량
  • 기존 애플리케이션 수정 없이도 적용 가능

핵심은 단일 TCP 연결에서 멀티플렉싱을 지원한다는 것이다. 즉, 하나의 연결 안에서 동시에 여러 리소스를 주고받을 수 있으니 브라우저가 더 빠르고 효율적으로 동작할 수 있게 된다.

기존의 요청-응답 구조는 그대로 유지하면서 내부 전송 방식만 개선한 것이 특징이다. 덕분에 기존 서버나 클라이언트는 큰 수정 없이 HTTP/2의 이점을 누릴 수 있다.

 

정리하며: 왜 이걸 알아야 할까?

소프트웨어 아키텍처나 멀티미디어 서비스 설계를 고민할 때, 전송 계층의 성능은 전체 사용자 경험에 지대한 영향을 끼쳐. 특히 아래와 같은 상황에서 HTTP의 동작 원리를 이해하는 게 중요하다.

  • CDN 및 캐시 정책 설계
  • 스트리밍 서비스 아키텍처 구축
  • 모바일/저지연 환경에서의 콘텐츠 전송 최적화
  • SPA나 모바일 앱의 백엔드 API 호출 구조 설계

HTTP의 역사는 단순한 기술 진화가 아니라, 사용자 경험을 최적화하고자 하는 노력의 결정체이다. 브라우저 네트워킹을 이해하는 건, 결국 우리가 만드는 서비스의 퍼포먼스를 좌우하는 핵심이 된다고 볼 수 있다.

참고문헌

[1] 일리아 그리고릭, "구글 엔지니어에게 듣는 네트워킹과 웹 성능 최적화 기법", 정해권, 오현주 공역, 인사이트(insight)

모바일 네트워크는 우리가 스마트폰을 사용하는 방식, 그리고 모바일 앱이 동작하는 근본 구조에 지대한 영향을 준다. 특히 5G는 단순한 속도 향상을 넘어, 완전히 새로운 가능성과 도전을 함께 가져왔다. 이번 글에서는 모바일 네트워크의 진화를 간단히 짚어보고, 5G의 핵심 목표와 모바일 앱 관점에서 꼭 알아야 할 특징을 정리해보자.

5G의 핵심 목표: Speed, Coverage, Connectivity

5G의 비전은 단순히 "더 빠르게"가 아니다. 다음 세 가지 목표가 중심이다:

  • Speed: 최고 속도 10Gbps 이상을 목표로 하며, 4G보다 최대 100배 빠르다. 이는 고해상도 영상 스트리밍, AR/VR 같은 애플리케이션을 실시간으로 가능하게 한다.
  • Coverage: 기존보다 훨씬 넓은 커버리지를 확보하고, 밀집 지역에서도 연결 품질을 유지할 수 있도록 설계되었다.
  • Connectivity: 단말 간 연결 수용량이 폭발적으로 늘어난다. 자율주행차, IoT 센서, 웨어러블 기기들이 동시에 연결되어도 문제없도록 하는 것이 핵심이다.

모바일 애플리케이션 개발 관점에서의 5G 특징

모바일 앱을 개발하거나 서비스를 설계하는 입장이라면, 5G 환경에 맞는 접근이 필요하다. 다음은 중요한 특징이다:

전력 효율과 RRC 상태 관리

5G에서는 4G와 유사하게 연결 상태를 관리한다.

  • 스마트폰은 항상 네트워크와 연결되어 있는 WiFi와는 달리, 필요할 때만 연결되는 무선 특성이 있다.
  • RRC(Radio Resource Control)는 데이터 전송 시에만 라디오 리소스를 할당함으로써 전력 소모를 줄인다.
  • 따라서 앱에서 데이터를 계속 조금씩 보내는 것보다, 몰아서 한 번에 전송하는 전략이 배터리 효율에 유리하다.

네트워크 지연(latency) 고려

  • 5G의 초저지연(1ms 이하)은 클라우드 게임, 원격 제어, 라이브 인터랙션 앱에서 핵심 자산이다.
  • 하지만 사용자의 위치나 단말 상태에 따라 RRC 연결 전환 지연이 여전히 발생할 수 있으므로, 앱은 이를 고려한 버퍼링, 프리로드 전략이 필요하다.

5G와 엣지 컴퓨팅(Edge Computing)의 만남

5G의 등장은 단지 네트워크 속도를 높이는 것을 넘어, 엣지 컴퓨팅(Edge Computing)과 결합해 새로운 컴퓨팅 패러다임을 만들어내고 있다. 특히 모바일 앱과 서비스가 요구하는 초저지연, 대용량 데이터 처리, 프라이버시 보호 같은 요소들이 엣지 컴퓨팅과 만날 때 큰 시너지를 낸다.

엣지 컴퓨팅이란?

엣지 컴퓨팅은 데이터를 사용자와 가까운 곳, 즉 "네트워크의 엣지(edge)", 예를 들어 기지국, 지역 서버, 또는 사용자 디바이스 근처의 마이크로 데이터 센터에서 처리하는 방식이다.

  • 기존에는 모든 요청이 중앙 클라우드로 갔기 때문에, 거리로 인한 지연(latency)이 발생했고,
  • 대역폭 소모도 컸으며,
  • 개인정보 보호 측면에서도 이슈가 있었다.

엣지 컴퓨팅은 이런 문제를 해결하며 실시간성과 효율성을 동시에 해결한다.

왜 5G와 엣지는 함께 가야 할까?

앞에서 이야기 한 것과 같이 5G는 이론적으로 1ms 이하의 초저지연, 기가비트급 전송속도, 1㎢당 100만 개 이상의 단말 수용을 목표로 한다. 그러나, 이 모든 걸 제대로 실현하려면 데이터가 중앙이 아닌 로컬에서 처리될 수 있어야 한다. 즉, 엣지 컴퓨팅 없이는 5G의 약속도 절반의 구현에 불과할 수 있다.

[2] Edge Computing 사례

 

 

모바일 애플리케이션에서의 활용 사례

클라우드 게임 스트리밍

  • 지연이 중요한 FPS 게임, 레이싱 게임은 5G만으로도 부족할 수 있다.
  • 사용자 근처의 엣지 서버에서 게임 데이터를 렌더링하고 스트리밍하면,
    • 조작 반응 속도(입력 ↔ 반응)가 현격히 줄어든다.
    • 실제로 Xbox Cloud Gaming, NVIDIA GeForce Now 등은 엣지 인프라를 적극 활용 중.

자율주행차와 스마트 시티

  • 차량의 위치, 속도, 도로 상황 등의 데이터가 엣지에서 처리됨으로써,
    • 교통 신호와 차량 간 실시간 협업이 가능해짐.
  • 스마트 시티에서는 CCTV, 센서 데이터를 엣지에서 실시간 분석하여 교통 제어, 범죄 예방 등에도 활용.

VR과 Edge Computing

  • 클라우드까지 왕복하는 방식은 보통 50~100ms 이상의 지연이 발생할 수 있으나, VR은 일반적으로 20ms 이하의 지연 시간을 유지해야 자연스럽고 어지럽지 않은 경험을 제공할 수 있다.
  • 8K 또는 16K 영상이 필요한 VR 콘텐츠는 데이터 용량이 매우 크다. 이걸 모바일 기기가 직접 처리하거나 원거리 클라우드에서 처리하면 부하가 크고, 지연이 생길 수 있다. 엣지에서 영상 렌더링을 처리하면, 최소한의 전송으로 최적의 영상 품질 제공이 가능하다.
  • VR 헤드셋이나 스마트폰의 연산 능력은 제한적이다. GPU 렌더링, 딥러닝 기반 공간 인식 등을 엣지에서 처리하면, 기기 발열과 배터리 소모도 크게 줄일 수 있다.

앱 개발자가 고려해야 할 점

  • 엣지 환경에 맞춘 API 및 서비스 설계가 필요하다. 예: Google Cloud’s Anthos, AWS Wavelength, Azure Edge Zones[3]
  • 네트워크 지연, 연결 품질이 변수가 될 수 있기 때문에, fallback 전략(엣지 → 클라우드 대체)이 있어야 한다.
  • 데이터 처리 위치를 사용자의 동의에 따라 동적으로 제어하는 기능도 점점 중요해진다.

정리

모바일 네트워크는 단순한 "통신 기술"이 아니라, 사용자 경험과 모바일 생태계를 뒤흔드는 근본 인프라다. 5G의 등장은 단지 더 빠른 유튜브 로딩을 의미하는 게 아니다. 그것은 개발자에게는 전혀 다른 설계 철학, 사용자에게는 새로운 서비스의 경험을 뜻한다. 특히, 엣지 컴퓨팅은 5G와 결합하여 단순히 속도를 높이는 것이 아니라, 네트워크를 유연하게, 그리고 스마트하게 만든다. 이제 중요한 것은 어디에서 데이터를 처리하느냐다. 사용자와 가까운 엣지에서 처리함으로써 얻는 이점은 앞으로의 모바일 앱과 서비스에 있어서 경쟁력을 좌우할 핵심 요소가 될 것이다.

참고 자료

[1] High Performance Browser Networking: Ch 07 모바일 네트워크, https://technical-leader.tistory.com/171

[2] Edge Computing Helps 5G Networks: A Practical Guide to Optimising Campus Network Architecture, https://community.fs.com/article/edge-computing-helps-5g-networks-a-practical-guide-to-optimising-campus-network-architecture.html

[3] AWS Wavelength 소개, https://aws.amazon.com/wavelength/

 

 

요즘 모바일 앱을 개발하다 보면 "왜 이렇게 느리지?" 혹은 "배터리 너무 빨리 닳는데?"가 주된 고민이다. 사실 이건 단순히 코드나 UI 문제가 아니라, 모바일 네트워크 자체가 갖고 있는 특성과 한계에서 비롯된 문제라고 할 수 있다. 여기서는 모바일 네트워크 최적화를 위한 진짜 핵심을 다룬 내용[1]을 정리해 보자.

배터리, 네트워크, 프레젠테이션 – 무시할 수 없는 세 가지 제약

모바일 앱을 만들 때 우리가 가장 많이 신경 쓰는 게 아마 반응형 디자인일 것이다. 그런데 네트워크 구조와 배터리 사용에 대한 이해가 부족하면, 아무리 멋진 UI를 만들어도 실사용자에겐 ‘답답한 앱’으로 느껴질 수 있다. 중요한 건 세 가지를 균형 있게 고려하는 것이라 할 수 있다.

  • 프레젠테이션: 작은 화면 안에 어떻게 정보를 전달할지
  • 네트워크 성능: 레이턴시, 처리량
  • 배터리 수명: 무선 전파 사용 최소화

이 중 하나라도 무시하면 전체 경험이 망가질 수 있다..

배터리를 아끼는 네트워크 설계법

모바일 네트워크에서 배터리를 아끼는 건 사용자를 포함한 모든 이해관계자의 관심사이다. 이를 위해서 우리가 고려해야 할 건 다음과 같다.

  • 무선 전파가 배터리 소모의 주범이라는 점
  • 데이터 크기와 무관하게, 전파를 켜는 순간 에너지를 소비한다는 점
  • 폴링보다 푸시가 효율적이라는 점

즉, 자잘한 데이터를 자주 보내는 방식은 최악이다. 가능하면 다음처럼 접근해야 한다.

  • 데이터를 묶어서 보내기
  • 네트워크 상태가 활성화됐을 때 전송 몰아서 처리하기
  • 중요도 낮은 요청은 연기하거나 합치기

예를 들어, Android의 Google Cloud Messaging(GCM)은 기기가 활성화됐을 때만 메시지를 전달한다. 이런 최적화는 상당히 효과적이다.

RRC 상태와 레이턴시를 고려하라

모바일 네트워크의 RRC(Radio Resource Control) 상태는 앱에서 전혀 제어할 수 없는 부분이지만, 레이턴시에 어마어마한 영향을 미친다. LTE에서도 첫 패킷 전송을 위해 수백 ms의 추가 지연이 생기고, 3G에서는 수초까지도 걸린다. 그래서 앱 설계 시에는 다음을 고려해야 한다.

  • 사용자 인터랙션과 네트워크 요청을 분리하기
  • 즉각적인 UI 피드백 제공 후 백그라운드에서 처리
  • 프리페치(prefetch)와 캐시 전략 활용

점진적 로딩 vs 몰아서 전송

모바일에서는 점진적 로딩이 항상 좋은 건 아니야. 무선 전파가 자주 활성화되면 배터리 소모는 기하급수적으로 커지고, 레이턴시는 늘어난다. 대신 다음과 같은 전략이 유리하다.

  • 콘텐츠를 예측해서 미리 다운로드
  • 여러 요청을 한 번에 전송
  • 유휴 상태를 최대한 활용

예를 들어, 음악 스트리밍 앱이라면, 노래를 소량씩 계속 스트리밍하는 것보다는 곡 전체를 한 번에 다운받는 게 전력 효율에 훨씬 좋다.

실패를 기본값으로 생각하라

모바일 네트워크는 언제나 불안정하다. 연결이 갑자기 끊길 수도 있고, 처리량이나 레이턴시가 들쭉날쭉할 수도 있다. 그래서 다음을 반드시 고려해야 한다.

  • 요청 실패 시 재시도 로직
  • 오프라인 모드 고려
  • 상태 저장 및 로컬 캐시 사용

요즘은 HTML5의 AppCache나 IndexedDB를 활용해서 오프라인 UX도 나쁘지 않게 만들 수 있다.

WiFi로 넘겨라

가능하면 사용자에게 WiFi를 쓰도록 유도하는 것도 하나의 전략이다. 무선 전파보다 WiFi가 배터리에도 덜 부담되고, 처리량도 안정적이다. 특히 대용량 콘텐츠를 다룰 땐 필수이다.

 

마치며 – “적게, 빠르게, 한 번에”

모바일 네트워크는 PC와 달라. 예측 불가능한 네트워크 품질, 제어할 수 없는 레이턴시, 에너지 테일 이 모든 요소가 얽혀 있다. 그래서 우리의 전략은 단순해져야 한다.

적게 보내고, 빠르게 받고, 한 번에 끝내라

이게 바로 고성능 모바일 네트워킹의 핵심이다. 

 

참고문헌

[1] 일리아 그리고릭, "구글 엔지니어에게 듣는 네트워킹과 웹 성능 최적화 기법", 정해권, 오현주 공역, 인사이트(insight)

모바일 네트워크의 진화와 그 영향

모바일 네트워크는 빠른 속도로 진화하고 있으며, 이는 사용자 경험과 웹 성능에 직접적인 영향을 미친다. 2013년 기준으로 전 세계에는 약 64억 개의 모바일 연결이 있으며, 이 숫자는 계속 증가할 것으로 예상된다. 이러한 성장은 소비자들의 스마트 기기에 대한 욕구가 크다는 것을 의미한다. 하지만 단순히 연결된 기기의 수만 늘어나는 것이 아니라, 이들 기기를 지원하기 위한 고속 인터넷과 유비쿼터스한 광역 무선 연결의 수요도 함께 증가하고 있다.

세대별 무선 네트워크 기술의 발전

모바일 네트워킹 기술은 GSM, CDMA, HSPA 그리고 LTE와 같은 몇 가지 주요 무선 기술로 구성되어 있다. 예를 들어, 1G는 데이터를 지원하지 않는 아날로그 시스템이었고, 2G는 최초의 디지털 시스템이 도입된 시점이다. 3G와 4G는 각각 향상된 데이터 전송 속도를 제공하며, 특히 4G는 데이터 전송 속도가 기가비트급에 이른다. 그러나 '최대' 데이터율은 이상적인 환경에서만 가능한 수치임을 명심해야 한다. 여기서는 5G 나오기 전까지의 책이어서 포함되어 있지 않다.

3GPP와 3GPP2 표준의 진화

3GPP와 3GPP2는 각기 다른 경로로 표준을 발전시켜 왔다. 3GPP는 유럽의 GSM을 기반으로 UMTS와 LTE 표준을 개발했으며, 3GPP2는 미국의 CDMA2000 기술을 기반으로 표준을 발전시켰다. 이렇게 다른 기술 기반의 두 표준이 따로 발전해 오다가 파트너십을 가지고 진행하였고, LTE 부터는 통합 표준을 만들기 시작했다. 이러한 표준들은 사용자 장비의 성능에 따라 다양한 성능을 제공하며, 네트워크마다 지정된 사용자 장비 카테고리의 요건을 충족시켜야 최상의 성능을 발휘할 수 있다.

프로토콜의 개요

Radio Resource Controller (RRC)는 3G/4G의 유니크한 기능으로 무선 기기와 기지국 사이의 연결을 관리하는 기능이다.

Radio Resource Controller (RRC)



WiFi와 Ethernet는 항상 네트워크와 연결되어 있다고 본다. 그러므로 무선 기기 혹은 다른 쪽에서도 항상 패킷을 전송할 수 있고, 지연시간(latency)를 최적화 하기 용이하다. 그럼에도 불구하고 전송 매체를 공유하기 때문에 예상하지 못한 패킷 충돌로 인해 성능 저하가 발생할 수 있다. 그리고, 네트워크가 항상 켜져 있기 때문에 파워 소모가 높을 수 있어서 무선 기기의 배터리 효율이 중요한 최적화 요소가 되기도 한다.

이러한 측면에서 RRC는 네트워크 효율적인 사용과 무선 전력 소모를 효과적으로 할 수 있다. 즉, 전송할 데이터가 있는 경우에만 무선 자원(radio resource)를 할당하도록 한다. 거꾸로 수신할 데이터가 있는 경우에도 유사한 과정을 통해서 연결되게 된다.

스마트폰과 같은 무선 기기의 경우, 대형 화면이 가장 큰 전력 소모를 하는 모듈이다. 그 다음이 WiFi 혹은 무선 네트워크 연결과 같은 모듈이다. 그렇기 때문에, 이 무선 모듈을 항상 켜 놓는 것은 무선 기기에게 적절한 해결책이 아니다. 그러므로, 데이터를 전달해야 하지 않는 경우에는 무선 자원을 끊고 데이터 전송이 필요한 경우에만 무선 자원을 사용하는 것이 효과적이다. RRC는 이러한 동작을 수행하는 중추적인 역할을 한다.

RRC 상태 설명

RRC Idle은 저전력 상태이다. 이 때에는 모바일 기기를 컨트롤 하는 작은 메시지만 수신하고 데이터 전송을 위한 라디오 리소스는 할당이 되어 있지 않은 상태이다. 실재로 데이터를 전송해야 하는 상황이 되면 몇번의 컨트롤 메시지 교환을 통해서 라디오 리소스가 할당된다.

RRC Connected가 되면 실재로 많은 데이터 량을 전송하는 상태(State)로 많은 배터리를 소모한다. 데이터를 송신하거나 수신하기 위해 기다립니다. 지정된 라디오 리소스(dedicated radio resource)가 할당되게 되어 있다.

Shrt DRX(Discontinous Reception) 상태는 네트워크의 연결 컨택스트와 네트워크 리소스 할당은 해 놓은 상태로 조금 더 빠르게 다시 네트워크와 연결 상태가 될 수 있다. 이와는 다르게 Long DRX의 경우는 연결 컨텍스트는 유지하지만, 리소스는 해제하여 연결의 시간을 줄이지만 리소스를 다른 곳에 할당하여 전송 효율을 높일 수 있다. 아래 그림과 같이 단말은 모니터링 해야 하는 슬롯을 줄여서 사용 전력을 절약할 수 있다.

LTE RRC State Machine



이러한 모바일 네트워크의 특징을 참고한다면 데이터를 뜨문뜨문 보내게 되면 빈번한 연결 동작을 요구하게 되어 지속적으로 베터로 소모가 많을 수 있다. 그러므로 데이터를 몰아서 보내고 수신하는 방법을 사용하는 것이 배터리 소모에는 효과적일 수 있다. 즉, 아래 그림에서 데이터 전송 구간(Data Transfer)을 하나로 몰아서 추가적으로 소모 될 수 밖에 없는 구간(energy tail)이 발생하는 것을 줄일 수 있다면 효과적일 수 있다.

 

결론

모바일 네트워크의 미래는 밝지만, 그 도달에는 여러 도전이 따른다. 기술적 장벽과 높은 비용은 모바일 네트워킹의 발전을 어렵게 만들 수 있다. 하지만 기술이 진화함에 따라 사용자 경험은 향상되고, 웹 성능은 최적화될 것이다. 이러한 변화를 이해하고 준비하는 것이 중요하다.

 

참고 문헌

[1] 일리아 그리고릭, "구글 엔지니어에게 듣는 네트워킹과 웹 성능 최적화 기법", 정해권, 오현주 공역, 인사이트(insight)

[2] High Performance Browser Networking Ch7 Ch8, https://docs.google.com/presentation/d/17UMWZ8V_CcBBTaqg50Ug_yvB2csL9SB_QgoPlniFoqo/edit?usp=sharing

오늘날 디지털 시대에 WiFi는 기술 발전의 증거로서, 우리 일상에 자연스럽게 통합되어 있다. WiFi의 여정은 1997년 802.11 프로토콜로 시작되었지만, 1999년 802.11b 표준이 도입된 후에야 WiFi 기술이 진정으로 발전하기 시작했다. 이 기술은 기존 로컬 영역 네트워크를 무선으로 확장할 수 있는 간단하고 저렴한 수단을 제공한다.

WiFi 표준의 진화

WiFi는 Ethernet에 무선을 고려하며 만들어져서 아래 그림과 같이 L1, L2의 표준화를 통해서 이루어 졌다. 이로 인해 Ethernet의 Carrier Sense Multiple Access (CSMA), 즉 공유 채널을 사용하는지 확인하는 것은 동일하게 사용한다. Ethernet의 경우는 Collision Detection 즉, CSMA를 하지만 보낼 수 있으면 바로 보내고 다른 쪽과 충돌이 발생하면 Random한 Interval을 가지고 다시 시도하는 반면, 무선은 CSMA를 하지만 Collision Avoidance를 하기 위해서 채널이 비어 있는 상황에서만 시도하는 방식을 사용한다.

 

Ehternet과 WiFi

 

WiFi 기술은 누구나 접근할 수 있고 비용 효율적인 비허가 ISM 스펙트럼에서 운영된다. 802.11b에서 802.11ac와 같은 더 정교한 프로토콜로의 진화는 지속적으로 높은 처리량과 고급 변조 기술을 추구함으로써 WiFi 성능을 크게 향상시켰다.

 

802.11 표준 가족은 802.11b부터 802.11n, 802.11ac에 이르기까지 다양한 기능을 제공하며, 이는 우리의 증가하는 데이터 전송 요구를 충족하기 위해 설계되었다. 이 표준들은 점진적으로 20MHz에서 최대 160MHz까지 대역폭을 확장하고 MIMO 기술을 도입하여 WiFi를 단순한 연결 옵션에서 강력한 네트워크의 중추로 전환시켰다.

WiFi 문제 극복

그럼에도 불구하고, WiFi는 특히 여러 네트워크가 겹치는 밀집된 도심 환경에서 많은 도전에 직면해 있으며, 이는 혼잡과 성능 저하로 이어진다. WiFi를 쉽게 배포할 수 있는 매우 단순함이 오히려 취약점을 초래하기도 하며, 간섭 및 예측 불가능한 네트워크 부하와 같은 문제를 포함한다.

 

WiFi는 대역폭이나 지연 시간을 보장하지 않으며, 그 성능은 주변 환경에 크게 좌우된다. 802.11n 표준의 프레임 집약과 802.11ac의 5GHz 대역 적응과 같은 혁신이 일부 문제를 완화했지만, 공유 채널 접근과 간섭의 근본적인 도전은 여전히 남아 있다.

 

WiFi의 채널 사용 특성

WiFi 사용 최적화

WiFi 배포를 이해하고 최적화하는 것은 애플리케이션 성능을 크게 향상시킬 수 있다. 예를 들어, 혼잡하지 않은 대역에서 다른 사용이 확인되지 않은 대역폭을 활용하거나 가변 대역폭을 사용하는 것은 서비스 중단을 방지하고 사용자 경험을 향상시킬 수 있다.

 

데이터 집약적 애플리케이션에 대해 WiFi 오프로딩과 같은 전략을 사용하면 네트워크 리소스를 효율적으로 사용하면서 성능을 유지하고 셀룰러 네트워크를 통한 데이터 전송과 관련된 비용을 최소화할 수 있다.

미래 방향

앞으로 WiFi 표준과 지속적인 개선이 필수적일 것이다. 서비스 품질을 애플리케이션 수준에서 향상시키는 혁신과 공유 네트워크 리소스의 관리 방법이 WiFi의 다음 단계를 정의할 것이다.

 

결론적으로, WiFi가 우리 네트워크 인프라의 핵심 요소가 되었지만, 그 복잡성을 이해하고 전략적으로 관리하는 것이 그 잠재력을 진정으로 활용하기 위해 필요하다. 더 연결된 미래를 향해 나아가면서, WiFi의 역할은 의심할 여지 없이 확장될 것이며, 우리가 서로 연결된 세계의 증가하는 요구를 충족하기 위해 더욱 정교한 솔루션을 요구할 것이다.

참고자료

[1] 일리아 그리고릭, "구글 엔지니어에게 듣는 네트워킹과 웹 성능 최적화 기법", 정해권, 오현주 공역, 인사이트(insight)

[2] High Performance Browser Networking Ch5 Ch6, https://docs.google.com/presentation/d/1WCDXTVjy9hoou3Ehjz-meoZQUJoPEjc-hGLCPGOkh3M/edit?usp=sharing

들어가며..

최근에 Vibe Coding [1,2] 이라는 이야기가 많이 회자되고 있다. 개발자는 구조나 Product에 집중하고 실재 코딩 작업은 LLM에 맞기는 것이라고 한다. VSCode에 통합되어 있는 AI도구인 Cursor에서는 Agent[3]라는 제품도 나와서 이러한 트렌드를 더 가속화 하는 것으로 보인다. Cursor가 이미 IDE와 결함되어 있고, Agent 그리고 Ask 기능을 이미 제공하고 있기 때문에 여기서 설명하는 내용이 이미 필요 없을 수 있다. 하지만, Cursor를 사용하지 않고도 가능하다고 하면 Cursor를 사용하지 못하기 때문에 AI 도구를 이용해서 효과를 내지 못하는 것은 아니라는 것의 반증이기도 할 것 같다.

나의 사례

여기서 다루려는 내용은 아래 내용으로 나누어 볼 수 있다.

  1. 기존에 존재하는 코드를 이해하고 
  2. 우리가 원하는 기능을 어떻게 구현할지 결정하고
  3. 구현하는 코드를 만들어 적용

 

1번은 우리가 이미 구현하고 있는 Android App기준으로 이 부분은 다른 사례에 적용한다면 개발 환경에 따라 다를 수 있을 것 같다. 이 Android App에 대해 분석하는 예는 따로 설명한다[4]. 2번 부터 3번까지의 경우, Android App 기준으로 하나의 예를 가지고 따라가 보자. 물론 상황에 따라 다를 수 있음을 이해하자.

원하는 기능의 구현

이 부분은 필자의 사례이므로 상황에 따라 많이 다를 수 있다. 우리는 사용자가 특정 기간 동안 다른 동작을 해서 주의가 산만해 지는 것을 확인하기 위해 휴대폰에서 특정 앱을 사용하는 것을 모니터링 하는 것을 구현하려고 했다. 이와 관련해서 ChatGPT에 Prompting해 본 결과 중 일부를 살펴 보자.

Prompt: 너는 pytorch 및 tensorflow의 전문가이고, 동영상 처리에 대한 전문가야. Android에 대해서도 잘 알고 있는 전문가야. 휴대폰의 사용자가 휴대폰 사용하는 동안 어떤 어플리케이션을 사용하고 있는지 알아 내는 모듈을 개발하려고해. 이를 알아내는 방법을 여러가지 제안해줘

ChatGPT said:  (7가지를 이야기 했지만, 아래 3가지만 추출)
휴대폰에서 사용자가 어떤 애플리케이션을 사용하는지 알아내는 모듈을 개발하려면 아래와 같은 여러 가지 접근 방법을 고려할 수 있습니다. 각 접근법은 기술적인 제약, 성능, 그리고 보안 문제를 고려해야 합니다.

 

1. Accessibility Services 활용
- 방법: Android의 접근성 서비스(Accessibility Service)를 이용하면 사용자가 현재 활성화된 앱과 상호작용하는 내용을 감지할 수 있습니다.
- 장점: 사용자가 상호작용하는 앱에 대한 정보를 비교적 간단하게 가져올 수 있습니다.
- 단점: 사용자 동의가 필요하며, 민감한 정보를 처리하기 때문에 오용 시 보안 문제가 발생할 수 있습니다.
- 구현:
    1. `AccessibilityService` 클래스 구현.
    2. `onAccessibilityEvent` 메서드에서 앱 사용 데이터를 수집.

 

2. UsageStatsManager 활용
- 방법: Android의 `UsageStatsManager` API를 사용하여 최근에 사용된 애플리케이션 목록 및 사용 시간을 가져올 수 있습니다.
- 장점: 시스템 API를 사용하므로 안정적이고 공식적인 접근 방식.
- 단점: 사용자에게 Usage Access 권한을 별도로 요청해야 합니다.
- 구현:
    1. `UsageStatsManager` 인스턴스 생성.
    2. `queryUsageStats` 메서드로 주어진 기간 동안 사용된 앱의 데이터를 수집.

 

3. Foreground Service 및 Activity Recognition API
- 방법: 포어그라운드 서비스와 Activity Recognition API를 조합하여 현재 활성화된 앱 상태를 모니터링.
- 장점: 백그라운드에서 안정적으로 작동.
- 단점: 높은 배터리 소모 가능성과 앱 승인 절차.
- 구현:
    1. `ActivityManager`로 현재 실행 중인 태스크 정보 확인.
    2. Activity Recognition API로 사용자 동작(예: 걷기, 정지)도 함께 분석.

여기서 도출된 것들 중 유사한 기능을 다른 유관 부서에서 구현한 것을 보아서 문의 시, UsageStatsManager를 사용하는 것을 알았다. 여기서도 동일한 방법으로 접근해 보기로 결정하였다.

구현하는 코드를 만들어 적용

이를 기반으로 Prompting을 하고 관련된 코드를 입수 하여 독립된 Android App 으로 구현 테스트를 진행한다. 다음과 같은 Prompt를 사용하였다.

너는 android application 개발자야. 다음 요구 사항을 만족하는 application을 만들어줘. 추가적으로 필요한 정보가 있다면, 확인하고 제안해줘. 프로그램을 작성하는 순서를 상세히 설명해줘. 
1. MainActivity를 가지고 있어 
2. MainActivity에는 Start 버튼을 가지고 있어. 이 버튼을 클릭하면, 동작 시간을 측정 시작해. 그리고, Start 버튼이 Stop 버튼으로 변경돼. 
3. MainActivity의 Stop 버턴을 클릭하면, 휴대폰에서 사용자가 다른 어플리케이션을 사용한 내용을 정리해서 알려주는 기능을 가지고 있어. 이 부분은 UsageStatsManager에서 사용 이력을 확인할 수 있어.

이 것 기반으로 Android에서 동작하는 Kotlin 코드를 제공한다. 실제로 Android Studio에 코드를 적용하고, 테스트를 한다. 여기서 획득한 Helper 코드의 기본적인 테스트가 완료되어서, 실재 우리 App과 연동해 보고 동작하는 것을 확인하였다. 

마무리하며

간단한 사례이지만, 여기서 의미 있는 부분은 나의 문제를 명확하게 하고 어떻게 해결할지 고민하면서 필요한 요구 사항을 LLM에게 제공하여 동작 가능한 코드를 제공받았다. 개발자의 학습면에서도 좋다고 생각되는 부분은 제공 받은 코드를 통해서 Kotlin에 대해서 학습할 기회를 얻게 된 부분도 부수적인 장점으로 생각된다.


참고 문헌

[1] https://youtu.be/mzomjCHEPpg?si=TJRR-4Er7arf5m-j
[2] https://youtu.be/IACHfKmZMr8?si=rGTS_SlI96HS16no
[3] https://youtu.be/gKCklJOWB6o?si=N95cuv_Nf23Ar8S8
[4] Modern Anroid Application의 구조 이해, https://technical-leader.tistory.com/174

ViewModel을 사용할 때 Factory를 사용하는 경우와 사용하지 않는 경우에는 큰 차이가 있다. 이 차이를 이해하면, ViewModel의 인스턴스 생성 방식의존성 주입(DI) 활용 방법을 더욱 효과적으로 설계할 수 있다.

1. 기본적인 ViewModel 사용 (Factory 없이)

특징

  • ViewModel이 기본 생성자만 가진 경우 Factory 없이 사용 가능.
  • ViewModelProvider를 사용하여 Activity 또는 Fragment에 간단히 연결 가능.
  • 인수가 필요 없는 ViewModel에 적합.

예제 코드

class MainViewModel : ViewModel() {
    val message = MutableLiveData<String>()
    fun updateMessage(newMessage: String) {
        message.value = newMessage
    }
}

 

class MainFragment : Fragment() {
    private val viewModel: MainViewModel by viewModels()
}

장점

  • 간단하고 구현이 쉬움 (by viewModels() 또는 ViewModelProvider 사용 가능).
  • 생명주기를 고려하여 자동으로 관리됨.

단점

  • 생성자에서 파라미터를 받을 수 없음 (Repository, UseCase 같은 객체를 직접 주입할 수 없음).
  • 의존성 주입(DI)이 어렵고, ViewModel 내부에서 객체를 직접 생성해야 함 (유지보수 어려움).

2. Factory를 사용하는 ViewModel

특징

  • ViewModel 생성자에서 파라미터를 받는 경우 반드시 Factory가 필요함.
  • 보통 Repository, UseCase, API 서비스 등의 객체를 ViewModel에 주입할 때 사용.
  • DI(Dependency Injection) 환경 (예: Hilt, Dagger)에서 활용하기 좋음.

예제 코드

① ViewModel이 생성자를 가지는 경우

class MainViewModel(private val repository: DataRepository) : ViewModel() {
    val data: LiveData<String> = repository.getData()
}

② Custom ViewModelFactory 구현

class MainViewModelFactory(private val repository: DataRepository) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return MainViewModel(repository) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

③ Factory를 이용한 ViewModel 생성

class MainFragment : Fragment() {
    private val repository = DataRepository()
    private val viewModel: MainViewModel by viewModels {
        MainViewModelFactory(repository)
    }
}

장점

  • ViewModel의 생성자를 통해 의존성을 주입할 수 있음 (Repository, UseCase 등).
  • DI를 활용하여 테스트가 용이하고 유지보수가 쉬움.

단점

  • Factory 클래스를 따로 구현해야 하므로 코드가 길어질 수 있음.
  • Factory를 생성할 때 ViewModel을 명시적으로 매핑해야 하는 과정이 필요함.

3. Factory를 사용하지 않는 경우 vs Factory를 사용하는 경우 비교

항목Factory 사용 X (by viewModels())Factory 사용 O (Factory 필요)

사용 가능 조건ViewModel에 생성자 파라미터 없음ViewModel에 생성자 파라미터 필요
ViewModel 생성 방식by viewModels() 또는 ViewModelProviderViewModelProvider.Factory를 통해 생성
의존성 주입(DI)불가능 (ViewModel 내부에서 직접 객체 생성)가능 (Repository, UseCase 등 주입 가능)
테스트 용이성어려움 (ViewModel 내부에서 직접 객체 생성)쉬움 (의존성을 모킹(Mock)할 수 있음)
코드의 복잡성단순하고 짧음Factory 클래스를 추가해야 함

4. ViewModelFactory를 활용하는 고급 예제

(1) ViewModel에 여러 개의 의존성을 주입하는 경우

class MainViewModel(
    private val repository: DataRepository,
    private val analyticsTracker: AnalyticsTracker
) : ViewModel() {
    fun logEvent(event: String) {
        analyticsTracker.trackEvent(event)
    }
}

(2) Factory에서 여러 개의 파라미터를 전달

class MainViewModelFactory(
    private val repository: DataRepository,
    private val analyticsTracker: AnalyticsTracker
) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return MainViewModel(repository, analyticsTracker) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

(3) Fragment에서 Factory를 활용한 ViewModel 생성

class MainFragment : Fragment() {
    private val repository = DataRepository()
    private val analyticsTracker = AnalyticsTracker()

    private val viewModel: MainViewModel by viewModels {
        MainViewModelFactory(repository, analyticsTracker)
    }
}

5. Hilt를 이용한 ViewModel Factory 대체 방법

최근에는 DI 라이브러리(Hilt, Dagger)를 사용하면 Factory를 직접 구현할 필요 없음.

(1) Hilt를 활용한 ViewModel 생성

① ViewModel에 @HiltViewModel 추가

@HiltViewModel
class MainViewModel @Inject constructor(private val repository: DataRepository) : ViewModel() {
    val data: LiveData<String> = repository.getData()
}

② Repository에 @Inject 추가

class DataRepository @Inject constructor() {
    fun getData(): LiveData<String> {
        return MutableLiveData("Hello from Repository")
    }
}

③ Fragment에서 간단하게 ViewModel 생성

@AndroidEntryPoint
class MainFragment : Fragment() {
    private val viewModel: MainViewModel by viewModels()
}
  • Hilt를 사용하면 Factory 클래스를 직접 만들 필요 없이, 의존성이 자동으로 주입됨.
  • 이 방식이 현재 Android 개발의 표준적인 접근법.

6. 결론

  • ViewModel에 생성자 파라미터가 필요 없다면 Factory 없이 by viewModels() 사용.
  • ViewModel에 생성자 파라미터가 필요하면 반드시 Factory를 사용해야 함.
  • DI 라이브러리(Hilt, Dagger)를 활용하면 Factory 없이도 자동으로 의존성 주입 가능.
  • 테스트 가능성과 유지보수를 고려하면 Factory 또는 Hilt를 사용하는 것이 권장됨.

📌 정리:

간단한 ViewModel → by viewModels()
의존성이 있는 ViewModel → Factory 사용 or Hilt 활용

'Android Programming' 카테고리의 다른 글

Modern Anroid Application의 UI 구조 이해  (0) 2025.03.18
Modern Anroid Application의 구조 이해  (1) 2025.03.11
Waydroid 설정하기  (1) 2022.04.15

들어가며..

앞에서 이야기 했던 것[1]과 같이 기존에 개발 중이던 Android Application 과제에 참여하게 되면서 작성된 내용을 이해해야 하는 상황이 되었다. 여기서는 앞에서 언급한 UI 및 네비게이션 흐름 분석 중에서 FragmentTransaction, ViewModel, LiveData의 동작 방식 확인하기 위한 상세 내용에 대해서 살펴 본다.

 

Modern Anroid 구조

(1) Fragment 중심 설계 (Modern Android Architecture)

✅ 장점

  1. 단일 Activity 구조 가능 (Single Activity Architecture)
    • 대부분의 UI를 하나의 Activity에서 관리하고 Fragment를 동적으로 교체.
    • Navigation Component를 활용하면 자연스러운 화면 이동 가능.
  2. 유지보수 및 확장성 용이
    • 같은 Activity 내에서 Fragment만 바꾸면 되므로 화면 재사용성이 높음.
    • 대규모 앱 개발 시 구성 요소를 분리하여 관리하기 용이.
  3. 반응형 UI (Adaptive UI) 지원
    • 태블릿과 스마트폰에 따라 레이아웃을 유연하게 조정 가능.
    • 예: 태블릿에서는 좌측 리스트 + 우측 상세보기, 스마트폰에서는 화면 전환.
  4. Activity 간 전환 비용 감소
    • Activity 간 전환 시 onCreate() → onDestroy() 호출이 발생하여 리소스 소모가 큼.
    • Fragment 전환은 비용이 상대적으로 적고, BackStack을 관리하면 자연스럽게 복귀 가능.
  5. ViewModel과 LifecycleOwner 활용 가능
    • Activity 단위에서 ViewModel을 공유하면 Fragment 간 데이터 유지 가능.
    • viewLifecycleOwner를 활용하면 Fragment의 라이프사이클을 안전하게 관리.

❌ 단점

  1. Fragment의 생명주기 관리가 복잡
    • Activity보다 복잡한 생명주기를 가짐 (onAttach(), onCreateView(), onDestroyView() 등).
    • BackStack을 적절히 관리하지 않으면 메모리 누수 발생 가능.
  2. FragmentTransaction 관리 필요
    • Fragment 간 전환 시 FragmentTransaction을 직접 관리해야 함.
    • commit(), commitNow(), addToBackStack() 등 사용법을 숙지해야 함.
  3. Navigation Component 도입 필요
    • 기존 방식 (FragmentTransaction) 대신 Navigation Component를 사용하는 것이 권장됨.
    • Safe Args 같은 추가적인 학습이 필요할 수 있음.

Fragment vs Activity 사용 비교

Fragment 기반 (Single Activity) - 동적인 화면 변경이 많은 경우
- 데이터 공유가 필요한 경우 (ViewModel 활용)
- 태블릿/멀티-윈도우 지원이 필요한 경우
- Navigation Component를 활용하는 경우
Activity 기반 (Multiple Activity) - 독립적인 기능의 화면이 많고, 서로 연결이 필요 없는 경우
- 단순한 앱(로그인 화면, 설정 화면)에서 사용
- 백스택 관리를 자동으로 하고 싶은 경우

 

Fragment, ViewModel, LiveData 분석 방법

(1) FragmentTransaction 분석

① Fragment 변경 방식 확인

  • replace(), add(), remove(), show(), hide() 사용 여부 확인.
  • commit(), commitNow()의 사용 방식이 적절한지 확인.
  • addToBackStack() 사용 여부 및 Fragment 백스택 관리 방식 파악.

② Fragment 생명주기 확인

  • onCreate(), onCreateView(), onResume(), onPause()의 호출 순서를 Logcat으로 확인.
  • Fragment 간 전환 시 ViewModel이 정상적으로 재사용되는지 확인.

③ Fragment 간 데이터 전달 방식 분석

  • arguments를 통해 전달하는지, ViewModel을 사용하는지 확인.
  • FragmentResultListener 또는 LiveData로 데이터 전달하는지 분석.

(2) ViewModel 분석

① ViewModel 인스턴스 범위 확인

  • Activity 범위인지 Fragment 범위인지 확인 (ViewModelProvider의 owner 확인).
  • Fragment 재생성 시 ViewModel이 유지되는지 확인.

② ViewModel 내부 데이터 흐름 확인

  • LiveData 또는 StateFlow를 사용하여 데이터를 관리하는지 분석.
  • Transformations.map(), Transformations.switchMap()이 적절히 활용되는지 확인.

③ ViewModel의 Clear 시점 분석

  • Fragment가 사라질 때 ViewModel이 정상적으로 유지되는지 또는 제거되는지 확인.

(3) LiveData 동작 분석

① LiveData의 구독 방식 확인

  • observe()가 어디에서 호출되는지 확인 (Activity vs Fragment).
  • viewLifecycleOwner를 사용하고 있는지 확인 (viewLifecycleOwner.lifecycleScope.launchWhenStarted).

② LiveData의 이벤트 처리 방식 확인

  • SingleLiveEvent(일회성 이벤트) vs 일반 MutableLiveData 사용 방식 검토.
  • observeForever()가 사용되었는지 확인 (메모리 누수 가능성 체크).

③ LiveData의 Thread 처리 확인

  • MediatorLiveData 사용 여부 확인 (여러 LiveData 조합 처리 확인).
  • viewModelScope.launch 등을 사용하여 백그라운드에서 처리되는지 확인.

 

마무리

Modern Android Application 구조가 Fragement 기반의 구조로 변경되면서 기존 Android Application을 이해하는 방법도 바뀌었다고 할 수 있다. 즉, Application -> Activity 기반의 구조 이해에서 Fragment, ViewModel, LiveData로 연결되는 구조를 이해를 먼저 해야 한다. 

 

Fragment에서는 변경 방식, 생명주기, 데이터 전달 방식을 이해한 후에, ViewModle 인스턴스 범위 확인, 내부 데이터 흐름 확인 그리고 Clear 시점 분석을 한다. LiveData의 동작 분석에서는 구독 방식, 이벤트 처리 방식, Thread 처리를 확인한다.

 

참고 문헌

[1] Modern Android Application 구조의 이해, https://technical-leader.tistory.com/174

 

'Android Programming' 카테고리의 다른 글

ViewModel에서 Factory 사용 여부 비교  (0) 2025.03.25
Modern Anroid Application의 구조 이해  (1) 2025.03.11
Waydroid 설정하기  (1) 2022.04.15

들어가며..

기존에 개발 중이던 Android Application 과제에 참여하게 되면서 작성된 내용을 이해해야 하는 상황이 되었다. 일반적으로는 빌드를 해보고, 실행을 해보는 "모의 설치" [1]와 비슷한 절차를 해보았다. 개발 환경을 구축하고 소스를 받아서 빌드를 해보, 소스 코드를 살펴 보았다. 예전에 알고 있던 Android Application과 구조도 많이 달라져 정리해 본다. 특히, LLM과 분석에 대해서 이야기 해볼 때, 여러가지 힌트를 얻어서 기존 Android Application Project를 이해하는데 도움이 될 것으로 보여 정리해 본다.

 

분석 절차

1. 런타임 동작 분석

  • 로그 분석: Logcat을 활용하여 주요 이벤트와 동작 흐름을 분석.
  • 트레이스 프로파일링: Android Profiler를 사용하여 CPU, 메모리, 네트워크 사용 패턴을 확인.
  • StrictMode 활성화: 백그라운드에서 발생하는 블로킹 작업이나 리소스 누수를 감지.

2. 의존성 및 모듈 구조 분석

  • Gradle의 dependencies 확인 (./gradlew dependencies 실행).
  • Android Studio의 Project Structure를 이용하여 모듈 간의 의존성 파악.
  • Dagger/Hilt, Koin 등의 의존성 주입(Dependency Injection) 구조가 있다면 플로우 확인.

3. UI 및 네비게이션 흐름 분석

  • Navigation Component를 사용하고 있다면 nav_graph.xml 분석.
  • Espresso 또는 UI Automator를 이용하여 주요 UI 플로우 자동화 테스트 실행.
  • FragmentTransaction, ViewModel, LiveData의 동작 방식 확인.

4. 네트워크 통신 분석

  • OkHttp 로그 인터셉터 추가하여 API 호출 확인.
  • Charles, Postman, Wireshark를 사용해 실제 API 요청과 응답을 캡처.
  • Retrofit, Volley, Ktor 등의 네트워크 라이브러리 사용 여부 확인.

5. 데이터 저장 방식 분석

  • Room, SharedPreferences, DataStore, Realm 등의 사용 여부 확인.
  • adb shell 명령어를 통해 DB 상태 확인 (adb shell sqlite3 /data/data/your.package.name/databases/your_db_name.db).

6. 멀티스레딩 및 백그라운드 작업 확인

  • WorkManager, JobScheduler, RxJava, Kotlin Coroutines 사용 여부 분석.
  • 주요 백그라운드 태스크 실행 여부와 성능 영향 파악.

7. 앱 보안 및 권한 점검

  • AndroidManifest.xml에서 불필요한 권한이 있는지 확인.
  • 앱의 내부 데이터 보호 방식 (EncrytedSharedPreferences, SQLCipher 등) 점검.
  • ProGuard 또는 R8 난독화 설정 확인.

8. 빌드 및 배포 프로세스 확인

  • CI/CD 파이프라인 (GitHub Actions, Jenkins, Bitrise) 연동 여부 분석.
  • Fastlane 또는 Gradle Task를 활용한 빌드 자동화 방식 점검.

 

정리

위 항목들을 실행하면서 애플리케이션의 구조적 특징과 문제점을 파악할 수 있을 것이다. 특히, 1차적으로 1, 2번은 쉽게 진행하였고 3번을 통해서 전체 프로젝트의 파일들과 역할들을 이해하게 되면서 전체적인 구조의 그림이 보이기 시작했다. 항후 진행 하면서 관련된 배경 지식등을 학습하게 된 내용도 추가 정리해 보자. 

 

참고 문헌

[1] 객체 지향 리엔지니어링 패턴: 3장 첫 번째 접근, https://technical-leader.tistory.com/139

 

 

'Android Programming' 카테고리의 다른 글

ViewModel에서 Factory 사용 여부 비교  (0) 2025.03.25
Modern Anroid Application의 UI 구조 이해  (0) 2025.03.18
Waydroid 설정하기  (1) 2022.04.15

+ Recent posts