클린코드 독후감 .. :)
클린코드를 읽고 더 좋은 코드에 관심이 생기게 되었다. 기존 개발 방식은 구현을 위주로 고민을 하였는데, 클린코드에 나온 내용을 내 프로젝트에 직접 적용해보는 과정을 통해 더 좋은 코드를 작성하고 싶다는 고민을 하게 되었다.
클린코드에 나와있는 내용들이 전부 다 맞는 말이라고 생각하지 않는다. 상황에 따라 좋지 못한 방법, 비효율적인 방법이 효율적일 수 있고, 효율적인, 다른사람들이 선호하는 그런 방식들이 비효율적일 수 있다.
예를들어 어떤 러닝커브가 높은 아키텍처를 도입하기 위해 팀원들이 많은 시간과 노력을 소비해야 한다면, 그런데 이 때 프로젝트 기한이 짧다면 과연 그 아키텍처를 도입하는게 올바른 선택일까?
현재의 나는 올바르지 않다고 생각한다. 좋은 아키텍처, 고민한 코드들도 물론 중요하지만 가장 중요한건 이 서비스를 실제로 사용 할 사용자들이 출시일에 서비스를 이용할 수 있도록 편의를 제공하는게 가장 중요하다고 생각한다.
개인앱을 만들면서 다양한 기술을 도입하고 싶어서 멀쩡히 잘 돌아가는 코드를 몇 번이나 리팩토링 했다. 그 결과 몇몇 릴리즈 버전에서 버그가 발생하는 경우가 발생했는데, 개발자 입장으로는 다양한 기술을 사용하고 싶은 욕심으로 코드를 수정했지만 사용자 입장에서는 멀쩡하던 앱이 갑자기 튕기는 등의 버그를 마주치니 불편함을 느낄 수 밖에 없다. 어찌보면 더 좋은 코드, 더 다양한 기술을 사용한 서비스를 만드는건 개발자 욕심이 아닐까..?ㅎㅎ 이로인해 기한이 늦춰지거나 없던 버그가 발생한다면..! 이라는 생각도 들었다.
그래서 내가 생각하는 클린코드란 협업에 도움을 주는 도구라고 생각한다. 협업에 있어 정해진 규칙에 맞게 작성하고, 클린코드의 내용을 하나의 도구로 사용하여 함께 작성하는 코드를 더 보기좋고 유지보수하기에 편한 코드로 만드는데 기여할 수 있는 도구라 생각한다. (웅애 개발자의 작은 생각입니다 ㅎ.ㅎ.. 나중에 바뀔지 모름!)
프로젝트를 리팩토링 하면서 불필요한 코드, 사용하지 않는 코드, 불필요하게 선언된 변수, 함수 등등 너무 많은 레거시 코드 때문에 그렇게 복잡한 UI가 아님에도 프로젝트가 무거워 보이는 느낌을 받았다.
처음에는 기존 코드를 따라가기 급급했는데 시간이 지나면서 불필요한 코드들이 계속 눈에 보여서 선임분께 동의를 구하고 리팩토링을 진행하게 되었다.
코드를 정리하면서 재사용성, 확장성이 고려되지 않은 부분이 종종 보였고 그 중 하나였던 Action Sheet 리팩토링에 도전하여따!

애플에서 기본으로 제공해주는 Action Sheet가 있지만 회사 프로젝트는 요구되는 디자인이 있었기 때문에 커스텀으로 구현되어 있었다.
요구되었던 상황은 다음과 같다.
1. 아이템 1개
2. 아이템 1개 + 취소 버튼
3. 아이템 2개 + 취소 버튼
4. 아이템 3개 + 취소 버튼
기존 구현방식은 하나의 뷰 컨트롤러에 StackView를 넣고, 그 안에 아이템에 해당하는 뷰를 필요한 개수만큼 미리 추가한 상태였다. 그리고 쓰임에 맞게 isHidden true/false하는 방식으로 구성되어 있었다.
그리고 상황에 따른 함수를 오버로딩을 통해 이름이 같은 여러개의 함수를 정의해두고 사용하고 있었다.
기존 구현방식도 무언가 엄청난 이유로 짜놓았겠지만, 좀 더 사용성 있게 짜볼 수 있을 것 같아 다음과 같은 방식으로 재 설계한 후 구현하였다.
- 아이템은 [String] 형태로 사용자에게 입력받는다.
- 취소버튼의 여부를 Bool 형태로 사용자에게 입력받는다.
- item 하나를 컴포넌트 단위로 쪼개 사용한다.
- 전달받은 아이템 [String]을 [CustomItemView] 형태로 변환하여 ViewController의 StackView에 추가한다.
- 앞으로 구현하게 될 다른 뷰들도 컴포넌트 단위로 쪼개 사용할 가능성이 높으므로 BaseView를 추가로 생성하여 상속받는다.
- BaseView를 상속받은 뷰를 사용할 때는 생성자 호출하는 것만으로 사용 가능하게 구성한다.
내가 정의한 다른 요구사항들은 순조롭게 진행했으나 마지막 조건인 “BaseView를 상속받은 뷰를 사용할 때는 생성자 호출하는 것만으로 사용 가능하게 구성한다.” 의 과정에서 문제가 생겼다.
import UIKit
class BaseView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
if let view = UINib(nibName: String(describing: type(of: self)), bundle: nil).instantiate(withOwner: self, options: nil).first as? UIView {
view.frame = self.bounds
addSubview(view)
}
}
}
위와 같이 BaseView를 만들고
import UIKit
final class CustomView: BaseView {
@IBOutlet weak var btnItem: UIButton!
convenience init(content: String) {
self.init()
initUI(content: content)
}
func initUI(content: String) {
btnItem.setTitle(content, for: .normal)
}
}
커스텀 뷰를 만들고
let itemView = CustomView(content: "cancel".localized)
itemStackView.addArrangedSubview(itemView)
이렇게 stackView에 추가해주려고 하였다.
그러나 BaseView에 commonInit()함수가 무한루프에 빠져 앱이 종료되는 상황이 발생했다.
문제는 init() (처음 생성자 호출)-> commonInit() (Base에서 nib초기화) -> init() (다시 생성자 호출) -> …
이런식으로 호출되고 있었기 때문에 무한루프에 빠진다.

