디자인 요구사항을 앱 개발에 효율적으로 반영하려면

leeokmin
DelightRoom
Published in
12 min readNov 15, 2021

딜라이트룸에서 디자인을 앱 개발에 반영하는 방법

앱 개발을 하면서 문구에 폰트, 크기, 컬러를 적용하는 것이 귀찮다고 생각한 적이 있나요? 혹은 값을 입력하다가 오타가 나서 긴긴 빌드 과정을 다시 했던 경험이 있나요?

앱 개발을 하면서 디자인 요구사항을 반영하는 경우는 필연적 입니다. 비슷한 작업이라 지루하기도 하고 이들의 값을 입력하다보면 오타가 나기도 하지요.

태초에 귀찮음이 있었다

아래와 같은 화면을 앱 내에 구현한다고 생각해 봅시다. 이 화면은 실제로 알라미 iOS 오늘의패널에 들어가는 화면 중 하나입니다.

좌. 실제화면. 우, “물 한잔 마시기”의 프로퍼티들

“물 한잔 마시기”라는 문구를 앱에 표시하는 방법을 생각해 봅시다. 단계를 나눠서 정리하면 다음과 같습니다.

1. What무엇을 보여줄 것인가?

  • “물 한잔 마시기”라는 문구

2. How어떻게 보여줄 것인가?

  • 문구에 적용해야 하는 폰트와 크기
  • 문구에 적용해야 하는 컬러

3.Where어디에 보여줄 것인가?

  • 폰트와 컬러가 적용된 문구를 나타내는 위치

각각의 단계를 코드로 작성하면 아래와 같습니다.

