Как бы вы организовали большое сложное веб-приложение (см. Базовый пример)? - PullRequest
17 голосов
/ 18 марта 2010

Просто чтобы сохранить интерес и закрыть мой последний открытый вопрос, решение, которое реализует перечисленные ниже функции в хорошо организованной манере с достойной архитектурой, получает хорошую награду. Полный код на jsfiddle, и не стесняйтесь задавать любые вопросы:)

Как вы обычно организуете сложные веб-приложения, которые чрезвычайно богаты на стороне клиента. Я создал надуманный пример, чтобы указать на тот тип беспорядка, в который легко попасть, если с большими приложениями дела идут плохо. Не стесняйтесь изменять / расширять этот пример по своему желанию - http://jsfiddle.net/NHyLC/1/

Пример в основном отражает часть публикации комментариев на SO и соответствует следующим правилам:

  1. Должно содержать не менее 15 символов, после обрезки нескольких пробелов к одному.
  2. Если Add Comment нажата, но размер менее 15 после удаления несколько пробелов, а затем показать всплывающее окно с ошибкой.
  3. Укажите количество оставшихся символов и Подводя итог с цветовым кодированием. Серый указывает небольшой комментарий, коричневый цвет обозначает средний комментарий, оранжевый большой комментарий и красный переполнение комментария.
  4. Один комментарий может быть отправлен только каждые 15 секунд. Если комментарий отправлено слишком рано, показать всплывающее окно с соответствующим сообщением об ошибке.

В этом примере я заметил пару проблем.

  • В идеале это должен быть виджет или какой-то пакет функций.
  • Такие вещи, как комментарий за 15 секунд и комментарий длиной не менее 15 символов, относятся к некоторым политикам всего приложения, а не встроены в каждый виджет.
  • Слишком много жестко закодированных значений.
  • Нет кода организации. Модель, Представления, Контроллеры все связаны. Не то, чтобы MVC был единственным подходом для организации полнофункциональных клиентских веб-приложений, но в этом примере его нет.

Как бы вы занялись уборкой? Применяя немного MVC / MVP по пути?

Вот некоторые из соответствующих функций, но это будет иметь больше смысла, если вы увидели весь код в 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.");
    }

});

Редактировать 1:

@ matpol Спасибо за предложение для объекта-оболочки и плагина. Это действительно будет большим улучшением по сравнению с существующим беспорядком. Тем не менее, плагин не является независимым и, как я уже говорил, он будет частью более крупного сложного приложения. Политики всего приложения на стороне клиент / сервер будут диктовать такие вещи, как минимальная / максимальная длина комментария, как часто пользователь может комментировать и т. Д. Конечно, плагин может передавать эту информацию в качестве параметров.

Кроме того, для приложения на стороне богатого клиента данные должны быть отделены от его представления в формате html, так как можно сохранить множество обращений к серверу, поскольку приложение учитывает данные, а вещи могут храниться локально и периодически обновляться. на сервере или при интересных событиях внутри самого приложения (например, когда окно закрыто). Вот почему мне не очень нравится плагин. Он будет работать так же, как и в случае с упакованным представлением, но все равно будет сосредоточен вокруг DOM, что будет проблематично, если в приложении будет 20 таких плагинов, что никоим образом не является абсурдным числом.

Ответы [ 4 ]

23 голосов
/ 13 июня 2010

Я бы сделал это в три раза.

  1. Инкапсулировать javascript в небольшие четко определенные классы в пространствах имен
  2. Классы Javascript должны иметь HTML, который им требуется «внедрить» в качестве зависимости, что позволяет модульное тестирование вне браузера
  3. Перенесите на сервер как можно больше функциональных возможностей на стороне клиента и используйте концепцию, известную как AHAH

Интервал имен Javascript

Это может быть легко достигнуто и было рассмотрено в других статьях, таких как этот Есть ли "краткий" способ сделать пространство имен в JavaScript?

Небольшие инкапсулированные классы

Javascript-код, так же как и код на стороне сервера, должен быть хорошо инкапсулирован небольшими связными классами и методами. Каждый класс находится в отдельном файле, названном вместе с пространством имен, в котором он находится, например: MyCompany.SomePackage.MyClass.js. Избыточные HTTP-запросы к каждому файлу могут быть сохранены с помощью , объединяя и минимизируя эти файлы классов во время сборки.

