어떤 프로그램을 개발할 때 주먹구구식으로 '우선 동작 가능하게 하자'라는 마인드로 개발을 했었다.

그런데 유지보수를 막상 해보니까 생각보다 하나를 추가하거나 삭제하는 일이 많은 비용이 들고 힘들었다.

그러다가 새로운 분이 우리 팀에 들어오셨는데 나에게 말했던 것이 바로 솔리드 원칙 바로 오늘 주제다.

 

SOLID라는 개념을 어렴풋이 들었지만 개발할 때 막상 지켜서 해본 적이 없었다.

그래서 이번 시간에 정리하기로 마음먹었다.

SOLID

로버트 마틴이 2000년대 초반에 명명한 객체 지향 프로그래밍 및 설계의 다섯 가지 기본 원칙을 마이클 페더스가 두문자어 기억술로 소개한 것이다. 프로그래머가 시간이 지나도 유지 보수와 확장이 쉬운 시스템을 만들고자 할 때 이 원칙들을 함께 적용할 수 있다. 즉 소프트웨어 작업에서 프로그래머가 소스 코드가 읽기 쉽고 확장하기 쉽게 될 때까지 소프트웨어 소스 코드를 리팩토링하여 보다 쉽게 적용할 수 있는 지침이다.

SRP(Single responsibility Principle, 단일 책임의 원칙)

하나의 클래스는 하나의 기능만 가지며 클래스가 제공하는 모든 서비스는 그 하나의 책임을 수행하는데 집중되어 있어야 하는 원칙이다.

어떤 변화에 의해 클래스를 변경해야 하는 이유는 오직 하나뿐이어야 한다. 이렇게 하면 책임 영역이 확실해지기 때문에 한 책임의 변경에서 다른 책임의 변경으로의 연쇄작용에서 자유로울 수 있다. 뿐만 아니라 책임을 적절히 분배함으로써 코드의 가독성 향상, 유지보수 용이라는 이점까지 얻을 수 있다.

 

'책임'이라는 키워드가 중요하다. 개발을 하다 보면 서로 강한 연결성을 만드는 경우가 자주 있다.

 

변경할 수 없는 부분변경이 발생할 수 있는 부분을 나누어 설계하기

이렇게 설계하면, 특성 정보에 변경이 일어나도 변경이 일어나는 클래스만 변경하면 되기 때문에 관리하기 편하다.

 

  • 클래스는 자신의 이름이 나타나는 일을 해야 한다. 이것이 클래스의 책임을 나타낼 수 있는 가장 좋은 방법이다. (이름 짓기)
  • 각 클래스는 하나의 개념을 나타내야 한다.
  • 사용되지 않는 속성이 결정적 증거(사용하지 않는 속성이 있다면 이는 잘못된 설계일 수 있다.)
  • 무조건 책임을 분리한다고 적용되는 개념이 아니다.

OCP(Open Close Principle, 개방 폐쇄의 원칙)

소프트웨어의 구성요소(컴포넌트, 클래스, 모듈, 함수)는 확장에 열려있고, 변경에는 닫혀있어야 한다는 원칙이다.

변경을 위한 비용은 가능한 줄이고 확장을 위한 비용은 가능한 극대화 해야 한다는 의미이며, 요구 사항의 변경이나 추가사항이 발생하더라도, 기존 구성요소는 수정이 일어나지 말아야 하며, 기존 구성요소를 쉽게 확장해서 재사용할 수 있어야 한다. OCP를 가능케 하는 중요 메커니즘이 추상화와 다형성이다.

 

변경될 것과 변하지 않을 것을 엄격히 구분하자.

이 두 모듈이 만나는 지점에 인터페이스를 정의하자.

구현에 의존하기보다 정의한 인터페이스에 의존하도록 코드를 작성하자.

 

항상 우리는 변화를 염두에 두고 있어야 한다.

커맨드 센터를 만들었다면, 서플라이 디팟, 배럭, 팩토리를 만들 수 있어야 한다.

그러면 매번 클래스를 새롭게 만들어야 할까? 아니다. 확장하자!

 

건물들의 공통 속성을 모두 담을 수 있는 인터페이스를 설계한다.

그 인터페이스를 상속받아서 구현하면 코드의 수정을 최소화하여 결합도는 줄이고 응집도는 높이는 효과를 낼 수 있다.

 

  • 인터페이스는 가능한 변경 되어서는 안 된다.
  • 인터페이스를 정의할 때는 여러 경우의 수에 대한 고려와 예측이 필요하다.
  • 인터페이스 설계에서 적당한 추상화 레벨을 선택하자. 여기서 추상화란 '구체적이지 않은' 정도의 의미로 약간 느슨한 개념을 가지고 있다.