결과적으로 이 무한루프를 해결하려면 File's Owner에서 각각의 Outlet 변수를 연결해주어야 한다.
위 사진처럼 File's Owner에서 우클릭하면 작은 창이 나타나고 각 요소를 뷰에 연결해주면 된다.
그럼 nib 파일로 만든 뷰를 생성자를 통해 초기화하여 사용할 수 있다.!!!
https://stackoverflow.com/questions/49127025/instantiate-uiview-from-nib-causes-infinite-loop-issue
https://swiftlyanand.medium.com/loading-custom-views-in-ios-the-right-way-bedfc06a4fbd
'iOS' 카테고리의 다른 글
[iOS/RxSwift] subscribe, bind, drive 비교하기 (0) | 2024.01.21 |
---|---|
[iOS/RxSwift] Merge, CombineLatest, Zip 비교하기 (0) | 2024.01.20 |
[iOS] CollectionView Pagination과 Kingfisher로 이미지 캐싱(Kakao Search Image API) (0) | 2023.10.24 |
[iOS] Keychain(키체인) 알아보기 (0) | 2023.07.31 |
[iOS] UIImageView Orientation과 이미지를 회전하는 방법 (0) | 2023.07.29 |
클린코드 독후감 .. :)
클린코드를 읽고 더 좋은 코드에 관심이 생기게 되었다. 기존 개발 방식은 구현을 위주로 고민을 하였는데, 클린코드에 나온 내용을 내 프로젝트에 직접 적용해보는 과정을 통해 더 좋은 코드를 작성하고 싶다는 고민을 하게 되었다.
클린코드에 나와있는 내용들이 전부 다 맞는 말이라고 생각하지 않는다. 상황에 따라 좋지 못한 방법, 비효율적인 방법이 효율적일 수 있고, 효율적인, 다른사람들이 선호하는 그런 방식들이 비효율적일 수 있다.
예를들어 어떤 러닝커브가 높은 아키텍처를 도입하기 위해 팀원들이 많은 시간과 노력을 소비해야 한다면, 그런데 이 때 프로젝트 기한이 짧다면 과연 그 아키텍처를 도입하는게 올바른 선택일까?
현재의 나는 올바르지 않다고 생각한다. 좋은 아키텍처, 고민한 코드들도 물론 중요하지만 가장 중요한건 이 서비스를 실제로 사용 할 사용자들이 출시일에 서비스를 이용할 수 있도록 편의를 제공하는게 가장 중요하다고 생각한다.
개인앱을 만들면서 다양한 기술을 도입하고 싶어서 멀쩡히 잘 돌아가는 코드를 몇 번이나 리팩토링 했다. 그 결과 몇몇 릴리즈 버전에서 버그가 발생하는 경우가 발생했는데, 개발자 입장으로는 다양한 기술을 사용하고 싶은 욕심으로 코드를 수정했지만 사용자 입장에서는 멀쩡하던 앱이 갑자기 튕기는 등의 버그를 마주치니 불편함을 느낄 수 밖에 없다. 어찌보면 더 좋은 코드, 더 다양한 기술을 사용한 서비스를 만드는건 개발자 욕심이 아닐까..?ㅎㅎ 이로인해 기한이 늦춰지거나 없던 버그가 발생한다면..! 이라는 생각도 들었다.
그래서 내가 생각하는 클린코드란 협업에 도움을 주는 도구라고 생각한다. 협업에 있어 정해진 규칙에 맞게 작성하고, 클린코드의 내용을 하나의 도구로 사용하여 함께 작성하는 코드를 더 보기좋고 유지보수하기에 편한 코드로 만드는데 기여할 수 있는 도구라 생각한다. (웅애 개발자의 작은 생각입니다 ㅎ.ㅎ.. 나중에 바뀔지 모름!)
프로젝트를 리팩토링 하면서 불필요한 코드, 사용하지 않는 코드, 불필요하게 선언된 변수, 함수 등등 너무 많은 레거시 코드 때문에 그렇게 복잡한 UI가 아님에도 프로젝트가 무거워 보이는 느낌을 받았다.
처음에는 기존 코드를 따라가기 급급했는데 시간이 지나면서 불필요한 코드들이 계속 눈에 보여서 선임분께 동의를 구하고 리팩토링을 진행하게 되었다.
코드를 정리하면서 재사용성, 확장성이 고려되지 않은 부분이 종종 보였고 그 중 하나였던 Action Sheet 리팩토링에 도전하여따!