Инверсия зависимостей в Javascript

Таким образом, вместо того, чтобы выбирать элементы, с которыми вам нужно работать, внутри вашего класса, вот так:

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

Вы бы добавили его так:

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

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

Этот метод хорошо подходит для тестируемого javscript и разделения проблем с помощью MVC стиля многоуровневого кода.

AHAH и упрощение на стороне клиента

AHAH - довольно старая техника, которая уже довольно давно используется в веб-разработке, хотя она возрождается среди поклонников веб-сайтов из-за ее чистой простоты. Однако эту философию следует воспринимать не только на уровне архитектурной техники, и она должна использоваться в качестве замены для всего вашего клиентского JavaScript, например: проверка, отображение / скрытие динамического содержимого, вычисления и т. Д.

Где вы раньше могли прикрепить событие onClick со сложностью на стороне клиента:

$('#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();
})

Теперь вы просто запускаете ajax-запрос обратно на сервер, чтобы получить новый HTML, и просто заменяете все или некоторые элементы, которые вас интересуют, как таковые:

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

Очевидно, что это тривиальный пример, но при эффективном использовании ЛЮБОЕ событие javascript на странице просто запускает идентичный запрос ajax и замену HTML, что значительно сокращает объем требуемого кода на стороне клиента. Перемещение его на сервер, где его можно эффективно протестировать.

А-а-а-а-а, утверждают, что это неэффективный способ запуска веб-сайта, однако я использовал и видел эту технику на сайтах с доступом к модему 56k, а также в массовых публичных сайтах. Результат, конечно, медленнее, но вы все равно можете совершать круговые поездки за 100 миллисекунд, что практически мгновенно для людей.

4 голосов
/ 07 июня 2010

Матпол дал буквальное решение конкретной предоставленной информации. Ваше редактирование подразумевает, что вы ищете ответ на более гипотетический вопрос. Другими словами, вы ищете «подход».

Ответ на вопрос таким образом; единственный пример, который вы привели, - это немного красной сельди. Это всего лишь один элемент во всем приложении, и он не позволяет нам «видеть лес с деревьев». Так что же такое лес? Вопрос, заданный как таковой, не определяет его. Но я думаю, что все программисты согласятся, когда я скажу, что работать над проектом без определения - это кошмар. Итак, я перефразирую ваш вопрос и отвечу: «Каков процесс определения проекта?»

Моя, на самом деле, задает ряд вопросов:

  • Какова основная цель этого приложения?
  • Когда вы хотите, чтобы он был запущен? Если бы нам пришлось запустить его в 1/4 того времени, какие функции вы бы оставили?
  • Какие функции вы абсолютно уверены, что вам понадобится впоследствии?

Большую часть времени, чтобы докопаться до этих вопросов, мне нужно задать другие деловые вопросы:

  • Кто ваша аудитория?
  • Почему они заботятся об этом сайте? Что заставит их возвращаться?
  • Как вы собираетесь получать доход?
  • Каков ваш призыв к действию? Если бы вы могли направить всех своих пользователей по одному пути, что бы это было?

Надеемся, что эти вопросы приведут к набору основополагающего кода, который вы сможете рассмотреть как свое ядро. Как вы и подозревали, ваше ядро, вероятно, не соответствует модульному подходу. И, как вы определили, вы захотите разбить это ядро ​​на макет Модель / Представление / Контроллер.

Но неизбежно, что вам нужно будет добавить дизайнерский пух. И это возвращает нас к вашему примеру кода - его пух. Пух относится к плагину, отделенному от ядра. Это не означает, что все ваши плагины должны быть доставлены пользователю в отдельных js-файлах ... но для целей разработки они должны рассматриваться как модульные и независимые от базового кода.

3 голосов
/ 18 марта 2010

Я бы включил его в плагин jQuery или в статический объект.

Статический объект просто действует как вид или оболочка. Я также разбил бы его на более мелкие функции, например

init()
checkLength()
checkTime()

Таким образом, вы можете получить что-то вроде:

