Разработка

индекс
203,40

Разработка снизу-вверх и базы данных.

    Пол Грэм в своих эссе часто касается темы разработки снизу-вверх. Этот метод упоминается у него, когда он пишет о разработке програмного обеспечения, о способе ведения бизнеса, о преимуществах open source и блогах. Ниже я опишу почему при этой модели разработки взаимодействие с базой данных встает поперек глотки, и предложу решение уместное в некоторых случаях.

    Нельзя сказать, что метод снизу-вверх лучше какого-либо другого, просто в большестве случаев он более жизнеспособен. Действительно, человек открывая, например, магазин или создавая DE начнет с малого и постепенно будет развивать его; но если он уже развил свой магазинчик в сеть магазинов, сравнимую с Auchan, или написал KDE, то в следующий раз он уже не будет начинать с малого, а проведет долгое время в планах и затем реализует большой проект сразу. В первый раз человек получает обратную связь во время разработки, во второй раз тоже, правда он уже разрабатывает уже не магазин, а последовательность магазинов, и отклик полчает от предыдущего разработанного проекта.

    В крупных компаниях разработка часто ведется сверху вниз. К сожалению, простые исполнители из-за этой методики начинают не любить свою работу, так как у них пропадает элемент творчества. Пол в своем эссе What business can learn from open source предложил интересную модель разработки, когда компания занимающаяся производством ПО, инвестирует деньги в команды программистов, которые уже занимаются разработкой в той области, которая интересна компании. Таким образом пропадает иерахия босс-подчиненный и разработчики работают с большем энтузиазмом, а компания занимается вопросами маркетинга, дистрибуции и не содержит собственный штат программистов. Из примеров, которые на слуху у читателей хабра — язык F#, над котором долгое время работал Don Syme и который microsoft решила пустить в mainstream в следующем релизе студии.

    В своих эссе Пол делает основной упор на преобладание практики над планированием, скоростью написания и легкостью изменения. К сожалению, многие средства для разработчиков создавались без оглядки на эти принципы и были нацелены на те компании, которые придерживаются сложившегося отношения босс-подчиненный. Часто, при работе в XP стиле взаимодействие с базой данных встает как кость в горле: сложности при тестировании; гетрогенность кода — думать приходиться то на ЯВУ, но на декларативном SQL, имея ввиду ньюансы отображения одного на другое; огромное количество ненужного кода и ненужных абстракций, которые отвечает за взаимодействие с базой, а решения, которые призваны это безобразие исправить, по сути являются кодогенерацией со всеми вытекающими из этого проблемами.

    Первыми этот бардак осознали люди, пишушие на динамических языках — и попытались исправить эту проблему. Так появились couchdb, strokedb и simpledb. Это решение подходит для небольших проектов, но думаю компании уровня яндекс не будут держать свои базы на субд, которые не прошли тестирование временем.

    Представим, что на дворе 95 год, вы проснулись и решили создать яндекс, то есть создать движок для web-поиска. Очевидно, что самое интересное в задаче это анализ информации, а не способ её хранения, поэтому вы сразу набросились на эту задачу. Частично её решили и хотите сделать первый прототип, что бы найти инвестора. Ясно, что без хранения данных здесь уже не обойтись, но с другой стороны вы понимаете, что какую-либо структуру базы вы не выбрали, то к моменту запуска она сто раз измениться, поэтому от перспективы писать сто раз workaround для работы с базой вас тошнит.

    Таким образом нужно решение, которое не будет сдерживать разработку в будушем, оно должно легко меняться при изменении требований и обладать такми свойством, что в любой момент это решение можно было быстро перенести на реляционные базы данных. Желая так же избавиться от гетрогенности и облегчить тестирование придем в выводу, что хорошим решением будет написать свой движок базы данным на языке, на котором ведется разработка, а методы взаимодействия вынести в интерфейс и работать только с интерфейсом, таким образом переход к провереной СУБД будет осуществлен реализацией взаимодействия с базой, согласующегося с этим интерфейсом.

    Если мы хотим написать свой простой движок базы данных, то это легко сделать используя язык, который поддерживает кортежи, списки и list comprehension, а так как реализация движка базы данных это не основная задача, которая перед нами стоит, то желательно, что бы этот язык был высокого уровня, обладал привычным синтаксисом и поддерживал популярные парадигмы. Думаю вы уже догадались, что я пишу о nemerle. Ниже я привиду примитивный пример реализации движка БД.

    Допустим схема базы следующая:
DROP TABLE IF EXISTS Author;
CREATE TABLE Author (
  ID INT AUTO_INCREMENT NOT NULL,
    Firstname VARCHAR(500) NOT NULL,
    Lastname VARCHAR(500) NOT NULL,
    PRIMARY KEY(ID)
);

DROP TABLE IF EXISTS Journal;
CREATE TABLE Journal (
  ID INT AUTO_INCREMENT NOT NULL,
    Title VARCHAR(500) NOT NULL,
    PRIMARY KEY(ID)
);

