Javascript-форум (https://javascript.ru/forum/)
-   Ваши сайты и скрипты (https://javascript.ru/forum/project/)
-   -   Как я пишу код (https://javascript.ru/forum/project/32896-kak-ya-pishu-kod.html)

FINoM 03.11.2012 03:26

Как я пишу код
 
Надеюсь этим постом дать начало традиции делиться не только своими наработками (библиотеки, фреймворки, отдельные функции), но и стилем написания кода, а точнее структурированием проекта.

Буквально пару дней назад ко мне обратился мой старый клиент с просьбой обновить небольшое веб приложение, которое я делал около года назад. Когда я открыл код, я там буквально ничего не понял. Весь проект был засунут в одну функцию, срабатывающую по domready. Там же были объявлены переменные и функции, в один уровень (хотя и в самом верху, как бы соблюдая правила хорошего тона). Первой же мыслью было "переписать всё нахер". Переписал я это всё дело, используя готовый набор инструкций, которые я выдумал пять проектов назад и тупо копировал в дальнейшем, так как было лень что-то новое придумывать.

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

Скажу честно, я не понимаю как применять всякие MVC на практике, да и код из примеров часто кажется слишком перегруженным. Часто намного проще изобрести свою собственную структуру, заточенную под проект, при этом прекрасно понимая, что, где и как работает.

Как я уже сказал, все функции и данные хранятся в одном пространстве имен. Скажем, проект вашего заказчика называется "Project Name".

Перед задействованием каких-либо скриптов, создаём пространство имен:
<script>	
	window.projectName = window.pn = {};
</script>

Затем добавляем скрипты в произвольном порядке. Файлы скриптов именуются так:
pn.something.js
Файл скрипта начинается c объявления строгого режима и подпространства имен:
"use strict";
pn.something = {
   
}

После этого инициализируем события (см. репозиторий внизу)

Минимальный список файлов:

pn.data.js
Здесь хранятся данные и методы, которые манипулируют этими данными, скажем:
pn.data = {
  i: 0,
  incrementI: function() { this.i++ }
}

В этот объект так же помещаются данные, которые мы получили в процессе работы скрипта:
pn.ajax.getSome( function( some ) {
  pn.data.some = some;
})


pn.ajax.js
Здесь хранятся методы для получения данных с сервера. Сюда же можно кинуть урлы и пр. вещи, относящиеся к исключительно к аяксу

pn.events.js
Здесь инициализируется страница объявляются события (подробнее с несколькими комментариями см. в репо)

pn.ui.js
Функции, отвечающие за интерфейс, к примеру:
pn.ui = {
  renderMenu: function() {...}
}


pn.utils.js
Здесь всякие вспомогательные функции, например, получение массива, с нулями. Данные из pn.data здесь не модифицируются, а функции только возвращают что-то.

Сделал для ознакомления небольшой репозиторий: https://github.com/finom/AG-JS-Boilerplate

Информации там немного, но общая идея, надеюсь понятна. Со временем буду обновлять, в том числе, и для себя, так как память часто подводит.

Хотя я не рассказал ничего особенно нового, не применил каких-нибудь сложных заумных штук, я надеюсь, новичкам будет полезно ознакомиться с простейшим набором универсальных приёмов, описанных выше, несколько уменьшая соотношение говнокод/код.

FINoM 03.11.2012 03:38

И не обращайте внимания на сами методы. Например, pn.ajax._get и pn.ui._render сделаны не очень удачно, на скорую руку.

vadim5june 03.11.2012 08:17

а зачем нам "use strict";?
В pn.data запятую вместо двоеточия нужно поставить

Gozar 03.11.2012 10:19

Цитата:

Сообщение от FINoM
pn.ui.js
Функции, отвечающие за интерфейс, к примеру:
pn.ui = {
renderMenu: function() {...}
}

Лично мне недостаточно одного файла под ui. В либе у меня на каждый элемент(графическое представление: tab, popUp, tree) по файлу и все это лежит в папке ui.

Для построения более сложных структур делается так:

Допустим у нас есть forum:
Далее разбиваем на файлы и объекты:
forum.content = {} соответствует forum.content.js
forum.path = {} соответствует forum.path.js
forum.tree = {} соответствует forum.tree.js
...


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

Проект на папки не бью, не вижу в этом смысла и сразу видна вся структура проекта, все лежит в одной папке:
forum.content.js
forum.path.js
forum.tree.js


Если создаются проекты с одним и тем же содержанием, но разными user скриптами, то добавляется файл userScript.js, который является управляющим и может собирать свои объекты и указывать на ещё пачку скриптов. Таким образом, при обновлении ПО проектов, пользователи имеют всегда последнее ПО и не теряют приписанный им скрипт(ы).

Gozar 03.11.2012 10:34

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

Либа лежит в отдельной папке.

Gozar 03.11.2012 10:52

Цитата:

Сообщение от Gozar
Проект на папки не бью

Имеется ввиду средний проект без предпосылок к росту. Если проект большой, то в примере выше создается папка forum в которой лежит:
forum.content.js
forum.path.js
forum.tree.js


Собственно это не сильно важно, т.к. проект все равно собирается и ужимается и можно пересобрать и распихать файлы по папкам. Хоть каждый файл в свою. На выходе получим те же один, два файла :)

kobezzza 03.11.2012 11:02

Я юзаю паттерн БЭМ, где все интерфейсные элементы абстрактно представляются, как атомарные блоки, а их состояния задаются через специальные модификаторы. Почитать описание паттерна можно на http://ru.bem.info/method/

Сразу скажу, что в личных проектах я не юзаю i-bem фреймворк Яндекса, т.к. он мне не нравится, а написал свой микро каркас. На работе разумеется приходиться работать с i-bem. Не нравится потому:
1) Слишком много туда засунули;
2) Излишнее количество неймспейсов и не самое приятное АПИ методов;
3) Не нравится их шаблонизатор;
4) Лишняя зависимость от jQuery и Яндекса (вдруг ребята из Лего захотят поменять концепцию и у меня всё сломается).

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

Gozar 03.11.2012 11:43

Цитата:

Сообщение от kobezzza
4) Лишняя зависимость от jQuery

Я принудительно, т.к. сначала хотелось с jq, вынул его из каркаса и не жалею. Подключаю только в userScript, при необходимости.

Цитата:

Сообщение от kobezzza
ребята из Лего

что за ребята из Лего?

kobezzza 03.11.2012 11:46

Цитата:

Сообщение от Gozar (Сообщение 213832)
что за ребята из Лего?

команда, которая разрабатывает i-bem

FINoM 03.11.2012 21:59

Цитата:

Сообщение от vadim5june
а зачем нам "use strict";?

Дабы избежать попадания переменных в глобальное пространство имен.
Цитата:

Сообщение от Gozar
Лично мне недостаточно одного файла под ui.

Мне иногда тоже, поэтому я создаю еще одно подпространство. Например:
pn.ui = {} // pn.ui.js
pn.ui.charts = {} // pn.ui.charts.js
Но всё равно сохраняя пространство ui для всего, что относится к интерфейсу.
Цитата:

Сообщение от Gozar
Проект на папки не бью, не вижу в этом смысла и сразу видна вся структура проекта, все лежит в одной папке:

Угу, и в файловом менеджере твои скрипты не путаются с либами (как было бы, если бы мы использовали разные префиксы для файлов).


Часовой пояс GMT +3, время: 17:16.