Jak zorganizować dużą, złożoną aplikację internetową (patrz przykład podstawowy)?

Żeby było ciekawie i zamknąć moje ostatnie otwarte pytanie, rozwiązanie, które implementuje poniższą funkcjonalność w ładnie zorganizowany sposób z przyzwoitą architekturą, dostaje dobrą nagrodę. Pełny kod znajduje się na jsfiddle i nie krępuj się zadawać pytań:)

Jak zwykle organizujesz złożone aplikacje internetowe, które są niezwykle bogate po stronie klienta. Stworzyłem wymyślny przykład, aby wskazać rodzaj bałaganu, w który łatwo się dostać, jeśli sprawy nie są dobrze zarządzane dla dużych aplikacji. Możesz dowolnie modyfikować / rozszerzać ten przykład - http://jsfiddle.net/NHyLC/1/

Przykład zasadniczo odzwierciedla część komentarza zamieszczonego na SO i przestrzega następujących zasad:

  1. musi mieć minimum 15 znaków, po przycięciu wielu spacji do jedynki.
  2. If Add Comment is clicked, but the rozmiar jest mniejszy niż 15 po usunięciu wiele spacji, a następnie pokaż wyskakujące okienko z błędem.
  3. podaj ilość pozostałych znaków oraz podsumuj za pomocą kodowania kolorami. Szary oznacza mały komentarz, brązowy wskazuje na średni komentarz, pomarańczowy duży komentarz, a czerwony przepełnienie komentarza.
  4. można złożyć tylko jeden komentarz co 15 sekund. Jeśli komentarz jest przesłane za wcześnie, Pokaż wyskakujące okienko z odpowiednim komunikatem o błędzie.

Kilka problemów, które zauważyłem w tym przykładzie.

  • powinien to być idealnie widżet lub jakaś spakowana funkcjonalność.
  • coś jak komentarz na 15 sekundy i minimum 15-znakowy komentarz należą do niektórych zasad aplikacji, a nie są osadzane wewnątrz każdego widżetu.
  • zbyt wiele zakodowanych wartości.
  • brak organizacji kodu. Model, widoki, kontrolery są połączone razem. Nie, że MVC jest jedynym podejściem do organizowania bogatych aplikacji internetowych po stronie klienta, ale nie ma żadnego w tym przykładzie.
Jak byś to posprzątał? Zastosowanie trochę MVC / MVP po drodze?

Oto niektóre z istotnych funkcji, ale będzie to miało większy sens, jeśli zobaczysz cały kod w jsfiddle:

/**
 * Handle comment change.
 * Update character count. 
 * Indicate progress
 */
function handleCommentUpdate(comment) {
    var status = $('.comment-status');

    status.text(getStatusText(comment));
    status.removeClass('mild spicy hot sizzling');
    status.addClass(getStatusClass(comment));
}

/**
 * Is the comment valid for submission
 * But first, check if it's all good.
 */
function commentSubmittable(comment) {
    var notTooSoon = !isTooSoon();
    var notEmpty = !isEmpty(comment);
    var hasEnoughCharacters = !isTooShort(comment);

    return notTooSoon && notEmpty && hasEnoughCharacters;
}

/**
 * Submit comment.
 * But first, check if it's all good!
 */
$('.add-comment').click(function() {
    var comment = $('.comment-box').val();

    // submit comment, fake ajax call
    if(commentSubmittable(comment)) {
        .. 
    }

    // show a popup if comment is mostly spaces
    if(isTooShort(comment)) {
        if(comment.length < 15) {
            // blink status message
        }
        else {
           popup("Comment must be at least 15 characters in length.");
        }
    }
    // show a popup is comment submitted too soon
    else if(isTooSoon()) {
        popup("Only 1 comment allowed per 15 seconds.");
    }

});

Edytuj 1:

@matpol dzięki za sugestię dla obiektu wrappera i wtyczki. To będzie naprawdę duża poprawa w stosunku do istniejącego bałaganu. Jednak wtyczka nie jest niezależna i jak wspomniałem, byłaby częścią większej złożonej aplikacji. Ogólne zasady aplikacji po stronie klienta / serwera dyktowałyby takie rzeczy jak Minimalna / Maksymalna długość komentarza, jak często użytkownik może komentować itp. Z pewnością wtyczka może być podawana jako parametry.

