Proxy

최완식·2023년 1월 3일
post-thumbnail

Proxy 패턴은 뭘까? 서버에서 들었던 것 같은데, 패턴으로는 어떤 의미가 있는지 알아보자.

Proxy

  • 예전에 의미있었던 방법
  • 오히려 클래스가 명백하지 않게 보이는 경우가 있어 조심해야 함

Proxy란?

  • 웹 브라우저 설정에 프록시 서버라는 것이 있음
  • 실제 웹 사이트 서버와 사용자 사이에 있는 중간 서버를 말함
  • 인터넷 상의 캐시 메모리

Proxy Pattern

  • Proxy 서버가 하려는 것과 비슷함
  • 클래스에서 어떤 상태를 유지하는게 애매한 경우가 있다.
    • 데이터가 너무 커서 미리 읽어두면 메모리가 부족함
    • 개체 생성시 데이터 로드 시간이 꽤 걸림
    • 개체는 만들었으나 내부 데이터를 사용하지 않을 수도 있음
    • 이런 것들을 값비싼 리소스라고 함
  • 목표: "당장은 필요 없지만, 필요하게 될 경우를 대비하여 언제든 로드할 수 있게 하자."
  • 처음 화면같은 것을 로드한다고 할 때, 리소스는 파일 경로만 기억
  • 실제로 화면에 보여질 필요가 있을 경우 로드
  • 그리고 그 정보는 저장해둚(캐싱)

예시: Image data

  • 이미지는 용량이 크고
  • 저장 장치에서 읽어와야 하기 때문에 보통 로딩하는데 오래 걸린다. (병목 현상 발생)
  • 그렇기 때문에 프록시 패턴을 적용하기 적합하다.

Proxy 적용 X

public final class Image {
    private ImageData image;

    // 생성시 이미지를 로드
    public Image(String filePath) {
        this.image = ImageLoader.getInstance().load(filePath);
    }

    public void draw(Canvas canvas, float x, float y) {
        canvas.draw(this.image, x, y)
    }
}
  • filepath를 받자마자 무조건 디스크에서 이미지 데이터를 읽어옴
  • 메모리를 많이 사용한다.
  • 무조건 이미지를 불러오기 때문에 시간도 오래 걸린다.
  • 언제나 문제점은 아니다. 만약 500개 이미지를 모두 사용한다고 한다면 큰 문제는 아닐 수 있다.
  • 다만, 사용 여부가 확률적으로 낮다면 굳이 로드할 필요가 없는 데이터를 로드하는 낭비를 범할 수 있다.

Proxy 적용 O

public final class Image {
    private String filePath;
    private ImageData image;

    public Image(String filePath) {
        this.filePath = filePath;
    }

    public void draw(Canvas canvas, float x, float y) {
        if (this.image == null) {
            this.image = ImageLoader.getInstance().load(this.filePath);
        }

        canvas.draw(this.image, x, y);
    }
}
  • 개체 생성시에는 아무 데이터도 읽지 않음
  • 실제로 사용하는 시점에 캐시 여부를 확인하고 로드를 결정
  • 이렇게 필요한 시점에 늦에 읽어오는 방식을 지연(게으른) 로딩(lazy loading)이라 함
    • 이 반대는 즉시((로딩하고싶어서) 안달이 난) 로딩(eagar loading)

즉시 로딩 vs. 지연 로딩

  • 위에서는 두가지 비교를 했는데, 사실 캐싱 여부까지 적용한다면 3가지 분류로 나눌 수 있다.
즉시 로딩지연 로딩 + 캐시 X지연 로딩 + 캐시
(프록시 패턴)
최신 데이터XO
메모리 사용량최대최소중간 (사용한 것에 대해 캐싱으로 들고 있음)
실행 속도 병목점생성 시점사용할 때 마다알기 어려움 (처음 사용한 시점에 발생)
  • 프록시 패턴의 경우 명확하지 않다는 문제가 있다.

요즘 세상에서의 프록시 패턴

  • 메모리량이 많다.
    • 한 번에 로딩해놔도 큰 문제는 아니다.
  • 한 번에 그리는 이미지 수가 많지 않다면?
    • 필요할 때마다 디스크에서 읽자.
    • 충분히 빨라졌다.
    • SSD면 더 빠르다.
  • 인터넷에서 로딩한다면?
    • 디스크보다 더 오래 걸린다.
    • 그 동안 프로그램이 멈춰있을 수는 없다.

프록시 패턴 + 캡슐화의 문제

  • 캡슐화는 잘 해둚
  • 클라이언트는 사용만 하면 결국 이미지가 로드되어 반환됨
  • 하지만.. 언제 해당 클래스가 느려지는지 알 수 없다.
  • 위에서 보았듯이 프록시 패턴을 사용한 경우 명확하지 않다는 문제가 발생하기 대문이다.
  • 클라이언트 입장에서 해당 클랙스를 어떻게 사용할 지 모르기 때문에,
  • 각 방식에 대해 제어권을 클라이언트 쪽으로 넘겨주는 것이 보다 옳다.
  • 결국 고객의 기준으로 프로덕트를 전달하는 것이 옳기 때문이다.