애플에서 기본으로 제공해주는 Action Sheet가 있지만 회사 프로젝트는 요구되는 디자인이 있었기 때문에 커스텀으로 구현되어 있었다.
요구되었던 상황은 다음과 같다.
1. 아이템 1개
2. 아이템 1개 + 취소 버튼
3. 아이템 2개 + 취소 버튼
4. 아이템 3개 + 취소 버튼
기존 구현방식은 하나의 뷰 컨트롤러에 StackView를 넣고, 그 안에 아이템에 해당하는 뷰를 필요한 개수만큼 미리 추가한 상태였다. 그리고 쓰임에 맞게 isHidden true/false하는 방식으로 구성되어 있었다.
그리고 상황에 따른 함수를 오버로딩을 통해 이름이 같은 여러개의 함수를 정의해두고 사용하고 있었다.
기존 구현방식도 무언가 엄청난 이유로 짜놓았겠지만, 좀 더 사용성 있게 짜볼 수 있을 것 같아 다음과 같은 방식으로 재 설계한 후 구현하였다.
- 아이템은 [String] 형태로 사용자에게 입력받는다.
- 취소버튼의 여부를 Bool 형태로 사용자에게 입력받는다.
- item 하나를 컴포넌트 단위로 쪼개 사용한다.
- 전달받은 아이템 [String]을 [CustomItemView] 형태로 변환하여 ViewController의 StackView에 추가한다.
- 앞으로 구현하게 될 다른 뷰들도 컴포넌트 단위로 쪼개 사용할 가능성이 높으므로 BaseView를 추가로 생성하여 상속받는다.
- BaseView를 상속받은 뷰를 사용할 때는 생성자 호출하는 것만으로 사용 가능하게 구성한다.
내가 정의한 다른 요구사항들은 순조롭게 진행했으나 마지막 조건인 “BaseView를 상속받은 뷰를 사용할 때는 생성자 호출하는 것만으로 사용 가능하게 구성한다.” 의 과정에서 문제가 생겼다.
import UIKit
class BaseView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
if let view = UINib(nibName: String(describing: type(of: self)), bundle: nil).instantiate(withOwner: self, options: nil).first as? UIView {
view.frame = self.bounds
addSubview(view)
}
}
}
위와 같이 BaseView를 만들고
import UIKit
final class CustomView: BaseView {
@IBOutlet weak var btnItem: UIButton!
convenience init(content: String) {
self.init()
initUI(content: content)
}
func initUI(content: String) {
btnItem.setTitle(content, for: .normal)
}
}
커스텀 뷰를 만들고
let itemView = CustomView(content: "cancel".localized)
itemStackView.addArrangedSubview(itemView)
이렇게 stackView에 추가해주려고 하였다.
그러나 BaseView에 commonInit()함수가 무한루프에 빠져 앱이 종료되는 상황이 발생했다.
문제는 init() (처음 생성자 호출)-> commonInit() (Base에서 nib초기화) -> init() (다시 생성자 호출) -> …
이런식으로 호출되고 있었기 때문에 무한루프에 빠진다.

결과적으로 이 무한루프를 해결하려면 File's Owner에서 각각의 Outlet 변수를 연결해주어야 한다.
위 사진처럼 File's Owner에서 우클릭하면 작은 창이 나타나고 각 요소를 뷰에 연결해주면 된다.
그럼 nib 파일로 만든 뷰를 생성자를 통해 초기화하여 사용할 수 있다.!!!
https://stackoverflow.com/questions/49127025/instantiate-uiview-from-nib-causes-infinite-loop-issue
https://swiftlyanand.medium.com/loading-custom-views-in-ios-the-right-way-bedfc06a4fbd
'iOS' 카테고리의 다른 글
[iOS/RxSwift] subscribe, bind, drive 비교하기 (0) | 2024.01.21 |
---|---|
[iOS/RxSwift] Merge, CombineLatest, Zip 비교하기 (0) | 2024.01.20 |
[iOS] CollectionView Pagination과 Kingfisher로 이미지 캐싱(Kakao Search Image API) (0) | 2023.10.24 |
[iOS] Keychain(키체인) 알아보기 (0) | 2023.07.31 |
[iOS] UIImageView Orientation과 이미지를 회전하는 방법 (0) | 2023.07.29 |