[iOS] 내가 보려고 정리하는 개발 용어 사전 (3) - 명령형 프로그래밍(Imperative Programming) vs 선언형 프로그래밍(Declarative Programming)

2024. 8. 27. 10:06Developer Basis

현재 이 글을 쓰고 있는 2024년 기준, iOS 개발을 배우고 싶다고 마음을 먹게 되면 선택할 수 있는 옵션은 두 가지.

명령형 프로그래밍 기반의 UIKit와 선언형 프로그래밍 기반의 SwiftUI가 있다.
처음 내가 iOS를 배울 때만 하더라도 SwiftUI가 생긴지 얼마 되지 않아 대부분의 프로그램이 UIKit 기반으로 짜여 있었다.
하지만, 18개월동안 군대를 다녀와보니 생각보다 SwiftUI는 많이 발전되어 있었고 애플에서도 지속적으로 생태계를 확장시키려는 움직임을 매년 WWDC에서 확인할 수 있었다.

애플이 현재 UIKit을 외면(?)하고 있는 것은 아니지만, 미래의 확장 가능성을 생각해 볼 때 UIKit보다는 SwiftUI가 더욱 전망이 밝아 보인다는 사실을 부인할 iOS 엔지니어는 없을 것으로 생각한다.


여기서 생긴 의문!

  • 기존 UIKit가 있음에도 애플은 왜 SwiftUI라는 새로운 프레임워크를 만든 것일까? (안드로이드 Jetpack Compose도 마찬가지)
  • 앞으로 UIKit는 SwiftUI로 완전히 대체될까?
  • 명령형 프로그래밍은 뭐고, 선언형 프로그래밍은 뭐지? 둘 중 어떤게 더 좋은 프로그래밍 패러다임이지?

이번 글은 위의 떠오른 의문들에 대한 답을 찾는 흐름으로 써보고자 한다.

 

명령형 프로그래밍은 뭐고, 선언형 프로그래밍은 뭐지?

우선, 명령형 프로그래밍과 선언형 프로그래밍이 각각 무엇인지를 알아야겠다.

✔️ 명령형 프로그래밍(Imperative Programming)은 "코드가 어떻게(How) 동작하는지를 작성"하는 방식
✔️ 선언형 프로그래밍(Decalrative Programming)은 "코드가 무엇을(What) 수행하는지를 작성"하는 방식

 


아직 감이 잘 안온다고? 그럼 쉬운 이해를 위해 예시를 하나 들어보겠다.
프로그래밍 관점을 빼고, 그냥 현실의 관점에서 "내가 라면 한 그릇을 먹고 싶은 상황"이라고 생각해보자.

✔️ 명령형 프로그래밍(Imperative Programming) 관점에서 바라보는 라면 상황
: 누군가에게 라면을 어떻게(How) 끓이는지에 대해 한 단계, 한 단계씩 차근차근 모든 명령을 내리는 방법이다.

-> "냄비에 물을 500ml 넣고, 분말과 후레이크 스프를 모두 넣고, 물이 끓으면 면을 넣고, 5분 뒤에 계란을 넣은 뒤, 계란이 익으면 냄비에 담긴 라면을 그릇으로 옮겨 담아라."

명령형 프로그래밍 관점에서는 내가 원하는 목표(= 라면 한 그릇)를 달성하기 위해서 모든 과정이 어떻게(How) 이루어지는지를 설명한다.

✔️ 선언형 프로그래밍(Decalrative Programming) 관점에서 바라보는 라면 상황
: 누군가에게 내가 원하는 결과, 곧 행위의 목표가 무엇(What)인지에 대해서 선언하는 방법이다.

-> "라면 한 그릇을 끓여라"

반면, 선언형 프로그래밍 관점에서는 목표를 달성하기 위한 과정이 어떻게(How) 이루어지는지에 대해서는 관심을 갖지 않는다.
오로지 내가 원하는 목표가 무엇(What)인지에 대해서만 설명할 뿐이다.

 

명령형 프로그래밍인 UIKit, 그리고 선언형 프로그래밍인 SwiftUI

UIKit vs SwiftUI에 대한 직관적인 비교

이제 조금 이해가 되는가?
그럼 UIKit과 SwiftUI 코드를 직접 비교하며, 프로그래밍 관점에서 명령형 프로그래밍과 선언형 프로그래밍이 어떻게 차이가 나는지에 대해 더 자세하게 이해해보자.

텍스트 필드를 통해 입력받은 문자열 String이 바뀔 때마다 Label에 업데이트를 하고자 하는 상황을 예시로 들어보겠다.

명령형 프로그래밍(Imperative Programming) 관점의 UIKit 코드를 쓸 때는 업데이트가 어떤 과정을 통해 수행되는지를 모두 설명해야 할 거다.
뭐.. 예를 들어 아래와 같은 것들 말이다.

  • UILabel과 UITextField는 화면 어디에 위치하고, 어떤 속성을 갖고 있는지
  • UITextField의 내용이 변경될 때마다 호출될 메서드를 구현 (UITextField의 텍스트 값이 UILabel의 텍스트 값에 대입되어 업데이트)
  • UITextField의 addTarget 메서드를 통해 위의 메서드와 수동으로 연결
