영구적 기능성 - 유창한 인터페이스에 대한 링크 호출

저자 Federico Kereki
링크 호출은 유창한 인터페이스를 설계하는 방법으로 반대로 더욱 뚜렷하고 이해하기 쉬운 코드를 작성할 수 있다.
명확한 API는 어떻게 설계합니까?더욱 구체적으로 말하면 어떻게 API를 더욱 쉽게 사용할 수 있습니까?"링크"의 "유창한 인터페이스"개념을 바탕으로 개발자에게 더욱 간소화된 개발 체험을 제공할 수 있습니다.본 시리즈의 이전 두 편의 기사(herehere)에서 우리는 성능을 어떻게 향상시키는지 연구했고, 지금은 선명도와 가용성을 어떻게 향상시키는지에 중점을 둘 것이다.

쇠사슬은 무엇입니까?


조합과 유수선은 기능성 작업을 할 때 일련의 전환을 응용하는 흔한 모델이다.그러나, 수조나 대상을 처리할 때, 이 호출을 연결하는 또 다른 방법이 있다. 바로 그것들을 연결하는 것이다.모두가 알고 있는 예는 map(...) 또는 filter(...)입니다. 모두 새로운 그룹으로 되돌아와서 더 많은 호출을 할 수 있습니다.사소한 일로 (좀 오버!)예를 들어, 우리 Mastering JavaScript Functional Programming 책의 코드를 좀 봅시다.기본적으로 무의미한 작업을 정의하는 것부터 시작할 수 있습니다.
const testOdd = x => x % 2 === 1;
const testUnderFifty = x => x < 50;
const duplicate = x => x + x;
const addThree = x => x + 3;
이제 매핑 및 필터를 순서대로 어레이에 적용할 수 있습니다.
  • 우선 짝수를 삭제합니다.
  • 그러면 우리는 남은 것들을 복제할 것이다.
  • 우리는 50 이상의 결과를 필터할 것이다.
  • , 나머지 부분에 3을 추가합니다.
  • const myArray = [22, 9, 60, 24, 11, 63];
    
    const a0 = myArray
      .filter(testOdd)
      .map(duplicate)
      .filter(testUnderFifty)
      .map(addThree);
    // [ 21, 25 ]
    
    .map(...).filter(...) 작업은 새로운 그룹을 되돌려줍니다. 더 많은 작업을 적용할 수 있습니다.너는 아래의 몇 줄에서 이렇게 할 수 있지만, 이것은 분명하지 않다는 것에 동의할 수 있기를 바란다.(예를 들어 독자들은 x1, x2x3이 다시 사용될지 궁금하다.)다음은 대체 코드입니다.
    const x1 = myArray.filter(testOdd);
    const x2 = x1.map(duplicate);
    const x3 = x2.filter(testUnderFifty);
    const a0 = x3.map(addThree);
    // [ 21, 25 ]
    
    따라서 링크는 작업이 일부 대상을 되돌려주고 더 많은 작업을 적용할 수 있음을 의미합니다.그 자체가 흥미롭지만'유창한 인터페이스'의 상하문에서 더 의미가 있으니 아래에서 토론하겠습니다.

    무엇이 유창한 인터페이스입니까?


    무엇이'유창한 인터페이스'입니까?이 용어는 마틴 폴러(Martin Fowler) back in 2005이 발명했다.그 생각은 링크 방법이 호출되기 때문에 코드가 더욱 명확해져 거의 특정한 영역의 언어가 될 것이다.fluent API는 사용자가 처리하고 있는 영역과 비슷한 용어(방법)를 사용하도록 크게 설계되었습니다.나는 이런 해석이 이해하기 어려울 수도 있다는 것을 인정한다. 그러니 몇 가지 예를 보자.
    fluent 인터페이스를 실현하는 유명한 라이브러리는 jQuery이다.예를 들어, DOM 요소에 액세스하고 특정 등록 정보를 설정하고 CSS를 추가하며 한 줄에 요소가 표시되도록 다음 컨텐트를 작성할 수 있습니다.
    $("#titlephoto")
      .attr({
        alt: "Street scene",
        title: "Pune, India",
      })
      .css("background-color", "black")
      .show();
    
    너는 몇 줄에서 같은 결과를 얻을 수 있지만, 이것은 더욱 깨끗하다.또 다른 예: 테스트 프레임워크 Jest은 어디에나 유창한 인터페이스를 적용했다.예를 들어 아날로그 함수를 정의할 수 있습니다. 이 함수는 한 줄에true를 한 번 되돌려주고false를 되돌려주며, 이 점에서undefined를 되돌려줍니다.
    const fakeTest = jest
      .fn()
      .mockReturnValueOnce(true)
      .mockReturnValueOnce(false)
      .mockReturnValue(undefined);
    
    마지막 예를 보도록 하겠습니다.유행하는 D3.js 라이브러리도 이런 스타일로 몇 가지 방법을 연결해서 사용한다.
    d3.select("svg")
      .append("text")
      .attr("font-size", "20px")
      .attr("transform", "translate(100,0)")
      .attr("x", 150)
      .attr("y", 200)
      .text("Sample Chart Title");
    
    유창한 인터페이스 개념의 관건은 어떤 방식으로 당신의 사고방식을 모방하는 데 있다. ('그래, 이런 요소를 선택하고 텍스트를 추가하고 글씨체의 크기를 바꾸자...)코드를 더욱 쉽게 이해하게 하다.링크 방법 호출은 이 점을 실현하는 방법이지만, 비교적 짧은 코드를 작성하거나 추가 중간 변수가 필요하지 않도록 허용하는 방법으로만 간주해서는 안 된다.간결함과 간결함은 편리하지만 링크 모델을 사용하는 가장 좋은 이유는 아니다.반면 링크를 유창한 인터페이스 개발의 수단으로 고려하고 있다.
    이 점을 감안하여 어떻게 자신의 코드를 위해 이 모델을 실현할 수 있는지 생각해 봅시다.

    DIY:링크 메소드 호출


    우리는 어떻게 링크 가능한 방법을 실현합니까?첫 번째 해결 방안은 수동으로 조작하는 것이다. 이것은 아마도 가장 간단할 것이다.마지막으로, 우리는 모든 방법을 return this으로 수정하기만 하면 됩니다. 분명히 다른 내용을 되돌려야 하는 방법은 제외됩니다.이것은 당연히 해결 방안이지만, 우리는 더 적은 일을 필요로 하는 것들을 생각할 수 있다. 대리 대상은 일종의 가능성이다.
    proxy object은 다른 대상에 대한 호출을 차단하고 작업 방식을 다시 정의할 수 있습니다.어떤 에이전트를 실현하든지 간에, 에이전트를 제공함으로써 그것을 실현할 수 있다.우리는 하나의 종류를 대리할 수 없음을 주의하십시오.우리는 모든 대상을 단독으로 대리해야 한다.
    우리의 예에서, 우리는 모든 방법의 호출을 차단하고, 그것들이 대상 자체에 대한 인용으로 되돌아오기를 희망한다.물론 이 방법이 다른 내용을 되돌려주지 않는 한이것은 작은 문제를 가져왔다. 우리는 어떤 방법이 아무런 내용도 되돌려 주지 않았는지 어떻게 검사하는가.기본적으로 자바스크립트의 작업 방식은 return undefined 문장이 함수나 방법에 추가된 것과 같습니다. 그렇지 않으면 어떤 내용도 되돌아오지 않습니다. 따라서 클래스에서 실제 undefined으로 되돌아갈 수 있는 방법이 있다면 저희는 골치 아프게 됩니다.
    이 에이전트의 실현 방식은 다음과 같다.makeChainable(...) 함수는 하나의 대상을 링크 가능한 대체 대상으로 변환하고 모든 방법(undefined을 되돌려주지 않음)은 대상 자체에 대한 인용을 되돌려줍니다.
    const makeChainable = (obj) =>
      new Proxy(obj, {
        get(target, property, receiver) {                        /* 1 */
          return typeof target[property] === "function"          /* 2 */
            ? (...args) => {                                     /* 3 */ 
                const result = target[property](...args);        /* 4 */
                return result === undefined ? receiver : result; /* 5 */
              }
            : target[property];                                  /* 6 */
        }
      });
    
    프로세서는 다양한 작업 및 액세스 유형에 대해 여러 트랩을 제공합니다.우리는 목표 방법이나 속성을 생성하는'get'호출을 차단하기를 원합니다(1).목표가 함수 (2) 라면 수정된 함수를 되돌려줍니다. 이 함수는 원시 방법과 같은 매개 변수 (3) 를 받아들이고, 이 방법 (4) 을 호출한 다음, 결과가 정의되지 않았는지 테스트합니다. 이 경우, 프록시 대상 (5) 에 대한 인용을 되돌려줍니다.만약 목표가 함수가 아니라면 그것은 속성에 대한 접근이다.우리는 그것을 돌려보냈다.

    오픈 소스 세션 재방송


    생산 환경에서 웹 응용 프로그램을 디버깅하는 것은 어렵고 시간도 소모될 수 있다.OpenReplay은 FullStory, LogRocket, Hotjar의 소스 대체품이다.사용자가 한 모든 것을 감시하고 재방송할 수 있으며, 모든 문제에 대한 응용 프로그램의 표현을 보여 줍니다.
    이것은 브라우저의 검사기를 열고 사용자의 어깨를 보는 것과 같다.
    OpenReplay는 현재 유일하게 사용할 수 있는 오픈 소스 대안입니다.

    즐거운 디버깅, 현대 전단팀-Start monitoring your web app for free.

    암흑가의 예


    만약 우리가 30년대의 폭도 데이터를 포함하는 프로그램을 개발하고 있다면, 아마도 우리는 새로운 '터치할 수 없는' 영화를 만들고 있을 것이다.우리는 범인의 이름과 성씨, 그리고 그의 닉네임이나 별명을 기록할 수 있는 종류가 있다.
    class Mobster {
      constructor(firstName, lastName, nickname) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.nickname = nickname;
      }
    
      setFirstName(newFirst) {
        this.firstName = newFirst;
      }
    
      setLastName(newLast) {
        this.lastName = newLast;
      }
    
      setNickname(newNickname) {
        this.nickname = newNickname;
      }
    
      getFullName() {
        return `${this.firstName} "${this.nickname}" ${this.lastName}`;
      }
    }
    
    이러한 유형의 객체는 원래 상태로 링크할 수 없습니다.이 세 setter는 return this을 지원하지 않기 때문에 연결 방법이 없습니다.물론, 우리는 아래의 몇 줄을 추가해서 이 종류를 다시 쓸 수 있다.하지만 우리는 더 좋고 실용적인 방법을 찾을 것이다.
    class Mobster {
      constructor(...) { ... }
    
      setFirstName(newFirst) {
        this.firstName = newFirst;
        return this;                 /* added */
      }
    
      setLastName(newLast) {
        this.lastName = newLast;
        return this;                 /* added */
      }
    
      setNickname(newNickname) {
        this.nickname = newNickname;
        return this;                 /* added */
      }
    
      getFullName() { ... }
    }
    
    새로운 링크 가능한 대상을 만드는 과정을 간소화하기 위해서 우리는 조수를 작성하거나 먼저 대상을 만들고 링크를 할 수 있도록 할 수 있다.가장 좋은 것은 한 걸음에 도착하는 것이다.우리가 필요로 하는 조수는 이 두 단계를 동시에 완성한다.
    const makeMobster = (...args) => makeChainable(new Mobster(...args));
    
    현재 우리는 다음과 같은 코드를 작성할 수 있다.
    const gangster = makeMobster("Alphonse", "Capone", "Al");
    console.log(gangster.getFullName());
    // Alphonse "Al" Capone
    
    console.log(
      gangster
        .setFirstName("Benjamin")
        .setLastName("Siegel")
        .setNickname("Bugsy")
        .getFullName()
    );
    // Benjamin "Bugsy" Siegel
    
    링크를 사용하면 창설 대상을 바꾸는 방식으로 코드를 유창하고 읽을 수 있는 코드로 설계할 수 있습니다!

    요약


    자신의 API를 설계할 때, 유창한 인터페이스를 사용하면 더욱 쉽게 사용할 수 있는 라이브러리를 만들 수 있다.링크는 이러한 모델을 실현하는 관건이다. 함수식 프로그래밍은 모든 대상을 링크가 가능한 등효 대상으로 변환할 수 있으며 수동으로 조작할 필요가 없다.이런 기술이 있으면 당신의 코드는 더욱 간단하고 이해하기 쉬워질 것이다.해봐!

    좋은 웹페이지 즐겨찾기