В предыдущей статье мы рассматривали то, как применяется кодогенерация в реальных продуктах.
В этой статье мы рассмотрим то, как какие подходы к кодогенерации могут облегчить нам жизнь.
Кодогенерация — это процесс генерации кода на основе определенных данных.
Я бы хотел выделить некоторые направления:
Этот подход нам позволяет получить на основе простого интуитивно понятного кода — код более низкого уровня. Такой подход помогает сохранить абстракцию. Язык, на котором написан исходный код, может не совпадать с языком кода, который будет сгенерирован.
Например, мы пишем сайт на каком-то своем языке. А на сервере у нас стоит PHP. Давайте посмотрим какая теоретически возможна генерация.
Мы сконфигурировали сайт на использование MySQL и можем получить на выходе подобный код:
А если кодогенератор умный, то он может сгенерировать нечто такое:
Вдруг мы решили не использовать MySQL, а использовать, например, прямую запись в файлы, то код может быть таким:
Еще один пример. Мы пишем на своем языке:
В случае использования MySQL, мы могли бы получить такой код:
В случае использования файлов, мы могли бы получить такой код:
Примеры кода не идеальны, но с задачей демонстрации кодогенерации они справляются.
Хочу так же привести пример работы реального кодогенератора, работающего по такому принципу. Это кодогенератор LINQ.
Исходный код:
Результирующий код:
Генерируется так же делегат:
И метод:
Этот подход позволяет нам создавать код работы с данными на основе описания структуры данных (метаданных). Например, у нас есть БД MySQL. Я хочу сгенерировать сущности для работы с БД. Наиболее простые данные о структуре БД получить легко:
Из этого можно сгенерировать примитивный класс хранения информации о пользователе.
Если подумать, то можно еще реализовать методы select, update, insert, delete. В будущем мы столкнемся с подобными кодогенераторами и даже рассмотрим разработку подобного.
Это один из простых и повседневных подходов к кодогенерации. Пример такой системы — Smarty. Эта система используется в основном для генерации HTML кода на основе шаблонов. В ходе экспериментов я генерировал PHP и C# код.
Например, у нас в неком источнике $source хранится список полей и нам надо на их основе сделать класс со свойствами.
Шаблон можно взять такой:
И при $source = array('width', 'height', 'name') мы получим:
В следующей статье мы рассмотрим то как можно управлять сложностью с помощью кодогенерации.
В этой статье мы рассмотрим то, как какие подходы к кодогенерации могут облегчить нам жизнь.
Кодогенерация
Кодогенерация — это процесс генерации кода на основе определенных данных.
Я бы хотел выделить некоторые направления:
Генерация кода на основе более высокоуровневого
Этот подход нам позволяет получить на основе простого интуитивно понятного кода — код более низкого уровня. Такой подход помогает сохранить абстракцию. Язык, на котором написан исходный код, может не совпадать с языком кода, который будет сгенерирован.
Например, мы пишем сайт на каком-то своем языке. А на сервере у нас стоит 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;
}
В следующей статье мы рассмотрим то как можно управлять сложностью с помощью кодогенерации.