복잡한 MVC 어플리케이션 처리 - 컨트롤러의 혼란을 확장하고 방지하는 방법


undabot.com 표지 사진 제공
본고는 Laravel를 코드 세션으로 사용하지만 이 범례는 다른 모든 MVC 프레임워크에 쉽게 적응할 수 있다.
더욱 흥미롭게 하기 위해 두 전문가 간의 허구적인 대화를 통해 본문을 선보일 것입니다.
Stan은 경험이 풍부한 개발자입니다. 그는 많은 구조 오류를 저질렀습니다(하지만 고맙습니다. 그는 그 중에서 교훈을 얻고 있는 것 같습니다).
Ollie는 엄격한 프로그래밍 분야에 막 깊이 연구하기 시작했고 간단한 응용 프로그램을 가지고 있는 초보 개발자이다.
다음은 대화의 과정입니다.

소개하다.


헤올리!오늘 여러분과 이야기하고 싶습니다MVC.MVC는 건장한 응용 프로그램을 구축하는 데 사용되는 유행하는 구조 모델이다.
잠깐만, MVC?저것은 무엇입니까?
[stan] MVC 대표Model - View - Controller.그것은 본질적으로 건장한 코드 설계 전략을 정의했다.응용 프로그램의 모듈 간에 더욱 높은 관심사 분리를 실현하기 위해 응용 프로그램을 다른 부분으로 분해한다.
더 많은 기능을 추가하거나 유지하려고 시도할 때 모듈화 코드가 큰 도움이 될 것이다.
다음 그림을 살펴보겠습니다.


그림 참조Wikipedia
[stan] 따라서 사용자는 보기와 상호작용을 하고 매번 상호작용을 할 때 관련 컨트롤러 방법을 호출한다. 그리고 이런 방법은 사용자에게 적당한 데이터를 업데이트/획득하는 것을 책임진다(마찬가지로 시청층을 사용한다).
알겠습니다!나는 이미 많은 종목에서 MVC를 사용했다.나 많이 알아!

일반적인 코드 예


너무 빨리 하지 마, 올리. 아직 보도할 게 많아.
이제 일반적인 자습서의 Laravel 컨트롤러 접근 방식을 살펴보겠습니다. 일반적으로 우리는 우연히 다음과 같은 사실을 알게 됩니다.

<?php  
namespace App\Http\Controllers;  

class HomeController extends Controller {  

  public function simpleMethod() {  

    $books = Books:all();
    foreach($books as $book) {
        // some business logic here...
    }
    return view('home.home')->with(['books' => $books]);  
  }  
}

[Ollie] 네, 이 코드는 간단해 보여요!
[stan] 만약에 우리가 그것을 단독 구성 요소로 분해해서 더 좋은 수익을 얻을 수 있다면?
우리 도대체 왜 이러는 거야?나는 이 코드를 좋아한다.간단하면서도 쓸모가 있다.그것은 어떤 특별한 점이 있습니까?
[스탄] 이 일은 특별해, 내 젊은 견습생!그것은 복잡한 응용 프로그램이라고 불린다.
비교적 작은 프로젝트에서 모든 내용을 컨트롤러 방법에 포함시키는 것은 매우 좋다.
잠깐만.. 무슨 소리야...?

층층이 구원하다.