LSP(The Liskov Substitution Principle, 리스 코브 치환의 원칙)

서브 타입은 언제나 기반 타입으로 교체할 수 있어야 한다. 상속은 구현 상속이든 인터페이스 상속이든 궁극적으로는 다형성을 통한 확장성을 목표로 한다. LSP 원리도 서브 클래스가 확장에 대한 인터페이스를 준수해야 함을 의미한다.

상속을 통한 재사용은 기반 클래스와 서브 클래스 사이에 IS-A 다형성 관계가 있을 경우로만 제한되어야 한다.

다형성과 확장성을 극대화하려면 하위 클래스를 사용하는 것보다는 상위 클래스(인터페이스)를 사용하는 것이 더 좋다.

상속은 다형성과 따로 생각할 수 없다. 다형성으로 인한 확장 효과를 얻기 위해서는 서브 클래스와 기반 클래스와 클라이언트 간의 규약(인터페이스)을 어겨서도 안 된다.

 

생각보다 이해하기 어려운 원칙이다...

  • 만약 두 개체가 똑같은 일을 한다면 둘을 하나의 클래스로 표현하고 이들을 구분할 수 있는 필드를 둔다.
  • 똑같은 연산을 제공하지만, 이들을 약간씩 다르게 한다면 공통의 인터페이스를 만들고 둘이 이를 구현(인터페이스 상속받아서)
  • 공통된 연산이 없다면 완전 별개인 2개의 클래스를 만든다.
  • 만약 두 개체가 하는 일에 추가적으로 무언가를 더 한다면 구현 상속을 사용하자.

확실한 건 생성 부분만 고치면 마음대로 어떤 컬렉션 구현 클래스든 사용할 수 있다는 거? => 다형성 장점

자바에서 ArrayList, LinkedList, Vector 대신 이들이 구현하고 있는 List를 사용하는 것이 좋다.

ISP(Interface Segregation Principle, 인터페이스 분리의 원칙)

한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다는 원칙이다.

어떤 클래스가 다른 클래스에 종속될 때에는 가능한 최소한의 인터페이스만을 사용하자. 

SRP가 클래스의 단일 책임을 강조한다면, ISP는 인터페이스의 단일 책임을 강조한다. 하지만 어떤 클래스 혹은 인터페이스가 여러 책임 혹은 역할을 갖는 것을 인정한다.

 

  • 클래스의 상속을 이용하여 인터페이스를 나눌 수 있다. 이와 같은 구조는 클라이언트에게 변화를 주지 않을 뿐 아니라 인터페이스를 분리하는 효과를 가진다. 
  • 위임을 이용하여 인터페이스를 나눌 수 있다. 위임이란, 특정 일의 책임을 다른 클래스나 메소드에 맡기는 것이다. 만약 다른 클래스의 기능을 사용해야 하지만 그 기능을 변경하고 싶지 않다면, 상속 대신 위임을 사용하자.
  • 어떤 클래스에 굉장히 많은 메소드들이 구현되어 있을 때, ISP가 제안하는 방식에서는 모든 인터페이스 분리를 통해 특정 역할만을 이용할 수 있도록 해준다. 이벤트 처리와 관련해서는 여러 리스너 인터페이스를 통해 해당 기능만 노출한다.

DIP(Dependency Inversion Principle, 의존성 역전의 원칙)

구조적 디자인에서 발생하던 하위 레벨 모듈의 변경이 상위 레벨 모듈의 변경을 요구하는 위계관계를 끊는 의미의 역전이다.

실제 사용 관계는 바뀌지 않으며, 추상을 매개로 메시지를 주고받음으로써 관계를 최대한 느슨하게 만드는 원칙이다.

 

정리

객체지향 원칙과 사고방식이 중요하지만, 이것보다 더 우선해야 할 것이 고객의 요구사항대로 동작해야 된다는 것이다. 아무리 객체지향 원칙을 적용하고 멋진 패턴을 사용하여 확장성이 뛰어나고 유연하게 설계가 되었다 하더라도 오동작하거나 동작하지 않는 프로그램이라면 쓸모없게 되는 프로그램이라는 것을.

 

오늘 공부한 SOLID 객체지향 원칙은 반드시 '고객의 만족'을 충족한다는 전재하에 적용돼야 한다.

 

참고글 :)

넥스트리

'Unity' 카테고리의 다른 글

[Unity] ios unitywebrequest.get  (0) 2021.06.28
[Unity] RemoveListener, RemoveAllListener  (0) 2021.04.15
[Unity] 소수점 처리  (0) 2021.04.14
[Unity] text component  (0) 2021.04.03
[Unity] RectTransform width height 변경하는 방법  (0) 2021.04.02

