다 추상적인 아이에 관한 거예요.

Art by Lønfeldt에서 Unsplash의 "추상 아트"
나는 일생 동안 개발자로 경력이 약 10년이다.그 10년 동안 나는 줄곧 일을 완성할 수 있다고 생각했지만 추상적인 개념을 받아들이면 일이 정말로 나에게 영향을 미치기 시작했다.

무엇이 추상적입니까?
Wikipedia부터 시작:

Abstraction, in general, is a fundamental concept to computer science and software development. The process of abstraction can also be referred to as modeling and is closely related to the concepts of theory and design. Models can also be considered types of abstractions per their generalization of aspects of reality.


응, 그건 나한테 잘 모르겠어.라벨은 나에게 매우 어렵지만 나는'한 가지 일이 어떻게 일어나야 하는가'가 아니라'무슨 일이 일어나야 하는가'를 정의함으로써 추상을 개념 모델로 보는 경향이 있다.
추상은 개념이지 디테일이 아니다.사람들은 매일 추상적인 개념을 사용하지만, 추상적인 개념이 어떻게 작동하는지 반드시 세부 사항을 이해하는 것은 아니다.간단한 예는 자동차 액셀러레이터의 추상적인 개념이다.엔진의 내부 구조가 어떻게 작동하는지 모르겠지만, 페달 뒤의 생각은 자동차를 전진시키는 것이다.추상적인 소비자에게 추상적으로 어떻게 그 의도를 실현하는지의 세부 사항은 중요하지 않고 중요한 것은 그것이 해냈다는 것이다.