프록시 패턴의 현대화 예

public final class Image {
    private String filePath;
    private ImageData image;

    public Image(String filePath) { 
        this.filePath = filePath;
    }

    public boolean isLoaded() {
        return this.image != null;
    }

    public void load() {
        if (this.image == null) {
            this.image = ImageLoader.getInstance().load(this.filePath);
        }
    }

    public void unload() {
        this.image = null;
    }

    public void draw(Canvas canvas, float x, float y) {
        canvas.draw(this.image, x, y);
    }
}
  • 생성 시에는 filePath만 받는다.
  • 바깥으로 이미지 로드 여부(isLoaded())를 파악 할 수 있게 열어준다.
  • 직접적으로 load() 함수를 열어주어 제어할 수 있도록 한다.
  • 캐시가 상할 것을 대비하여 unload() 함수도 제공한다.
  • draw() 함수의 경우 image가 있다는 전제하에 작동한다.
  • 이렇게 하면 해당 클래스를 사용하는 클라이언트가 화면에 리소스 파일을 몇개 로드했는지에 대한 정보도 보여줄 수 있다!
    • 원래는 로드 여부를 모르기 때문에 그냥 벙찌고 기다려야 한다.
    • 그럼 강종해버리고 그 앱 안쓰겠지

지연 로딩 주의사항

  • 필요한 곳에 잘 선택하여 사용해야 한다.
  • UX도 고려해야하기 때문
  • 그렇게 되면 프록시 패턴의 입지가 좀 애매해짐
    • 클라이언트 쪽으로 제어여부를 노출하기 때문에 캡슐화가 좀 깨짐
      • 결국 내부가 어떻게 도는지 노출하는 셈
  • 즉, 부수적인 요소(시간, UX 등)을 고려 해야 한다면 캡슐화가 깨짐에도 열어두는 것이 좋은 방안일 수 있다.
  • 단순히 캡슐화를 위해 밖에서 동작을 명확히 알아야 함에도 숨기는 것은 개념에 함몰되어 중요한 것을 놓치는 오류를 범할 수 있다.

Reference

profile
Goal, Plan, Execute.

8개의 댓글

comment-user-thumbnail
2023년 8월 9일

subway surfers online I'm captivated by how this article seamlessly weaves together seemingly unrelated topics into a cohesive narrative.

답글 달기
comment-user-thumbnail
2024년 12월 27일

이 기사를 읽는 것은 독자가 필요로 하는 것을 진정으로 이해하는 사람과 함께 앉아 있는 것과 같았습니다. 당신의 글은 명확하고 https://avatarworldgame.com 위안이 되며 주의와 인내로 각 아이디어를 안내합니다. 글쓰기에서 이처럼 전문성과 공감의 균형 잡힌 조합을 찾는 것은 드문 일이며, 이는 진정으로 풍요로운 경험을 선사했습니다.

답글 달기
comment-user-thumbnail
2025년 5월 8일

오~ 프록시 패턴부터 시작해서 웹 성능 최적화, 안드로이드 이미지 최적화까지! 진짜 개발하면서 필요한 내용들 꽉꽉 담았네. 한번 쭈욱 읽어봐야겠다!@chill guy clicker

답글 달기
comment-user-thumbnail
2025년 7월 2일

와! 프록시 패턴 하나로 이렇게 다양한 최적화 방법을 다루다니 신기하다. AWS랑 Android 내용도 있어서 완전 꿀팁이네! 나도 프로젝트에 적용해봐야겠다. @wu-name

답글 달기
comment-user-thumbnail
2025년 7월 25일

프록시 패턴 설명 너무 실용적이네요! 특히 현대화 예시에서 클라이언트에게 제어권 주는 방식이 인상적입니다. 개발자 취업할 때 AI Cover Letter Generator로 이런 디자인 패턴 이해도를 어필하면 좋겠어요. UX 고려한 접근이 현실적이라 생각해요!

답글 달기
comment-user-thumbnail
2025년 8월 4일

좋은 내용이네요! 현대적인 예시들이 정말 도움이 됩니다. 디자인 패턴이 어떻게 진화하는지 생각하게 만드네요. Random Tarot Card 를 뽑는 것과 같아요 - 때로는 옛날 방식도 새로운 시각이 필요하죠!

답글 달기
comment-user-thumbnail
2026년 3월 9일

프록시 패턴 설명이 정말 명쾌하네요! 특히 클라이언트에게 제어권을 넘겨주는 현대적인 예시가 와닿습니다. 디자인 패턴 이해도를 높여서 AI Video Generator 같은 툴을 활용할 때도 더 효과적으로 적용할 수 있을 것 같아요!

답글 달기
comment-user-thumbnail
2026년 7월 28일

캡슐화와 사용자 제어권 간의 절충을 제시한 지점이 매우 인상적입니다. 시스템 성능과 UX를 정교하게 타협하며 클라이언트에 제어권을 넘기는 방식은 campaign performance reporting 지표 대시보드 처리와 같은 대용량 데이터 리소스 관리 작업에도 적용 가능한 실무적 통찰입니다.

답글 달기