도입 배경

게임을 개발할 때 시간과 관련해서 처리를 할 때가 있다.

지금 개발하고 있는 게임에서는 시간과 관련해서 처리해야 하는 것들이 존재하고,

동시에 사용자로 인해 시간을 조작할 수 없도록 하기위해서 인터넷 시간을 받아와 운영할 수 있게 했다.

IEnumerator GetCurrentTime() 
{
    UnityWebRequest request = new UnityWebRequest();
    using (request = UnityWebRequest.Get(url))
    {
        yield return request.SendWebRequest();

        if (request.result == UnityWebRequest.Result.ConnectionError)
        {
            Debug.Log("Failure get current Time in GoogleNTP!");
        }
        else
        {
            // 서버에서 응답하는 패킷 중에 Date 정보만 추출해서 가져온다.
            string date = request.GetResponseHeader("date");
        }
    }
}

안드로이드에서는 구동하는데에는 문제가 없었는데, IOS에서 구동하는 데에서는 읽어올 수 없었다.

이유를 알아보니까, IOS에서는 Secure 하지 않다는 이유로 http 프로토콜을 기본적으로 차단하고 있었다.

그래서 기존에 사용하는 url에 http를 통해 받아올 수 없었던 것 같다. (IOS는 기본적으로 http 통신이 불가능)

 

간단하게 해결한 방법은 기존의 사용하던 http 프로토콜을 https 프로토콜로 변경해서 사용하니까 정상적으로 작동했다. 그렇지만, http로 해결해야 하는 경우는 info.plist에서 App Transport Security Settings를 수정해야 한다고 한다.

https://www.hahwul.com/2019/03/11/ios-app-http-app-trasport-security/

 

iOS App에서 HTTP 통신 허용하기(+App Trasport Security란?)

Security engineer, Developer and H4cker

www.hahwul.com

주의할 점

 

ios 9.0 이전에서는 NSAllowsArbitraryLoads가 true이면 하위 옵션들의 설정과는 관계없이 무조건 true이지만, ios 10.0 이상에서는 NSAllowsArbitraryLoads가 trud여도 하위 옵션들이 있다면 최상위 옵션이 무시된다고 한다.

따라서 최상위 옵션만 사용하고 싶다면 하위 옵션들은 삭제하자. (물론 하위 옵션들도 사용한다면 다 체크해줘야 한다.)

 

info.plist에 추가할 때, 첫 번째 <dict> 태그 밑에 넣어줘야 한다고 한다.

https://aerimforest.tistory.com/144

 

iOS HTTP 통신 허용하기

iOS에서 HTTP 통신을 하려는 경우 App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist fil..

aerimforest.tistory.com

정리

좋은 방법은 http -> https 로 바꿔서 보안적인 방법으로 사용하는 것이 가장 좋지만, http 사용이 필요하다면 위의 처럼 따로 옵션을 추가해줘야 한다.

 

ios 정책상 ios 9.0 부터 생겼다고 하는데 확실히 폐쇄적인 정책? 보다는 보안에도 신경을 많이 쓴 부분이 보인다.

'Unity' 카테고리의 다른 글

SOLID, 객체지향 원칙  (0) 2021.08.15
[Unity] RemoveListener, RemoveAllListener  (0) 2021.04.15
[Unity] 소수점 처리  (0) 2021.04.14
[Unity] text component  (0) 2021.04.03
[Unity] RectTransform width height 변경하는 방법  (0) 2021.04.02

한동안 엄청 고생했던 것을 바탕으로 작성한다.

 

Unity 상에서 Button에 이벤트를 할당하는 방법은 2가지가 있다.

직접 Inspector 창에서 매핑하기

스크립트 상에서 할당하기

using UnityEngine.UI;

GoPCBtn.onClick.AddListener(func);

 

보통은 매핑하기 힘들거나 코드를 한눈에 파악하기 힘들 때 사용하는 방법이 스크립트 상에서 할당하는 것이다.

가끔 Button 에 이벤트를 추가할 때 기존에 추가한 이벤트를 지우고 싶은 순간이 찾아오게 된다.

예를 들어 활성화될 때마다 리스너를 추가한다던가, 한 Popup 안에서 다양한 기능들을 스위칭해서 사용하는 경우

이때 사용하는 것이 바로 RemoveListener 혹은 RemoveAllListener이다.

 

알아둬야 할 점이 RemoveListener와 RemoveAllListener는 Editor에서 매핑시켜준 이벤트(메서드) 들은 제거되지 않고

스크립트 상에서 추가한 리스너들만 제거한다는 것이다.

 

Unity 레퍼런스에서도 읽어보면