왜 추상이 중요합니까?
추상은 조직의 수단이며, 조직은 깨끗하고 따르기 쉬운 코드에 필요하다!추상화를 실현하는 전통적인 방법은 다음과 같다.
  • 커넥터
  • 개의 추상류(불가능!)
  • 단순 모델 클래스(이상적인 상황에서 속성은 행위가 없음)
  • 객체
  • 개의 행위를 가진 유형(디자인 측면에서 볼 때 가장 좋지 않은 추상적인 유형일 수 있지만?)
  • 네, 위의 목록에는 확실히 대부분의 언어 특성이 포함되어 있지만, 고위층 추상적인 측면에서 볼 때, 그 중 일부 요점은 다른 요점보다 더 유용할 수 있습니다.
    나는 인터페이스와 모형류가 개념 모델링에 가장 유용한 도구라는 것을 발견했다. 왜냐하면 그들은 너로 하여금 더욱 작은 범위 내에서 문제를 생각하게 하기 때문이다.앞에서 말한 바와 같이 인터페이스는 모두 정의 방법에 관한 서명이다 — 완성해야 할 것은'무엇'이지'어떻게'가 아니다.
    예를 들면 다음과 같습니다.
  • 일부 기준에 기반한 일련의 MyObject가 필요합니다.
  • (좋지 않은) 추상적인 단계를 통해 다음과 같은 클래스를 만들 수 있습니다.
    public class MyObjectDbRetriever
    {
     public IEnumerable<MyObject> GetMyObjects(MyObjectCriteria criteria)
     {
      // Connect to a database
      // Do some sql-ey stuff that limits the result set based on criteria
    
      return results;
     }
    }
    
    위의 코드가 잘 작동하고 (ish) 최종적으로'최종 결과'의 일부분이 되지만 호출자의 입장에서 볼 때 가장 좋은 코드는 아니다.
    호출자는 어떻게 이 코드들을 사용합니까?
    public class MyObjectController
    {
     public IEnumerable<MyObject> GetMyObjects()
     {
      // make up some criteria
      var myObjectCriteria = new MyObjectCriteria()
      {
       // some criteria
      }
    
      // Get the data
      var myObjects = new MyObjectDbRetriever()
       .GetMyObjects(myObjectCriteria);
     }
    }
    
    위의 클래스에서 호출자는 MyObjectDbRetriever과 밀접하게 결합된다.왜 이렇게 엉망이야?다음과 같은 몇 가지 이유가 있습니다.
  • 은 컨트롤러를 테스트하기 어렵다. 컨트롤러가 MyObjectDbRetriever을 직접 인용하기 때문이다.이것은 데이터베이스 논리가 없으면 컨트롤러 논리를 테스트할 필요가 없다는 것을 의미한다 — 단원 테스트를 매우 불가능하게 하다.
  • 은 상술한 내용과 관련이 있지만 나는 이 점을 지적해야 한다고 생각한다.컨트롤러는'어떻게'와 관련이 있는 것이지'무엇'과 관련이 있는 것이 아니다."MyObjectCriteria MyObjects이 아니라 데이터베이스에서 MyObjectCriteria이 필요합니다."MyObjects이 아닌
  • 이 필요합니다.

    왜 적당한 추상이 당신이 더 좋은 코드를 작성하는 데 도움을 줄 수 있습니까?
    위의 MyObject 예시부터 몇 가지 일을 바꾸자.현재의'어떻게'가 아니라 추상적으로'무엇'을 도입합시다.
    public interface IMyObjectRetriever
    {
     IEnumerable<MyObject> GetMyObjects(MyObjectCriteria criteria);
    }
    
    이제 우리는 하나의 계약, 하나의 생각, 하나의'무엇'의 추상적인 개념이 생겼다.이제 기존 MyObjectDbRetriever을 수정하여 이 인터페이스를 활용할 수 있습니다.
    public class MyObjectDbRetriever : IMyObjectRetriever
    {
     public IEnumerable<MyObject> GetMyObjects(MyObjectCriteria criteria)
     {
      // Connect to a database
      // Do some sql-ey stuff
    
      return results;
     }
    }
    
    이것은 이전에 사용한 종류와 완전히 같지만, 지금은 우리의 IMyObjectRetriever 생각을 실현시켰다.이것은 어떻게 컨트롤러의 상황을 바꿀 수 있느냐고 물어볼지도 모른다.아주 재미있는 방식으로!구체화가 아니라 인터페이스를 프로그래밍하고 있는 이상 주입에 의존하는 것이 우리의 선택이 되었다.
    의존 주입은 SOLID 설계 원칙의'D'를 실현하는 방법의 하나이다 — 의존이 뒤바뀌다.기본 사상은 고급 모듈(컨트롤러)이 저급 모듈(MyObjectDbRetriever)에 의존해서는 안 된다는 것이다.첫 번째 예에서, 이 원칙은 분명히 위반되었지만, 지금 그것을 방지하기 위해 어떤 변화가 있습니까?
    원래는 MyObjectController이었습니다.
    public class MyObjectController
    {
     public IEnumerable<MyObject> GetMyObjects()
     {
      // make up some criteria
      var myObjectCriteria = new MyObjectCriteria()
      {
       //
      }
    
      // Get the data
      var myObjects = new MyObjectDbRetriever()
       .GetMyObjects(myObjectCriteria);
     }
    }
    
    이러한 상황에서'고전평 모듈'컨트롤러는 MyObjectDbRetriever의'저전압 모듈'에 매우 의존한다.우리의 새로운 인터페이스와 구조 함수 의존 주입을 이용하여 우리는 이 점을 바꿀 수 있다!
    public class MyObjectController
    {
     private readonly IMyObjectRetriever _myObjectRetriever;
    
    public MyObjectController(IMyObjectRetriever myObjectRetriever)
     {
      _myObjectRetriever = myObjectRetriever;
     }
    
     public IEnumerable<MyObject> GetMyObjects()
     {
      // make up some criteria
      var myObjectCriteria = new MyObjectCriteria()
      {
       //
      }
    
      // Get the data
      var myObjects = _myObjectRetriever.GetMyObjects(myObjectCriteria);
     }
    }
    
    위의 실현에서 단지 몇 가지 일만 변화가 생겼다. 비록 그것들은 매우 중요한 변화이지만!현재 우리는 IMyObjectRetriever이 실현한 구조 함수를 받아들였다.함수 GetMyObjects은 구체적인db방법이 아닌 GetObjects(myObjectCriteria)의 인터페이스 방법을 사용합니다.컨트롤러 클래스는 더 이상 MyObjectDbRetriever 또는 데이터베이스에 의존하지 않습니다!현재 컨트롤러 클래스는 단지 데이터를 검색할 수 있는 인터페이스의 개념에 의존할 뿐, 컨트롤러 상하문에 대해 어떻게 하는지는 중요하지 않다 — 느슨한 결합!
    만약 컨트롤러를 호출하는 대상이 데이터를 되돌려 주는 성질에 따라 다른 행동을 한다면 어떻게 해야 합니까?상술한 변화는 우리가 현재 시뮬레이션, 모조품, 패드를 사용하여 test 컨트롤러를 더욱 쉽게 제어할 수 있다는 것을 의미한다.이전에 MyObjectDbRetriever을 사용할 때 우리는 우리의 데이터베이스가 실제 데이터베이스에서 특정한 데이터 수요를 되돌려 몇 가지 잠재적인 장면에 대한 수요를 확보해야 한다.현재 하나의 예로, 우리는 우리의 인터페이스를 실현하는 몇 가지 다른 종류를 내놓고, 우리의 테스트 수요에 따라 데이터를 되돌려줄 수 있다.
    public class MyEmptyFakeObjectRetriever : IMyObjectRetriever
    {
     public IEnumerable<MyObject> GetMyObjects(MyObjectCriteria criteria)
     {
      return new List<MyObject>();
     }
    }
    
    public class MyNullFakeObjectRetriever : IMyObjectRetriever
    {
     public IEnumerable<MyObject> GetMyObjects(MyObjectCriteria criteria)
     {
      return null;
     }
    }
    
    public class MyKritnerFakeObjectRetriever : IMyObjectRetriever
    {
     public IEnumerable<MyObject> GetMyObjects(MyObjectCriteria criteria)
     {
      return new List<MyObject>()
      {
       new MyObject("kritner")
      };
     }
    }
    
    위의 모든 클래스가 IMyObjectRetriever을 실현했기 때문에 가짜 클래스의 실례를 전송하여 특정 장면을 테스트할 수 있다.이런 상황에서 나는 보통 '' 을 사용하지만, 이런 모조품도 쉽게 시범을 보일 수 있다.
    나는 이것이 단지 추상적인 표면에 닿을 뿐이라고 생각하지만, 이것은 다른 사람들이 클릭할 때 도움을 줄 수 있기를 바란다.
    관련:
  • Getting started with unit testing and Moq
  • What is the business value of unit testing?
  • 좋은 웹페이지 즐겨찾기