Ponadto, dla bogatej aplikacji po stronie klienta, dane muszą być oddzielone od jej reprezentacji html, ponieważ wiele serwerowych podróży w obie strony może być zapisanych, ponieważ aplikacja jest świadoma danych i rzeczy mogą być przechowywane lokalnie, i okresowo aktualizowane na serwerze, lub na interesujące zdarzenia w samej aplikacji (np. gdy okno jest zamknięte). Oto dlaczego tak naprawdę nie lubię podejście wtyczki. Działałoby to tak, jak w dostarczaniu reprezentacji spakowanej, ale nadal byłoby skupione wokół DOM, co będzie problematyczne, gdy masz 20 takich wtyczek w aplikacji, co w żaden sposób nie jest absurdalną liczbą.

Author: Anurag, 2010-03-18

4 answers

/ Align = "left" /

  1. Enkapsuluj javascript w małych, dobrze zdefiniowanych klasach w przestrzeniach nazw
  2. klasy Javascript powinny mieć kod HTML, który wymaga "wtrysku" do nich jako zależności pozwalającej testować jednostki poza przeglądarką
  3. Przenieś jak najwięcej funkcji po stronie klienta do serwera i użyj koncepcji znanej jako AHAH

Javascript name-spacja

Można to łatwo osiągnąć i zostało pokryte w innych postach, takich jak ten czy istnieje "zwięzły" sposób na przestrzeni nazw w JavaScript?

Małe klasy zamknięte

Kod Javascript, podobnie jak kod po stronie serwera powinien być dobrze zamknięty za pomocą małych spójnych klas i metod. Każda klasa żyje w osobnym pliku, nazwanym wraz z przestrzenią nazw, w której się znajduje, np.: MyCompany.Jakieś opakowanie.MyClass.js. Nadmierne żądania HTTP do każdego pliku mogą być zapisywane poprzez łączenie i minifikowanie tych plików klas w czasie budowy.

Inwersja zależności w Javascript

Tak efektywnie zamiast wybierać elementy potrzebne do pracy wewnątrz klasy, jak to:

var MyNamespace.MyClass = function() {
  var elementINeed = $('#IdOfElementINeed');
}

Można by go wstrzyknąć w taki sposób:

var foo = new MyNamspace.MyClass($('#IdOfElementINeed'));

var MyNamespace.MyClass = function(incomingDependency) {
  var elementINeed = incomingDependency;
}

Ta technika dobrze nadaje się do testowania javscriptu i oddzielania obaw poprzezstyl MVC warstwowanie kodu.

AHAH i uproszczenie po stronie klienta

AHAH jest dość starym technika, która istnieje już od dłuższego czasu w tworzeniu stron internetowych, chociaż odradza się wśród miłośników stron internetowych ze względu na jej czystą prostotę. Jednak filozofia musi być kupiona na więcej niż poziomie techniki architektonicznej i musi być używana jako zamiennik dla całego javascript po stronie klienta, np.: Walidacja, Pokazywanie / ukrywanie dynamicznej zawartości, obliczenia itp]}

Gdzie może być dołączone zdarzenie onClick o złożoności po stronie klienta:

$('#someElement').click(function(){
  // insert complex client-side functionality here, such as validating input
  // eg var isValid = $(this).val() < minimumCommentLength;
  // update page based on result of javascript code
  // eg $('#commentTooLong').show();
})

Teraz po prostu uruchomisz żądanie ajax z powrotem na serwer, aby uzyskać nowy HTML i po prostu zastąpić wszystkie lub niektóre elementy, które Cię interesują jako takie:

$('#addCommentButton').click(function(){
  $.ajax({ 
    url: "/comment/add", 
    context: document.body, success: 
    function(responseHTML){
        $('body').html(reponseHTML);
      }});
})

Oczywiście jest to banalny przykład, ale gdy jest efektywnie używane, każde zdarzenie javascript na stronie, po prostu odpala identyczne żądanie ajax i zastąpienie HTML, znacznie zmniejszając ilość wymaganego kodu po stronie klienta. Przeniesienie go na serwer, gdzie można go skutecznie przetestować.