런타임 중에 추가된 "비 영구" 리스너만 제거합니다. 영구 리스너들은 제거할 수 없습니다.

비 영구 리스너?

스크립트에 의해 추가 된 리스너들을 말한다.

 

영구 리스너

Editor 상에 Inspector에서 매핑시킨 리스너들은 Inspector 상에서만 제거할 수 있다.

 

결론

내가 스크립트에서 리스너를 할당했으면 RemoveListener 나 RemoveAllListener를 이용하고,

Inspector 창에서 리스너를 할당했으면 Inspector 창에서 지워야 한다.

 

'Unity' 카테고리의 다른 글

SOLID, 객체지향 원칙  (0) 2021.08.15
[Unity] ios unitywebrequest.get  (0) 2021.06.28
[Unity] 소수점 처리  (0) 2021.04.14
[Unity] text component  (0) 2021.04.03
[Unity] RectTransform width height 변경하는 방법  (0) 2021.04.02

소수점 처리가 필요한 경우는 아래와 같이 장인의 기운을 표시할 때 사용할 수 있다.

이럴 때 바로 포맷 함수를 이용하면 편하다.

 

장인의 기운이 30.13333 이라고 할 때

다음과 같이 소수점 둘째 자리까지 표기는 아래와 같이 하면 된다.

using System;

craftsmanship.text = string.Format("{0:0.##}", 표기할 수치) + "%";

Format

콜론 앞에 있는 부분은 Format에 들어갈 매개변수

 

콜론 뒤에 부분은 소수점 자릿수를 표시

 

'#'은 값이 있으면 표시하고 없으면 표시하지 않는다.

'Unity' 카테고리의 다른 글

SOLID, 객체지향 원칙  (0) 2021.08.15
[Unity] ios unitywebrequest.get  (0) 2021.06.28
[Unity] RemoveListener, RemoveAllListener  (0) 2021.04.15
[Unity] text component  (0) 2021.04.03
[Unity] RectTransform width height 변경하는 방법  (0) 2021.04.02

UI를 개발하다가 보면, Text component를 자주 사용하게 된다.

그런데 가끔 모르는 부분도 만지다 보면 '이렇게 사용하는 게 맞나?' 싶은 생각이 자주 들 때가 있다.

항상 개발하면서 Text component에 대해서 궁금했는데, 이번에 한 번 정리해볼까 한다.

 

Text Component는 아래와 같이 생겼다.

 

Text 표시할 텍스트를 넣는다.
Font 텍스트의 폰트 지정
Font Size 폰트 크기
Line Spacing 상, 하 글 간격을 띄워준다.
Rich Text 입력 텍스트를 마크업 형식으로 표현할지 여부
ex) <color=#0000ff>black</color>
사용하지 않는다면 끄는 게 좋다고 한다.
Alignment 텍스트를 정렬하는 기능이다. 자주 사용한다.
Horizontal Overflow 가로 영역을 넘어선 글의 처리 방식을 설정한다.
Wrap은 다음 행으로 내려쓰는 것이고
Overflow는 가로 영역을 넘어가도록 허용하는 것이다.
Vertical Overflow 세로 영역을 넘어선 글의 처리 방식이다.
Truncate는 넘어간 글자는 잘라내어서 미표시하고
Overflow는 세로 영역을 넘어가도록 허용하는 것이다.
Best Fit Font size를 무시하고 Text 컴포넌트의 범위에 맞게 크기를 조정한다. 간편하지만 성능에 좋지 않다고 한다.
Color Text의 색상을 지정할 수 있다.
Material Text에 별도의 티리얼을 적용할 수 있다.
Raycast Target On하면 해당 클릭할 때 반응할 수 있게 한다.
아니라면 꺼놓자.
Maskable 마스킹을 허용하는지 여부

 

'Unity' 카테고리의 다른 글

SOLID, 객체지향 원칙  (0) 2021.08.15
[Unity] ios unitywebrequest.get  (0) 2021.06.28
[Unity] RemoveListener, RemoveAllListener  (0) 2021.04.15
[Unity] 소수점 처리  (0) 2021.04.14
[Unity] RectTransform width height 변경하는 방법  (0) 2021.04.02

자주 찾아보게 되어서 포스팅으로 작성하기로 했다.

rectTransform.sizeDelta = new Vector2(width, height);

'Unity' 카테고리의 다른 글

SOLID, 객체지향 원칙  (0) 2021.08.15
[Unity] ios unitywebrequest.get  (0) 2021.06.28
[Unity] RemoveListener, RemoveAllListener  (0) 2021.04.15
[Unity] 소수점 처리  (0) 2021.04.14
[Unity] text component  (0) 2021.04.03

+ Recent posts