원시 미혹증의 치료 방법

무엇이 원시적인 미치광이입니까?


우선, 원어는 대부분의 언어에서 사용할 수 있는 기본 데이터 형식이다.문자열, 숫자 (int,float), 브리 값 등 데이터 형식을 포함합니다.
원시 곤란은 일종의 코드 냄새이다. 이런 냄새에서 원시 데이터 유형은 데이터 모델을 나타내는 데 과도하게 사용된다.원어의 문제는 그것들이 매우 보편적이라는 것이다.예를 들어 문자열은 이름, 주소, 심지어 ID를 대표할 수 있습니다. 왜 이것이 문제입니까?
  • 모델에 특정한 논리나 행위를 포함할 수 없다. 이것은 모든 논리가 포함 클래스에 저장되어야 한다는 것을 의미한다.이것은 귀하가 최종적으로 상관없는 논리를 포함하는 많은 종류를 얻게 된다는 것을 의미합니다. 이것은 단일 책임 원칙 read more here 에 위반됩니다.

  • 그들은 안정감을 잃었다.밧줄 한 가닥이 밧줄 한 가닥이다.컴파일러는 이름이나 주소를 나타내는 문자열을 전달했는지 알 수 없습니다.이것은 의외로 잘못된 필드에 값을 부여하기 쉽다는 것을 의미한다. 코드는 데이터가 완전히 혼란스러울 때까지 정상적으로 실행되고 컴파일될 것이다.
  • 다른 한편, 제가 직장 생활에서 자주 만나는 분야는 IDs입니다.id를 정수로 표시하는 것은 매우 흔한 일입니다. 플러그인 대상 (대상마다 자신의 id가 있음) 에 대해 필터 논리를 실행하려고 하면 의외로 잘못된 id를 사용하기 쉽습니다. 코드가 잘 컴파일되어 처음에는 정상적으로 작동할 것 같았지만, 뒤이어 추적하기 어려운 이상한 오류가 발생했습니다.

  • 원시 미혹증을 치료하다


    다음은 원시적으로 어려움을 겪는 Person 유형의 예입니다.
    public class Person
    {
        public Person(string id, string firstName, string lastName, string address, string postcode, string city, string country)
        {
            // initialisation logic
        }
    
        public string Id { get; set; }
    
        public string FirstName { get; set; }
        public string LastName { get; set; }
    
        public string Address { get; set; }
        public string PostCode { get; set; }
        public string City { get; set; }
        public string Country { get; set; }
    
        public void ChangeAddress(string address, string postcode, string city, string country)
        {
            // change address logic
        }
    }
    
    여기 왜 이래?우리는 완전히 문자열 속성으로 구성된 클래스가 있다.구조 함수는 긴 문자열 매개 변수로 구성되어 있습니다. 어느 순간 잘못된 값이 잘못된 매개 변수 슬롯에 분배될 것을 보장합니다.우리도 주소를 바꾸는 방법이 하나 있지만, 실제로 이런 논리는 Person 클래스가 책임져서는 안 된다.마지막으로 ID도 문자열이므로 다른 유형의 ID로 예기치 않게 사용될 수 있습니다.
    그럼 우리 어떡하지?
    우리가 먼저 보아야 할 것은, 어떤 속성이 한데 조합될 수 있느냐는 것이다.이것에 대한 좋은 테스트는 이 속성 중 어떤 것들이 함께 업데이트될 수 있습니까?예를 들어 주소, 우편 번호, 도시, 국가 필드는 분명히 그룹을 나누어야 한다. (이사를 가면 모든 속성이나 대부분의 속성이 함께 업데이트될 가능성이 높다.)그러면 우리는 이러한 속성을 그것들의 종류로 재구성할 것이다.
    public class Address
    {
        public Address(string address, string postCode, string city, string country)
        {
            // initialisation logic
        }
    
        public string Address { get; set; }
        public string PostCode { get; set; }
        public string City { get; set; }
        public string Country { get; set; }
    }
    
    public class Person
    {
        public Person(string id, string firstName, string lastName, Address address)
        {
            // initialisation logic
        }
    
        public string Id { get; set; }
    
        public string FirstName { get; set; }
        public string LastName { get; set; }
    
        public Address Address { get; set; }
    }
    
    우리의 개인 수업은 보기에 이미 많이 좋아진 것 같다.주소와 관련된 모든 논리는address 클래스에 봉인되어 있으며, 우리는 구조 함수에서 많은 문자열 파라미터를 제거하려고 노력했다.
    전체적으로 말하자면, 우리는 여전히 같은 수량의 문자열 속성을 가지고 있다는 것을 알 수 있습니다.최종적으로 데이터를 원어에 저장해야 할 수도 있기 때문에 매우 좋다.원시적인 미혹을 피하는 중요한 부분은 이러한 원시적인 요소를 정의가 좋은 대상에 봉하는 것이다. 이런 대상은 실제적으로 그들의 의미를 대표한다.
    다음에 처리해야 할 것은 ID입니다. 유형 보안을 ID로 복원하기 위해서 이른바 강력한 유형 ID를 만들 수 있습니다. 간단히 말하면, 이것은 해당 실체에 특정한 용기 대상에 봉인된 기본값입니다.예를 들어 PersonId 객체의 구현은 다음과 같이 보일 수 있습니다here.
    public readonly struct PersonId : IComparable<PersonId>, IEquatable<PersonId>
    {
        public string Value { get; }
    
        public PersonId(string value)
        {
            Value = value;
        }
    
        public static PersonId New() => new PersonId(Guid.NewGuid().ToString());
    
        public bool Equals(PersonId other) => this.Value.Equals(other.Value);
        public int CompareTo(PersonId other) => Value.CompareTo(other.Value);
    
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            return obj is PersonId other && Equals(other);
        }
    
        public override int GetHashCode() => Value.GetHashCode();
        public override string ToString() => Value.ToString();
    
        public static bool operator ==(PersonId a, PersonId b) => a.CompareTo(b) == 0;
        public static bool operator !=(PersonId a, PersonId b) => !(a == b);
    }
    
    public class Person
    {
        public Person(PersonId id, string firstName, string lastName, Address address)
        {
            // initialisation logic
        }
    
        public PersonId Id { get; set; }
    
        public string FirstName { get; set; }
        public string LastName { get; set; }
    
        public Address Address { get; set; }
    }
    
    이것은 매우 좋다. 왜냐하면 Person 클래스는 현재 자신의 PersonId를 ID로 사용하기 때문이다. 이것은 의외로 다른 유형의 ID로 사용할 수 없다. 왜냐하면 그것은 자신의 강한 유형의 ID를 가지고 있기 때문이다.
    그러나, 이 PersonId 정의가 좀 커서, 만들고자 하는 모든 강력한 ID에 대해 설명하기가 매우 번거롭다는 것을 알 수 있습니다.솔직히 이 장애는 C# 개발에서 여전히 강력한 유형 ID가 흔치 않은 원인일 수 있다.
    다행히도 C#9에서 우리는 새로운 기록 유형을 가지게 되었고, 이로써 강력한 유형의 ID를 정의하는 것이 더욱 쉬워졌기 때문에, 그것의 사용이 더욱 보편화되기를 희망합니다. (기록에 관한 내용을 더 많이 읽을 수 있습니다. here
    // PersonId as a record
    public record PersonId(string Value);
    
    // how to initialise
    var personId = new PersonId("my-id");
    
    네, 그렇습니다.이는 문자열 속성 이름이 Value인 PersonId 레코드를 선언하며 구조 함수를 통해 전달할 수 있습니다.레코드는 해당 속성의 값에 따라 자동으로 동일성을 설정하므로 선언에 다른 내용을 추가할 필요가 없습니다.

    F의 오리지널 마니아 #


    비록 본고는 주로 C#를 주목하고 위에서 응용한 모든 원칙을 F#에 사용할 수 있지만 나는 F#가 독특한 특성을 가지고 있어 주의할 필요가 있다고 생각한다.
    차별 연합은 F#(C#이 아닌 여러 언어)의 데이터 유형으로 상황에 따라 서로 다른 유형의 데이터를 되돌려받을 수 있다(차별 연합에 대한 자세한 정보는 참조here.흔히 볼 수 있는 예는 오류 처리입니다.
    type Result<'a> =
        | Data of 'a
        | Error of string
    
    위의 예시에서 함수가 일반적인 데이터 형식을 되돌려줄 수 있지만, 오류가 발생하면 문자열을 되돌려줍니다.

    그러나 대소문자를 구분하는 연합은 기본 유형의 포장기를 충당하고 함수에 유형 안전성을 제공할 수 있다.예를 들어 다음과 같은 개인 기록이 있을 수 있습니다.
    type Person = {
        FirstName: string;
        LastName: string;
        EmailAddress: string;
    }
    
    문제는 전자메일 주소가 사실상 하나의 문자열이 아니라 특정한 형식이 있기 때문에 우리는 이를 위해 특정한 검증 논리를 설계해야 할 수도 있다는 것이다.따라서 자신의 유형에 봉인하는 것이 좋다.노조를 일례로 차별하는 것은 정말 쉽다.
    type EmailAddress = EmailAddress of string
    
    type Person = {
        FirstName: string;
        LastName: string;
        EmailAddres: EmailAddress;
    }
    
    이제 Person 레코드는 EmailAddress 유형의 e-메일 주소만 받습니다.

    결론


    이 글에서 나는 원시적인 괴로움의 개념을 소개했다. 그것이 어떤 문제를 초래할 수 있는지, 그리고 그것을 어떻게 해결할 수 있는지.정보를 가져가서 자신의 코드 라이브러리에서 사용해서 더욱 안전하고 유지보수가 가능한 코드를 만들 수 있기를 바랍니다.
    나의 게시물은 주로 무더기에 관한 것이다.NET 및 Vue 네트워크 개발 (곧 더 많은 F# 컨텐츠가 있을 수 있음!)어떤 댓글도 놓치지 않도록 본 블로그와subscribe to my newsletter를 주목해 주십시오.만약 당신이 이 문장이 매우 유용하다고 생각한다면, 좋아하고 공유해 주십시오.너도 인터넷에서 나를 찾을 수 있다.

    좋은 웹페이지 즐겨찾기