[stan] 대부분의 애플리케이션이 어떻게 작동하는지 이해할 수 없을 것 같은데...전형적인 MVC 애플리케이션에는 다음과 같은 계층이 있습니다.
  • 인증 레이어
  • 비즈니스 논리 계층
  • 데이터베이스/라이브러리 레이어
  • 오류 처리 계층
  • 성공/오류 표시층
  • 솔직히 MVC 앱은 더 많은 층으로 세분화할 수 있지만, 가장 기본적인 층이다.만약 대부분의 강좌가 그것들을 생략한다면 다행이다.그들의 업무는 응용 프로그램을 어떻게 나누는지 설명하는 것이 아니라 본 강좌의 주제를 설명하는 것이다.
    [Ollie] 그래...그럼 내가 왜 내 신청서를 분해해야 되지?만약 내가 일부 기능을 추가하고 싶다면, 나는 나의 컨트롤러 방법에 추가할 수 있다.

    시간의 추이에 따라 엉망진창인 코드


    [stan] 물론, 너는 계속 이렇게 할 수 있지만, 어느 순간 코드가 중복되고, 매우 큰 컨트롤러 방법과 클래스, 그리고 전체적으로 나쁜 코드를 초래할 수 있다.
    이것이 바로 내가 복잡한 응용 프로그램에서 층을 나누는 것이 더 효과가 있다고 말하는 이유이다.
    만약 당신이 프로젝트를 확장할 생각이 없다면, 당신은 모든 것을 컨트롤러 방법에 남겨 둘 수 있습니다.
    응용 프로그램이 증가함에 따라 유지 보수는 갈수록 어려워진다.복잡성이 증가함에 따라 중용 모듈의 가치도 증가한다.우리는 우리가 기술 채무의 위험을 무릅쓰기 전에 반드시 조치를 취해야 한다는 것을 안다. 이것은 오히려 더욱 어려운 유지와 진일보한 개발을 초래할 것이다.
    한동안 더 많은 기능을 추가한 후에 예시된 코드를 봅시다.
    
    <?php  
    namespace App\Http\Controllers;  
    
    class BooksController extends Controller {
    
        public function complexMethod(HttpRequest $request) {
    
            $authorId = $request->author_id;
            if(!Author::find($authorId))
                // wrong data
                return back()->with('error','Wrong data');
            try {
    
                // this DB query needs to be duplicated if we want
                // to use it in another part of the code
                $books = Books::with('autor')
                ->with('reviews')->where(['author_id' => $authorId])
                ->get();
    
                foreach($books as $book) {
                    // some business logic here...
                    // this code snippet can turn out to be huge,
                    // since it grows with the application complexity.
                }
    
                return view('home.home')->with(['books' => $books]);
            } catch (Exception $e) {
                return back()->with('error', $e->getMessage());
            }
        }
    }
    
    
    
    아이고, 네 말이 맞다!나는 나의 응용 프로그램이 확장되기를 바란다.어떻게 코드를 더 많은 층으로 구분합니까?
    내 생각엔 그래.본질적으로 컨트롤러는 뷰(MVC의 V) 레이어와 상호 작용합니다.이것은 사용자의 입력을 처리하고 표시할 데이터를 되돌려야 한다는 것을 의미한다.
    더 많지도, 더 적지도 않다.

    누가 각 층을 책임집니까?


    그렇다면 이러한 계층을 수정하여 컨트롤러에 보관해야 할 계층과 분리해야 할 계층을 살펴보겠습니다.
  • 인증 계층
    이 층은 사용자가 입력한 데이터를 검증하는 것을 책임진다.MVC 그림에서는 근시 도면층에 매우 의존하기 때문에 컨트롤러 클래스에서 이루어져야 한다.
  • 비즈니스 논리 계층
    시간이 지날수록 이 층은 통상적으로 너무 복잡해진다.그것은 보기와 무관한 응용 프로그램의 업무 규칙을 정의했다.따라서 컨트롤러와 분리해서 업무 논리층의 다른 종류로 포장해야 한다.
  • 데이터베이스/라이브러리 레이어
    이 계층에는 애플리케이션의 DB 쿼리가 포함됩니다.많은 데이터 집약형 복잡한 응용 프로그램(예를 들어 실시간 시스템)에서 이 층 자체도 다른 응용 프로그램일 수 있다.따라서 컨트롤러에서 이루어지지 않고 데이터베이스/메모리 라이브러리층의 다른 클래스에서 이루어져야 한다.
  • 오류 처리층
    이상을 던질 때 우리는 어떻게 해야 합니까?상황을 보고 결정하다.아마도 우리는 이상을 로그 채널에 기록하고 특수한 조치를 취하고 싶을 것이다.
    대부분의 MVC 애플리케이션에서 오류를 사용자에게 알리고자 하므로 이 계층은 비즈니스 논리 계층과 컨트롤러 계층에서 구현되어야 합니다.
  • 레이어 성공/오류 표시
    이 층은 전 층과 결합한다.조작이 성공하거나 이상을 던질 때 사용자에게 알리는 것이 매우 중요하다.이 층은 컨트롤러와 보기 사이에 정의되어 컨트롤러 클래스에서 실현할 수 있다.
  • 와, 나 많이 배웠어!그래도 난 좀 곤혹스러워.내 컨트롤러는 지금 어떤 모양이어야 합니까?

    계층 코드


    잘 물었어!다음 예제를 참조하십시오.
    
    <?php
    namespace App\Http\Controllers;
    
    class BooksController extends Controller {
    
      protected $bookManager;
    
      function __construct() {
          $this->bookManager = new BookManager();
      }
    
      public function complexMethod(HttpRequest $request) {
          // VALIDATION LAYER
          // having all rules in a separate validationRules method
          // allows reusage
          $validator = Validator::make($request->all(), $this->validationRules($request));
    
          if ($validator->fails()) {
              return back()->with('error','Wrong data');
          }
    
          try {
              // BUSINESS LOGIC LAYER
              $books = $this->bookManager->getAllBooksForAuthor($request->author_id);
    
              // SUCCESS DISPLAY LAYER
              return view('home.home')->with(['books' => $books]);
          } catch (Exception $e) {
                //ERROR DISPLAY LAYER
            return back()->with('error', $e->getMessage());
          }
    
      }
    
    }
    
    [Ollie] 하지만 비즈니스 논리적 접근 방식과 데이터베이스/라이브러리 계층 접근 방식은 어디에 있습니까?
    [stan] 다른 수업에서 정의했죠!대상을 대상으로 프로그래밍을 하는 가장 좋은 부분 중 하나는 서로 다른 모듈을 다른 클래스로 포장하고 이런 클래스를 만드는 실례를 통해 사용할 수 있다는 것이다.
    (이전 예시의 구조 함수 참조).
    우리BookManager class:
    
    <?php  
    namespace App\BusinessLogicLayer\;
    use App\StorageLayer\BookRepository;
    
    class BookManager {
    
        protected $bookRepository;
        const PUBLISHED_BOOK_STATE = 1;
    
        public function __construct() {
            $this->bookRepository = new BookRepository();
        }
    
        public function getAllBooksForAuthor($authorId) {
            // here we can add all the business logic:
            // for example, we can check whether the author has any 
            // books that are in a DRAFT state, or we can check if the
            // author is the same user as the logged in user, in order
            // to display more data.
    
            $books = $this->booksRepository->getAllBooks([
                'state' => self::PUBLISHED_BOOK_STATE,
                'author_id' => $authorId
            ]);   
    
            foreach($books as $book) {
                // business logic here
            }
    
            return $books;
        }
    }
    
    [Ollie] 하지만 데이터베이스 조회도 보지 못했습니다.
    맞아요!데이터베이스 조회는 메모리 라이브러리/메모리 층에 있습니다. 기억하십니까?다음 과정을 살펴보십시오.
    
    <?php 
    
    namespace app\StorageLayer;
    use app\models\Book;
    
    class BookRepository {
    
        public function getAllBooks($attributesArray) {  
            return Book::where(attributesArray);  
        }
    
    }
    

    앞서가는 사고


    이 반은 아주 작지 않습니까?DB 쿼리를 비즈니스 논리 계층에 포함하는 것을 생략할 수 없습니까?
    [stan] 우리가 정확하게 축소하고 싶다면 안 할 거야.프로젝트가 성장함에 따라, 우리 클래스에서 복잡한 DB 조회를 해야 할 수도 있고, 심지어는 완전히 독립된 프로젝트에서 저장소 층을 전송해야 할 수도 있다는 것을 기억하십시오.
    와, 나는 정말 이런 것들을 생각하지 못했어!니가 맞았어.이 코드는 보기에 깨끗하고 확장이 가능하다.나는 이것이 더 많은 기능을 추가하는 것을 더욱 쉽게 할 것이라고 생각한다.
    [스탄] 맞아요.복잡한 애플리케이션에서는 다음을 따라야 합니다Open-closed principle.
    "소프트웨어 엔티티(클래스, 모듈, 함수 등)는 확장을 위해 열려 있지만 수정을 위해 닫아야 합니다."
    따라서, 오래 전에 컨트롤러 방법을 만들었고, 다른 클래스에서 정의한 층을 다시 사용하는 방법을 만들려고 하더라도, 새로운 컨트롤러 방법에서 관련 방법을 호출할 수 있습니다.
    너무 멋있어!나 지금 준비됐어!

    좋은 웹페이지 즐겨찾기