import UIKit

final class ViewController: UIViewController {
    private let label = UILabel()
    private let textField = UITextField()

    override func viewDidLoad() {
        super.viewDidLoad()

        label.text = ""
        label.frame = ...
        textField.placeholder = ...
        textField.borderStyle = ...
        textField.frame = ...
        [label, textField].forEach { view.addSubview($0) }
        
        textField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
    }

    @objc func textFieldDidChange(_ textField: UITextField) {
        label.text = textField.text
    }
}

 

반면, 선언형 프로그래밍(Decalrative Programming) 관점의 SwiftUI로 동일한 작업을 하는 코드를 작성한다고 하면,
UIKit처럼 업데이트가 어떤 과정을 통해 수행되는지를 작성할 필요 없이 - 그저 "이런 상황에서는 이런 UI를 그려라"라고 프로그램에 선언할 뿐이다.

  • Text(= UILabel)는 inputText의 값을 표현

텍스트 필드와 라벨의 상태가 어떤지, 이벤트 처리가 어떤 과정으로 이루어지는지와 같은 과정은 우리 개발자의 관심사가 아닌 것이다.
-> 관심사가 아닌 부분은 SwiftUI 프레임워크나 Xcode 같은 빌드 툴이 내부적으로 최적의 방식을 찾아 처리한다. (추상화!)

import SwiftUI

struct ContentView: View {
    @State private var inputText: String = ""

    var body: some View {
        VStack {
            TextField(..., text: $inputText)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding()
            Text(inputText.isEmpty ? "" : inputText)
                .padding()
        }
        .padding()
    }
}

 

애플은 왜 SwiftUI를 만든 걸까? SwiftUI는 UIKit을 완전히 대체할 수 있을까?

코드를 통해 비교하니 UIKit에서 SwiftUI로 넘어가려고 하는 iOS 프로그래밍의 전체적인 흐름과 Apple의 의도가 조금은 이해가 될 것 같은가?

일단 명확하게 명령형 프로그래밍(UIKit)에 비해 선언형 프로그래밍(SwiftUI)은 획기적으로 코드의 길이를 줄일 수 있었다.
또한 단순히 코드의 길이가 짧아지는 것을 넘어서, How는 신경 쓰지 않고 What에만 집중하다 보니 - 코드가 보다 더 직관적이고 읽기 쉬워진다는 장점이 있었다.

이 외에도 선언형은 명령형 패러다임에 비해 재사용이 용이해서 유지보수적인 측면에서 우위를 갖는다는 점.
프레임워크나 런타임 차원에서 자동으로 최적화가 이루어진다는 점 등등.. 많은 장점을 갖고 있다고 함께 설명할 수 있다.
-> 이를 통해 SwiftUI는 UIKit에서 제공하지 않았던 실시간 미리보기나 Multi App Flatform 등을 SwiftUI에서 제공하며, 개발자들에게 더욱 편한 개발 환경을 제공하고 있는 셈이다.

🤔 선언형 프로그래밍 패러다임의 발전에 대한 개인적인 생각

처음 코딩에 입문했을 때, <프로그래밍적 사고>를 설명하며 - 아이가 아버지에게 시리얼을 먹는 상황을 코딩하듯이 명령하던 한 영상이 기억에 났다.
그때 아이가 아버지에게 "시리얼을 붓는다 (어디에 붓는지 코딩하지 않아 에러 발생) / 우유를 그릇에 담는다 (얼마큼 담아야 하는지 명시하지 않아 에러발생)"와 같은 명령을 내리면서 <프로그래밍적 사고과정>에 대해 배우는 모습이 담겨있었는데,
이랬던 명령형 패러다임에서 선언형 패러다임으로 흘러가는 최신 프로그래밍 기술의 흐름을 보며 - "내가 처음 생각했던 코딩과는 또 다른 방향으로 미래에는 흘러갈 수 있겠구나"라는 생각이 들게 된다.

+ 보다 개발이라는 분야의 진입 장벽이 낮아지는 느낌이랄까....?

그 어디서도 SwiftUI를 UIKit의 대체제로 소개하지 않는다. 오히려 보완재라는 말이 더 적절하다고 본다.

What에만 집중하는 코드가 How를 설명하는 코드에 비해 직관적인 것에는 부인할 사람이 없겠지만, How를 신경 써야 하는 상황도 프로그래밍 과정에 있어 분명히 존재하기 때문이다. (= 비동기 작업과 같은 복잡한 상황의 경우, 분명 각 상태별로 처리해야 하는 작업을 나누어서 프로그램에 직접 명령을 내려야 하는 상황이 있다는 의미.)

즉, 선언형 프로그래밍이 갖는 명확한 장점 때문에 미래지향적으로 보면 SwiftUI의 발전이 유망한 것은 분명하지만,
그렇다고 UIKit를 모르는 상황에서 SwiftUI만으로 모든 것을 다 Control 하기는 어렵다고 보는 것이 내 개인적인 생각이다. (물론, 또 모르지)

아무튼 그렇지만. SwiftUI 공부할 때가 이제는 된 것 같다는 생각(?)