DROP TABLE IF EXISTS Article;
CREATE TABLE Article (
  ID INT AUTO_INCREMENT NOT NULL,
    Title VARCHAR(500) NOT NULL,
    JournalID INT NOT NULL,
    AuthorID INT NOT NULL,
    CONSTRAINT `journal_id` FOREIGN KEY (JournalID) REFERENCES Journal(ID) ON DELETE CASCADE,
    CONSTRAINT `author_id` FOREIGN KEY (AuthorID) REFERENCES Author(ID) ON DELETE CASCADE,
    PRIMARY KEY(ID)
);


* This source code was highlighted with Source Code Highlighter.


    Реализовать эту структуру и пару запросов к ней можно следующем образом.

public interface IDB
{
 AddAuthor(firstName : string, lastName : string) : int;
 GetAuthor(firstName : string) : list[int*string*string];
}

public class MyDB : IDB
{
 public this() { Author = []; Journal = []; Article = []; ID = 0; }
 public Author : list[int*string*string] { get; set; }  // (ID, Firstname, Lastname)
 public Journal : list[int*string] { get; set; }     // (ID, Title)
 public Article : list[int*string*int*int] { get; set; } // (ID, Title, JournalID, AuthorID)
 public ID : int { get; set;};
 
 public AddAuthor(firstName : string, lastName : string) : int
 {
  ID++;
  Author = (ID,firstName,lastName)::Author;
  ID
 }
 
 public GetAuthor(firstName : string) : list[int*string*string]
 {
  $[(id,first,last)|(id,first,last) in Author, first==firstName]
 }
}


* This source code was highlighted with Source Code Highlighter.


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

cc-by-nc-sa
+5
17 января 2009, 16:55
7

комментарии (6)

0
inxo #
Предложение рождать с каждым новым проектом новую СУБД?
0
shai_xylyd #
С каждым подходящем да=), но ближе к релизу, когда структура определиться переходить на настоящую.
0
inxo #
Сложно представить потом этот переход.
И как мне кажется тут описан переход сверху-вниз, сначала есть структура БД, потом реализуется эта структура на Nemerle, что больше похоже на способ для отказа от СУБД в небольших проектах.
С яндексом вообще непонятно, когда структура небольшая — можно использовать любую СУБД. Да и скорее всего в такой задаче возникнет проблема, где физически хранить простую БД с большим числом данных и будет написана специализированная СУБД.
Тема интересная, сейчас в проекте зашел в тупик, что структура базы данных непонятная и хочется, чтобы и осталась постоянно меняющаяся.
+1
shai_xylyd #
Мне кажется этот переход достаточно простым — реализую интерфейс IDB, где описывают работу с реальной БД, а везде в приложении используется MyDB только через этот интерфейс.

Описание на SQL я привел только, что бы можно было понять, что я определяю на nemerle.
+1
devprom #
На мой взгляд, таким суждением вы совершаете главную ошибку: пытаетесь абстрагироваться от реляционной базы данных на уровне некоего объектного представления (реализуемого через интерфейс DIB).

Существующие проблемы, связанные с разработкой ORM-решений и их использования в основном кроются в отсутствии реального мэппинга объектов на отношения. Каждая СУБД имеет свои ограничения и свои фичи, которые необходимо учитывать и использовать в конкретных проектах. СУБД также накладывает и некоторые ограничения, которые после разработки некоего мока (IDB) потребуют переписать половину системы. Другими словами, вести разработку изначально нужно с учетом этих ограничений, а также преимуществ конкретной СУБД.

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

Используйте объектную СУБД, но сразу, и проблема разработки снизу вверх отпадает сама собой.

Конечно, разработать бОльшую часть базы данных до момента кодирования функционала освобождает от массы проблем связанных с развитием структуры данных и соответствующей модификации самих данных (что несомненно возникает при разработке снизу вверх). Однако, давно известны процессные паттерны для обслуживания этой задачи (Фаулер. «Рефакторинг баз данных»).

Я пробовал оба подхода при разработке решений с использованием базы данных: разработка сверху вниз и снизу вверх. В целом у каждого подхода есть минусы, но то что программный код неразрывно связан с логикой (запросами), реализуемой на стороне СУБД, обязывает аккуратно и внимательно относится к мэппингу при разработке.
0
shai_xylyd #
Спасибо за ценные замечания.

Я не написал это в заметке, но абстракция IDB будет уточняться и эволюционировать, как только будет возникать дополнительная информация, например, выбор NHibernate как ORM спровоцирует замену типа список кортежей в GetAuthor на список объектов класса, например, Author. Таким образом процесс разработки учитывает ограничения СУБД, просто в начальный момент, код к которому приведен в заметке, СУБД еще не выбрана и ограничений пока нет, поэтому используется максимально абстрактная реализация, по мере возникновения ограничений эта абстрактная реализация будет заменема более конкретной.

В общем случае, например в CRUD, подход, который я описал будет более сложным и не даст хорошей отдачи; но в проекте, над которой я сейчас работаю, он оказался успешным так, как база исользовалась только для хранения информации и быстрому поиску по ней, а почти вся логика работы приложения заключалась в обработке данных до занесения их в базу.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.