//What
let titleText: String = "물 한잔 마시기"
//How
let attributes: [NSAttributedString.Key: Any]
= [.font: UIFont.systemFont(ofSize: 20, weight: .heavy),
.foregroundColor: UIColor(red: 31 / 255, green: 37 / 255, blue: 46 / 255, alpha: 1.0)]
let attributedText = NSMutableAttributedString(string: titleText, attributes: attributes)
//Where
let label = UILabel(frame: CGRect(x: 10, y: 10, width: 300, height: 20)
label.attributedText = attributedText

How 부분을 다시 봅시다. 폰트와 크기, 컬러 값들은 디자인 요구사항에 있는 숫자 값을 입력 했습니다. 이런 작업을 모든 텍스트에 적용한다면 어떨까요? 하나 하나 적용하다 보면 오타가 발생할 수 있습니다. 수정이 쉽지 않아 유지보수가 힘들어 집니다. 무엇보다 귀찮죠. 이 글에서는 알라미 iOS가 이런 요구사항들을 효율적으로 반영해 구현하는 방법을 다룹니다.

We have the ADS(Alarmy Design System)

알라미에는 디자인 시스템이 있습니다. 폰트와 크기 및 컬러도 디자인 시스템 내에 정의되어 있는데요. 덕분에 디자인 작업물은 일관성을 유지합니다.

개발 작업을 할 때도 이 시스템을 이용할 수 있다면 효율적이겠다고 생각했습니다. 보이지 않는 위험인 폰트, 크기, 컬러 값을 잘 못 입력하는 휴먼 에러를 방지할 수 있습니다. 코드 작업이 간결해지고, 수정이 쉬워져 개발자의 생산성도 높아질 수 있고요. 그리고 디자이너와 소통할 때도 한결 편할 것 같습니다. 미리 정의된 요구사항들로 소통하니 이야기하기 편하고 수정 작업도 한결 수월해 지겠죠.

귀찮음은 효율화를 유발한다

폰트와 크기 및 컬러가 디자인 시스템 내에서 어떻게 정의되어 있는지 알아보고, 이를 코드로 어떻게 구현 하는지 살펴봅시다.

Step1. Typhography

Typography는 디자인 시스템에서 폰트와 크기에 해당합니다.

ADS에서 실제 Typography

TypographyHero, Hero2, Title1과 같은 각각 고유한 이름이 있습니다. 그리고 그에 맞는 폰트와 크기가 정해져 있죠. 이를 코드로 표현하면 다음과 같습니다.

public enum Typography {
case hero1
case hero2
case title1
case title2
case title3
//...
}
extension Typography {
var font: UIFont {
let result: UIFont
switch self {
case .hero1: result = UIFont.systemFont(ofSize: 110, weight: .heavy)
case .hero2: result = UIFont.systemFont(ofSize: 48, weight: .heavy)
case .title1: result = UIFont.systemFont(ofSize: 32, weight: .heavy)
case .title2: result = UIFont.systemFont(ofSize: 26, weight: .heavy)
case .title3: result = UIFont.systemFont(ofSize: 20, weight: .heavy)
//...
return result
}
}

이를 사용해 위 코드의 How를 이렇게 개선할 수 있습니다.

//How
let attributes: [NSAttributedString.Key: Any]
= [.font: Typography.title3,
.foregroundColor: UIColor(red: 31 / 255, green: 37 / 255, blue: 46 / 255, alpha: 1.0)]
let attributedText = NSMutableAttributedString(string: titleText, attributes: attributes)

UIFont.systemFont(ofSize: 20, weight: .heavy) 코드가 .font: Typography.title3 로 간결해졌습니다.

Step2. Color

이어서 Color 항목을 살펴봅니다. 컬러는 아래와 같이 정의되어 있습니다.

마찬가지로 Colorbackground, appbar 등 고유한 이름이 있습니다. 그에 맞는 색상 값도 정해져 있죠. 이를 코드로 표현하면 다음과 같습니다.

extension UIColor {
public static var background: UIColor {
return UIColor(hexString: "#F5F9FF")
}
public static var appbar: UIColor {
return UIColor(hexString: "#E8F1FF")
}
public static var scrim: UIColor {
return UIColor(hexString: "#30435F").withAlphaComponent(0.8)
}
public static var onSurfaceDisabled: UIColor {
return UIColor(hexString: "#BDCFED")
}
public static var surface: UIColor {
return UIColor(hexString: "#FFFFFF")
}
public static var onSurfaceHighEmphasis: UIColor {
return UIColor(hexString: "#1F252E")
}
//...
}

다시 How 부분의 코드를 수정합니다.

//How
let attributes: [NSAttributedString.Key: Any]
= [.font: Typography.title3,
.foregroundColor: UIColor.onSurfaceHighEmphasis]
let attributedText = NSMutableAttributedString(string: titleText, attributes: attributes)

.foregroundColor: UIColor(red: 31 / 255, green: 37 / 255, blue: 46 / 255, alpha: 1.0 ) 부분이 .foregroundColor: UIColor.onSurfaceHighEmphasis 로 간결해졌습니다.

Step3. extension

정해진 값을 이용해 휴먼 에러를 방지할 수는 있게 되었습니다. 하지만 아직 코드가 직관적이지 않습니다. 사용하기도 조금 불편하고요.

이를 개선하기 위해 아래와 같은 extension을 추가했습니다. (아래의 코드는 기술적으로 이해하지 않아도 괜찮습니다.🙂)

extension String {
private func attributedString(type: Typography) -> NSMutableAttributedString {
let attributes: [NSAttributedString.Key: Any] = [.font: type.font, .foregroundColor: UIColor.onSurfaceHighEmphasis]
return NSMutableAttributedString(string: self, attributes: attributes)
}

public var title3: NSMutableAttributedString {
return attributedString(type: .title3)
}
//...
}
extension NSMutableAttributedString {
public func addColor(_ uiColor: UIColor) -> NSMutableAttributedString {
let result = self
let range = NSRange(location: 0, length: self.length)
if attribute(.foregroundColor, at: 0, effectiveRange: nil) != nil {
removeAttribute(.foregroundColor, range: range)
}
result.addAttribute(.foregroundColor, value: uiColor, range: range)
return result
}
//...
}

위의 개선을 적용하면 How 부분은 한 줄 코드로 표현 가능합니다.

//How
let attributedText = titleText.title3.addColor(.onSurfaceHighEmphasis)

코드를 읽어 봅시다. “titleText(물 한잔 마시기)에 title3 폰트를 적용하고 onSurfaceHighEmphasis 컬러를 추가한다"라는 흐름으로 읽을 수 있고 표현 방법도 더 간결합니다.

Step4. one more thing,,

위의 코드들은 extension을 이용한 구현이 대부분입니다. 그리고 편의를 위해 줄여서 표현했지만 TypographyColor는 각각 코드라인이 100줄을 넘어 분량이 꽤 되는데요. 안그래도 기나긴 빌드시간을 조금이라도 늘리고 싶지 않았습니다.

작성한 코드들은 앱과 의존성이 없고 재사용성이 충분합니다. 그래서 Swift Package를 만드는게 합리적이라 판단했습니다. 이렇게 디자인 시스템을 구현한 ALDesign 모듈이 만들어졌습니다.

개발자는 위의 구현 내용을 알 필요 없이 아래와 같이 코드를 작성하면 됩니다.

import ALDesign//How
let attributedText = titleText.title3.addColor(.onSurfaceHighEmphasis)

결론

디자인 시스템을 적용하고 난 후 협업과 소통을 더 편하고 효율적으로 바꿀 수 있었습니다. 수정 요청이 명확해지고, 덕분에 기나긴 빌드 시간이 많이 줄었습니다. 이를 정성적으로 표현하면 이렇습니다. 전에는 디자이너와 개발관련 피드백을 주고 받을 때는 아래처럼 소통했었죠.

디자이너: 여기 문구가 실제 앱으로 보니 좀 작은 느낌인데요. 조금 키워서 볼 수 있을까요?
개발자: 얼마나요?
디자이너: 음..한 2 정도?
개발자: 네, 잠시만요~
(5분의 빌드 타임 후)개발자: 이렇게 어떠세요?
디자이너: 죄송한데 한 2정도 더 크게 볼 수 있을까요?
개발자: 넵~
(또다시 5분의 빌드 타임 후)개발자: 좀 더 키워왔어요~
디자이너: 네, 이렇게 가요!

디자인 시스템을 적용한 후에는 소통이 더 간결하고 효율적이 되었습니다.

디자이너: 여기 문구가 실제 앱으로 보니 좀 작은 느낌인데요. 조금 키워서 볼 수 있을까요? 적용된 타이포그라피가 title3인데 title2로요!
개발자: 네, 잠시만요~
(5분의 빌드 타임 후)디자이너: 네, 이렇게 가요!

개발 작업에도 아래와 같은 이점이 생겨 개발 생산성도 향상 됐습니다.

  • 같은 구현을 재사용하는 부분을 개선해 코드를 일관적으로 정리할 수 있습니다.
  • 폰트, 크기, 컬러 값을 직접 입력할 필요가 없어 휴먼에러가 감소합니다.
  • 수정 작업이 간결합니다.

여기까지 디자인 요구사항을 앱 개발에 효율적으로 반영하는 방법을 살펴봤습니다. 저에게는 딜라이트룸이 추구하는 가치인 효율화를 실현하고, 기술적으로는 Swift Package를 더 다룰 수 있게된 좋은 경험이었습니다. 끝까지 읽어주셔서 고맙습니다!

Smis, Swift man in Seoul

디자인 시스템을 적용하고 모듈화까지 가는 과정에 격려와 도움을 주신 모든 딜라이터 분들에게 감사를 전하며 이 글을 마칩니다.

iOS 개발자로서 성장할 수 있는 환경을 원한다면! 알라미팀 구경하기

참조

--

--