Подходы к кодогенерации

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

    Кодогенерация


    Кодогенерация — это процесс генерации кода на основе определенных данных.

    Я бы хотел выделить некоторые направления:

    Генерация кода на основе более высокоуровневого


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

    Например, мы пишем сайт на каком-то своем языке. А на сервере у нас стоит PHP. Давайте посмотрим какая теоретически возможна генерация.
    user = Users.find(5);
    user.lastActivity = DateTime.Now;
    user.save();

    Мы сконфигурировали сайт на использование MySQL и можем получить на выходе подобный код:
    $user_query = mysql_query('SELECT * FROM `users` WHERE `id`=5', $mysql_connection);
    $user = mysql_fetch_assoc($user_query);
    mysql_query('UPDATE `users` SET `lastActivity`='.time().' WHERE `id`='.$page['id'], $mysql_connection);

    А если кодогенератор умный, то он может сгенерировать нечто такое:
    mysql_query('UPDATE `users` SET `lastActivity`='.time().' WHERE `id`=5', $mysql_connection);

    Вдруг мы решили не использовать MySQL, а использовать, например, прямую запись в файлы, то код может быть таким:
    $user_list = unserialize(file_get_contents('users.txt'));
    foreach ($user_list as $current_user)
    {
      if ($current_user->id == 5)
      {
        $user = $current_user;
        break;
      }
    }
    $user->lastActivity = time();
    file_put_contents('users.txt', serialize($user_list));


    Еще один пример. Мы пишем на своем языке:
    deletedRowsCount = query: delete from myTable where id>5;

    В случае использования MySQL, мы могли бы получить такой код:
    $query = mysql_query('DELETE FROM `myTable` WHERE `id`>5', $mysql_connection);
    $deletedRowsCount = mysql_affected_rows($mysql_connection);

    В случае использования файлов, мы могли бы получить такой код:
    $deletedRowsCount = 0;
    $myTable_list = unserialize(file_get_contents('myTable.txt'));
    foreach ($myTable_list as $key_myTable=>$current_myTable)
    {
      if ($current_myTable->id > 5)
      {
        unset($myTable_list[$key_myTable]);
        $deletedRowsCount++;
      }
    }
    file_put_contents('myTable.txt', serialize($myTable_list));


    Примеры кода не идеальны, но с задачей демонстрации кодогенерации они справляются.

    Хочу так же привести пример работы реального кодогенератора, работающего по такому принципу. Это кодогенератор LINQ.

    Исходный код:
    byte[] source = new byte[] { 1, 5, 7, 4, 3, 9, 8, 2, 6 };
    var dest = from n in source where n > 5 select n;


    Результирующий код:
    IEnumerable<byte> dest = Enumerable.Where<byte>(new byte[] { 1, 5, 7, 4, 3, 9, 8, 2, 6 }, new CS$<>9__CachedAnonymousMethodDelegate1(Main_b__0));

    Генерируется так же делегат:
    [CompilerGenerated]
    private static Func<byte, bool> CS$<>9__CachedAnonymousMethodDelegate1;

    И метод:
    [CompilerGenerated]
    private static bool Main_b__0(byte n)
    {
      return (n > 5);
    }


    Генерация на основе метаданных


    Этот подход позволяет нам создавать код работы с данными на основе описания структуры данных (метаданных). Например, у нас есть БД MySQL. Я хочу сгенерировать сущности для работы с БД. Наиболее простые данные о структуре БД получить легко:
    show tables;
    +---------------+
    | Tables_in_gen |
    +---------------+
    | users         |
    +---------------+

    describe users;
    +-------+--------------+------+-----+---------+----------------+
    | Field | Type         | Null | Key | Default | Extra          |
    +-------+--------------+------+-----+---------+----------------+
    | id    | int(11)      | NO   | PRI | NULL    | auto_increment |
    | name  | varchar(100) | YES  |     | NULL    |                |
    +-------+--------------+------+-----+---------+----------------+

    Из этого можно сгенерировать примитивный класс хранения информации о пользователе.
    class User
    {
      public $id;
      public $name;
    }


    Если подумать, то можно еще реализовать методы select, update, insert, delete. В будущем мы столкнемся с подобными кодогенераторами и даже рассмотрим разработку подобного.

    Кодогенерация на основе шаблонов


    Это один из простых и повседневных подходов к кодогенерации. Пример такой системы — Smarty. Эта система используется в основном для генерации HTML кода на основе шаблонов. В ходе экспериментов я генерировал PHP и C# код.

    Например, у нас в неком источнике $source хранится список полей и нам надо на их основе сделать класс со свойствами.

    Шаблон можно взять такой:
    class MyClass
    {
    {{foreach from=$source item=name}}
      public ${{$name}};
    {{/foreach}}
    }

    И при $source = array('width', 'height', 'name') мы получим:
    class MyClass
    {
      public $width;
      public $height;
      public $name;
    }


    В следующей статье мы рассмотрим то как можно управлять сложностью с помощью кодогенерации.
    Поделиться публикацией
    Ой, у вас баннер убежал!

    Ну. И что?
    Реклама
    Комментарии 53
    • 0
      В следующей статье сравним многоуровневую абстракцию и кодогенерацию.
      • 0
        Спасибо за ваши усилия, интересно будет дальше почитать.

        Но здается мне что за подобное надо по рукам бить (я о "вы пишете на ... а в универе установлен ...". Если вы в состоянии осилить кодогенератор пхп - значит можете и сам пхп по-человечески осилить. А превращать процесс дебага из "нашел ошибку -> исправил" в "сгенерировал -> нашел ошибку -> почесал мозг, как ее исправить в кодогенераторе чтоб код другой нормальный сгенерировал -> сгенерировал код" при знаниях пхп - неумно.
        • 0
          Не понял сути вашего поста. Я пока не пишу о преимуществах конкретных. Я пишу о подходах которые существуют и применяются. А они намного более совершенны того, что я написал. Перед нами есть живой пример - LINQ. Но если я приведу исходный и сгенерированный код, то мало кто разберется. Поэтому я стараюсь простыми вещами описывать данную отрасль. Если у вас есть более интересный подход - вы можете написать топик в этом разделе.
          • 0
            К сожалению, мало знаком с C#, но почитав википедию и т.п. не понял совершенно, с чего вы взяли, что linq можно отнести к кодогенерации?
            • 0
              Linq типичный кодогенератор. Он генерирует более низкоуровневый код на основе более выоскоуровневого в зависимости от метаданных источника и способа взаимодействия с ним.
              • 0
                Генерация у LINQ идет, кстати, через CodeDOM - стандартный интерфейс кодогенерации в .NET. В .NET кодогенерация очень хорошо развита.
                • 0
                  Мне кажется, что LINQ, всё-таки, это фреймворк абстракции от БД, наподобие перловых Class::DBI: и DBIx::*. Если нет, может у вас есть ссылки на странички с примерами?
                  • 0
                    Да, это абстракция за счет кодогенерации. Есть еще DataSet - это общая абстракция за счет многоуровневой абстракции.
          • 0
            интересно чему уже это всё кончится
            • 0
              нда.. сериал получается - тем увлекательней
              • 0
                Никого не заставляю читать. Спасибо за внимание.
              • 0
                Получается, для того чтобы воспользоваться кодогенераторами, необходимо сначала выучить язык кодогенератора.
                1)Не лучше ли это время потратить на изучение того языка, на котором собираешься писать программы
                2)Создание некоторого универсального кода, который можно преобразовать в код на любом произвольном языке программирования напоминает поиск философского камня. Не понятно зачем это нужно, зато понятно, что оптимальный код "умный" кодогенератор все равно не сгенерирует.
                • 0
                  Раздел про метаданные вы намеренно проигнорировали? Подходов много, на любой вкус. Некоторые требуют знания языков, другие могут генерировать на основе метаданных, явлений, событий и т.п.
                  • 0
                    я его прочитал.
                    Генерация типов данных по структурам таблиц в БД...но все же типы используемые в программе находят свое отражение в БД
                    • +1
                      Генерация на основе метаданных - отличная абстракция от источника данных. Имея гибкий генератор (либо несколько генераторов) мы можем оптимальный генерировать код для конкретного источника данных и без труда сменить источник перегенерировав код с другой конфигурацией. Кстати, многоуровневая абстракция так же подходит для быстрой смены источников данных. В следующей статье я как раз сравню эти подходы.
                      • 0
                        Хм, ИМХО, с этого надо было начинать ;)
                        • 0
                          Все это конечно красиво, но нужно ли менять источник данных? Если проектируют какую-либо систему, то под конкретные источники данных. Все равно будут проблемы при смене, как бы хороша система ни была. И при использовании минимальных возможностей всех поддерживаемых источников, мы теряем мощь одного определенного (например тот же mysql).
                          И не лучше ли просто разрабатывать сразу на специализированных системах, навроде Cache', где можно работать напрямую с данными?
                    • 0
                      Это чего получается тогда по вашим словам не имеет смысла учить C\C++, а учить ассемблер? Язык кодогенератора обычно находится на более высоком абстрактном уровне чем язык на котором генерируется код.
                      • 0
                        А разве языки типа С++, Java не являются языками высокого уровня? Или есть уровень выше (для кодогенеаторов)
                        • 0
                          Думаю, всегда можно придумать уровень выше. Каждый следующий уровень пораждает бОльшую простоту, но меньшую гибкость :-)
                    • 0
                      Честно говоря не согласен с LINQ и кодогенерацией... Linq - это расширение языка, которое компилируется в IL код. Если же про LINQ говорить как о кодогенерации, то тогда давайте возьмём все оставшиеся N конструкций языка C#...
                      • 0
                        Рекомендую посмотреть предыдущие статьи, они в этом же блоге.
                        • –1
                          Я про то, что смешно как то называвать например свойства, которые тоже генерятся в методы get_ и set_. Или анонимные методы, которые в превращаются в
                          [CompilerGenerated]
                          Метод {}
                          Вобщем считаю это чушью, потому что компиляция С#, VB.NET генерит IL код (ниразу не слышал, чтобы кто то называл это процессом кодогенерации). При компиляции C++, C, геренирует asm код с последующей компиляцией...
                          • 0
                            Компиляция - разновидность кодогенерации.
                            • –1
                              Прошу прощенья за сарказм, но, работать - разновидность жизни... А жизнь это разновидность существования. Зачем переходить к астракции без необходимости?
                              • 0
                                Кодогенерация - принцип. Компиляция - частный случай.

                                Не понимаю что тут непонятного?
                              • 0
                                Просто мне очень хочется ляпнуть, что почему не упомянули самого главного тогда кодогенератора... Девелопера?
                                • +2
                                  О нем слишком много говорят, а мне интересна автоматическая и динамическая кодогенерация.
                                • 0
                                  Кодогенерация — _ЧАСТЬ_ процесса компиляции, когда специальная часть компилятора
                                  http://ru.wikipedia.org/wiki/%D0%9A%D0%B…
                                  • 0
                                    Я предпочитаю английскую википедию. Ссылку дал, есть что почитать.
                                    • –1
                                      Вы ссылаетесь на источник, но при этом сами НЕ понимаете вопрос. Я бы вам хотел прояснить это, и всем людям, которые тоже ДОВЕРЯЮТ статьям, при этом отключают голову для анализа, и не разбираются в проблеме.
                                      А теперь этапы компиляции:
                                      1) Разбиение на токены
                                      2) Проверка синтаксиса и семантики
                                      3) Кодогенерация (например на asm)
                                      4) Компиляция
                                      И это только с моим скудным познанием компиляторов, который я ещё помню с университета, когда приходилось их писать. Уверен профессионалы укажут больше стадий. Но кодогенерация, как раз является частью процесса компиляции. И тут уже не поспоришь. НО если рассмативать компиляцию в общем виде, как перевод из одного в другой, то да можно так сказать, как написано в английском варианте. Но пожалуйста, голову то используйте, перед тем как давать ссылки на статьи. Их надо ПРАВИЛЬНО читать. Удачи.
                                      • 0
                                        Рекурсивная компиляция? :-)
                                • 0
                                  http://en.wikipedia.org/wiki/Code_genera…(compiler) Рекомендую.
                                    • 0
                                      (что-то ссылку со скобкой никак не разместить)
                                      http://en.wikipedia.org/wiki/Code_genera… - а дальше выберите то что надо)
                                      • 0
                                        Вот в странице Source code generation по вашей ссылке есть чудная цитата: "Parnas concluded that "automatic programming has always been an euphemism for programming in a higher-level language than was then available to the programmer.""

                                        Это не к тому, что ваша тема неинтересна (наоборот очень даже интересует людей с 40х годов), а к теме используемой терминологии...
                              • 0
                                Между прочим статья вообще не приводит в пример ниодин из открытых или проприетарных проектов, коих кучи, например:
                                CodeSmith (http://www.codesmithtools.com/) с кучей уже готовых шаблонов
                                StringTemplate.NET (http://www.stringtemplate.org/)
                                NVelocity (http://nvelocity.sourceforge.net/)
                                iCodeGenerator (http://codegenerator.sourceforge.net/)
                                и это не говоря уже о конкретных шаблонах, например для CodeSmith, типа:
                                .netTiers (http://csharp-source.net/open-source/tem…)
                                • 0
                                  CodeSmith рассматривал в предыдущей статье.
                                • 0
                                  Господа, я понимаю что автора на хабре надо послать, унизить, обвинить в некомпетентности, но когда вы утверждаете что-то - вы хоть проверяйте в различных источниках это.
                                  • 0
                                    Вам наверное стоит просто более четко обьяснить народу о чем Вы собираетесь поведать. Сами ведь признаете, что кодогенерация - ну очень широкое понятие. И зачем Вы стараетесь, если Вам не нравится аудитория?
                                    • +1
                                      Есть люди которые интересуются - для них стоит писать :)
                                  • 0
                                    Создание новых функций на основе замыканий - часто используемая практика, и тоже схожа с кодогенерацией.

                                    По крайней мере, очень много современных каркасов на JavaScript или Perl интенсивно используют замыкания.
                                    • 0
                                      очень весело иногда бывает случайно замкнуться не на тот контекст и пару часов искать ошибку...
                                    • 0
                                      Вспомните десятое правило Гринспуна.
                                      • 0
                                        Lisp выучить времени не хватает никак :(
                                        • 0
                                          попробуйте почитать Сибела на http://gigamonkeys.com/book для CL или SICP вообще для всего (по последней, кстати, на itunes-u есть чудный и совершенно бесплатный курс лекций из беркли)

                                          А по поводу статьи - с одной стороны не могу сказать ничего хорошего, потому что в этой части все примеры наиграны и должны решаться совершенно не методом кодогенерации, а с другой не могу сказать ничего плохого, ибо именно такую штуку я написал сам в своё время.
                                          • 0
                                            Я стараюсь переходить от простого к сложному :)
                                            • 0
                                              SICP обязательно почитайте. Он, кстати, давно есть на русском.
                                              Если CL учить сложно, начните со Scheme, там очень быстрый вход.

                                              Тема кодогенерации мне очень интересна, потому что сильно пересекается с темой DSL вообще и eDSL в частности. К сожалению, здесь мало об этом говорится.

                                              За статьи спасибо! Они как минимум собирают интересный народ ;-)
                                      • +2
                                        спасибо за статью, всегда классно посмотреть на реализацию какой-либо задачи с другой стороны. Возможно пигодиться
                                        • –2
                                          Не знаю зачем меня заминусовали, никто мою идею не понял, поэтому объясню ещё раз. Я не придираюсь ко всей статье, я лишь хочу сказать, что это немного некорректно приводить ТАКОЙ пример LINQ как кодогенератора, а потом говорить, что компиляция это часть кодогенерации. Либо автор не совсем понимает и ещё не использовал LINQ в своих проектах. Я бы и слова не сказал, если бы привели пример ДЕЙСТВИТЕЛЬНОЙ кодогенерации например cпециальную утилиту КОДОГЕНЕРАЦИИ SqlMetal.exe. Зачем вводить тут людей в заблуждение, и расказывать какие то левые примеры кодогенерации LINQ, что вот этак конструкция сгенерила этот код, а эта вот этот. Это чушь, самую основную деталь LINQ to SQL автор почему то пропустил, а это самый главный пример, который можно привести если рассматривать LINQ. Я не понимаю также, почему автор выбрал именно LINQ в этом контексте, в котором он его использовал, так как можно было взять ЛЮБУЮ конструкцию любого языка программирования, и показать как она интерпретируется/компилируется в машинный/промежуточный код. В качестве примера указываю источник - Code Generation in LINQ to SQL (http://msdn2.microsoft.com/en-us/library…). Посмотрите на нормальный пример, а не притягивание за уши к статье того, в чём автор НЕ РАЗОБРАЛСЯ но очень бы хотел воткнуть, потому что это наверное модно.
                                          • 0
                                            Вы сами себе доказали свою неправоту :-) Приятно когда статьи полезны для тех кто их читает :-)
                                          • –1
                                            Да и так на вскидку пришёл ещё очень интересный пример кодогенерации - динамическое создание лямбда выражений на лету для условия выборки в LINQ.
                                            • 0
                                              В статье, кстати, этот случай описан :-)

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

                                            Самое читаемое