Widget = {

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


}
1 голос
/ 13 июня 2010

Текущий код - хорошее начало, и его можно «масштабировать» в большие приложения, которые избегают жесткого кодирования и имеют четкое разделение MVC с помощью всего лишь нескольких изменений.

  • В идеале это должен быть виджет или какой-то пакет функций

Виджет упростит повторное использование комментариев и обеспечит повторное использование на разных страницах / в приложениях. Расширьте инкапсуляцию и разделение задач не только на представление, но и на модель виджета. Когда вы думаете о поле комментария, интуитивно можно думать о состоянии компонента как о тексте комментария, но все параметры, влияющие на его поведение, могут быть частью его модели, включая параметры проверки. Итак, в дополнение к тексту комментария, я хотел бы, чтобы модель включала:

  • сопоставление количества символов с категорией размера (слишком маленький, маленький, средний, большой, переполнение).
  • максимальная частота отправки комментариев (15 секунд)

Модель виджета обновляет размерную категорию при изменении текста. Представление прослушивает изменения в size-category и в значении size-category, используемом для обновления текстового класса для создания CSS-стиля для разных длин комментариев. Категория размера также проверяется при нажатии «Добавить комментарий». Если это «слишком мало» или «переполнение», то может быть показано всплывающее окно. Обратите внимание, что обработчик «Добавить комментарий» не проверяет счетчик символов - который изолирован в модели - он проверяет размерную категорию. При необходимости контроллер «Добавить комментарий» может использовать то же отображение числа символов в размерную категорию, которое используется моделью для создания полезных сообщений для пользователя. Например. «Комментарии должны содержать не менее 15 символов», где 15 выбирается из карты размерной категории.

Модель также предоставляет свойство «количество оставшихся символов», события изменения которого используются для обновления пользовательского интерфейса виджета. Максимальное количество символов выбирается из карты персонажа в категорию размеров.

  • Такие вещи, как комментарий за 15 секунд и комментарий длиной не менее 15 символов, относятся к некоторым политикам всего приложения, а не встроены в каждый виджет.
  • Слишком много жестко закодированных значений.
  • Нет кода организации. Модель, Представления, Контроллеры все связаны. Не то, чтобы MVC был единственным подходом для организации полнофункциональных клиентских веб-приложений, но в этом примере его нет.

Может быть много типов комментариев (например, различные элементы, которые комментируются) и различные типы виджетов комментариев. Если все они должны иметь одинаковый минимальный / максимальный диапазон, тогда все они должны быть параметризованы с одинаковыми значениями модели, контролирующими проверку комментариев. Это лучше всего делать на стороне сервера при построении данных для модели комментариев. Текст комментария выбирается для этого конкретного комментария, а значения проверки комментария, такие как сопоставление категории размера, выбираются из параметров конфигурации страницы или приложения по умолчанию. Имея центральную логику для создания модели проверки компонентов, добавление новых правил становится намного проще - например, например, «модераторы могут оставлять комментарии размером до 1 КБ», становится изменение одним куском кода. Еще один момент, когда компонентная модель рассчитывается на стороне сервера, состоит в том, что модель также должна быть проверена на стороне сервера - проверка клиента является более удобной для пользователя (неудобство, которое некоторые могут подумать!), А не жестким применением. JavaScript может быть отключен, а HTTP-запросы построены независимо от проверяющего клиента.

Подводя итог, можно сказать, что многое из этого можно рассматривать как организацию производства на стороне сервера модели виджетов. Делая это на стороне сервера, сервер может применять правила проверки и защищать виджет от сложности правил и конфигурации всего приложения.

Я не упомянул jQuery или какую-либо технологию пользовательского интерфейса, поскольку этот шаблон действителен для приложений независимо от технологии пользовательского интерфейса. То, как вы применяете шаблон, будет в некоторой степени зависеть от пользовательского интерфейса, например, от того, как модель проверки предоставляется виджету или как подключить слушателей к модели, но организационный уровень шаблона ортогонален пользовательскому интерфейсу. Основное внимание уделяется модели - расширение ее для включения аспектов проверки и вычислений на стороне сервера. Как только это произойдет, организационная проблема в значительной степени решена.

...