AHAH nay-sayers, will polemizować że nie jest to skuteczny sposób na uruchomienie strony internetowej, jednak używałem i widziałem tę technikę na stronach z dostępem do modemu 56K, a także masowo skalowane publiczne strony internetowe. Wynik jest oczywiście wolniejszy, ale nadal można produkować mniej niż 100 milisekund podróży w obie strony, co jest praktycznie natychmiastowe dla ludzi.

 23
Author: Xian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:25:06

Matpol podał dosłowne rozwiązanie konkretnych informacji. Twoja edycja oznacza, że szukasz odpowiedzi na bardziej hipotetyczne pytanie. Innymi słowy, szukasz "podejścia".

Odpowiadając na pytanie w ten sposób; pojedynczy przykład, który podałeś, jest trochę czerwonym śledziem. Jest to tylko jeden element w całej aplikacji i uniemożliwia nam "zobaczenie lasu z drzew". Czym jest Las? Pytanie, zadane jako takie, nie definiuje go. Ale Ja myślę, że wszyscy programiści zgodzą się, kiedy powiem, że praca nad projektem, który nie ma definicji, to koszmar. Więc przeformułuję twoje pytanie i odpowiem: "jaki jest proces definiowania projektu?"

Moja w zasadzie zadaje serię pytań:

  • jaki jest główny cel tej aplikacji?
  • Kiedy ma zostać uruchomiony? Gdybyśmy mieli uruchomić go w 1/4 tego czasu, które funkcje zachowałbyś?
  • które funkcje są absolutnie pewne, że zamierzasz potrzebujesz później?

Często, aby dotrzeć do sedna tych pytań, muszę zadać inne pytania biznesowe:

  • kto jest twoją publicznością?
  • Dlaczego zależy im na tej stronie? Co ich powstrzyma?
  • jak zamierzasz generować przychody?
  • Jakie jest twoje wezwanie do działania? Gdybyś mógł przekierować wszystkich użytkowników na jedną ścieżkę, co by to było?

Mam nadzieję, że te pytania zaowocują zestawem Podstawowy kod, który możesz uznać za swój rdzeń. Twój rdzeń, jak podejrzewałeś, prawdopodobnie nie pasuje do podejścia modułowego. I jak już zidentyfikowałeś, będziesz chciał rozbić ten rdzeń na układ modelu / widoku / kontrolera.

Ale jest nieuniknione, że będziesz musiał dodać design fluff. A to sprowadza nas z powrotem do twojego przykładu kodu - jego puszystości. Fluff należy do wtyczki, oddzielonej od rdzenia. Nie oznacza to, że wszystkie wtyczki powinny być dostarczane użytkownikowi w osobnym js pliki... ale w celach rozwojowych powinny być postrzegane jako modułowe i niezależne od podstawowej bazy kodu.

 4
Author: Matrym,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-07 06:27:20

Zamieniłbym go na wtyczkę jQuery lub obiekt statyczny.

Obiekt statyczny działa tylko jako rodzaj lub opakowanie. Chciałbym też podzielić go na mniejsze funkcje np.

init()
checkLength()
checkTime()

Więc możesz skończyć z czymś takim:

Widget = {

init:function(){//setup events etc},
checkLength:function(){},
checkTime:function(){},
doMessage:function(){}


}
 3
Author: matpol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-18 08:46:55

Obecny kod jest dobrym początkiem i może być "skalowany" do dużych aplikacji, które unikają kodowania na twardo i mają wyraźne oddzielenie MVC z kilkoma zmianami.

  • to powinien być idealnie widget lub jakiś rodzaj spakowanej funkcjonalności

Widżet ułatwi ponowne użycie funkcji komentarza i zapewni ponowne użycie na różnych stronach / aplikacjach. Rozszerz enkapsulację i rozdzielenie problemów nie tylko na prezentację, ale także na model widżetu. Gdy myślisz o polu komentarza, intuicyjnie myślisz o stanie komponentu jako o tekście komentarza, ale wszystkie parametry wpływające na jego zachowanie mogą być częścią jego modelu, w tym parametry walidacji. Tak więc, oprócz tekstu komentarza, chciałbym, aby Model zawierał:

  • mapowanie liczby znaków do kategorii size (zbyt mała, mała, średnia, duża, przepełnienie).
  • Maksymalna częstotliwość komentowania (15 sekund)

Model widgetu aktualizuje rozmiar-Kategoria po zmianie tekstu. Widok nasłuchuje zmian w size-category, a wartość size-category używana do aktualizacji klasy tekstowej w celu wytworzenia stylu CSS dla różnych długości komentarza. Kategoria rozmiar jest również sprawdzana po kliknięciu "Dodaj komentarz". Jeśli jest "zbyt mały" lub "przepełnienie", można wyświetlić wyskakujące okienko. Zauważ, że obsługa dodawania komentarza nie sprawdza liczby znaków - która jest izolowana w modelu - sprawdza kategorię rozmiaru. W razie potrzeby " dodaj komentarz" kontroler może używać tego samego mapowania liczby znaków do kategorii rozmiaru, które model używa do tworzenia przydatnych wiadomości dla użytkownika. Np. "komentarze muszą mieć co najmniej 15 znaków", gdzie 15 jest pobierane z mapy kategorii rozmiar.

Model zawiera również właściwość "liczba pozostawionych znaków", której zdarzenia zmiany są używane do aktualizacji interfejsu widżetu. Maksymalna liczba znaków jest pobierana z mapy kategorii znaku do rozmiaru.

  • coś jak komentarz na 15 sekundy i minimum 15-znakowy komentarz należą do niektórych zasad aplikacji, a nie są osadzane wewnątrz każdego widżetu.
  • zbyt wiele zakodowanych wartości.
  • Brak organizacji kodu. Model, widoki, kontrolery są połączone razem. Nie, że MVC jest jedynym podejściem do organizowania bogatych aplikacji internetowych po stronie klienta, ale nie ma żadnego w tym przykładzie.

Może być wiele rodzajów komentarzy (np. różne elementy komentowane) i różne typy komentarz-widget. Jeśli wszystkie powinny mieć ten sam minimalny/maksymalny zakres, to wszystkie powinny być parametryzowane tymi samymi wartościami modelu kontrolującymi walidację komentarza. Najlepiej jest to zrobić po stronie serwera podczas budowania danych dla modelu komentarza. Tekst komentarza jest pobierany dla tego konkretnego komentarza, a wartości walidacji komentarza, takie jak mapowanie kategorii rozmiaru, są pobierane z domyślnej konfiguracji strony lub aplikacji. Poprzez centralną logikę wytwarzania walidacji komponentu model, dodawanie nowych reguł staje się znacznie prostsze - np. "moderatorzy mogą dodawać komentarze do 1K", staje się zmianą w jednym kawałku kodu. Inną kwestią związaną z obliczaniem modelu komponentu po stronie serwera jest to, że model powinien być również walidowany po stronie serwera-Walidacja klienta jest bardziej wygodna dla użytkownika (niedogodność, którą niektórzy mogą pomyśleć!)- i nie jest to trudne egzekwowanie. JavaScript może być wyłączony, a żądania HTTP konstruowane niezależnie od klienta walidującego.

Podsumowując, wiele z można to postrzegać jako organizowanie produkcji modelu widżetu po stronie serwera. W ten sposób serwer może egzekwować reguły walidacji i chronić widżet przed złożonością reguł i konfiguracją dla całej aplikacji.

Nie wspomniałem o jQuery ani żadnej technologii UI, ponieważ ten wzór jest ważny dla aplikacji niezależnie od technologii UI. Sposób zastosowania wzorca będzie w pewnym stopniu specyficzny dla interfejsu użytkownika, na przykład sposób dostarczenia modelu walidacji do widżetu lub sposób podłącz słuchaczy do modelu, ale poziom organizacyjny wzorca jest ortogonalny do interfejsu użytkownika. Główny nacisk kładziony jest na model-rozszerzenie go o aspekty walidacji i obliczenie po stronie serwera it. Gdy już to nastąpi, problem organizacji jest prawie rozwiązany.

 1
Author: mdma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-13 18:36:16