SlideShare a Scribd company logo
1 of 40
Download to read offline
Ф‘Yii’лософия
QuartSoft
YiiSoft
Климов П.В.
Чем «Компилятор» отличается
от «Интерпетатора»?
Компилятор
Бинарный код
(*.exe, *.dll)
Анализ:
лексический и
синтаксический
Семантический
разбор
Исходный код
Внутренне
представление
Генерация кода
Компилятор
Разработчик
Пользователь
Интерпретатор
Анализ:
лексический и
синтаксический
Семантический
разбор
Исходный код
Внутренне
представление
Выполнение
Интерпретатор
Пользователь
Динамическое
подключение
файлов
Для каких языков пишут
«умные» книги?
Порядок выполнения приложения
Построение
конфигурации
Создание
приложения
Разбор маршрута,
выбор контроллера
Выполнение
контроллера
Построение и
возврат ответа
Web Server
php “index.php”
Параметры
HTTP сообщения
Конфигурация *должна* храниться в
текстовых файлах специального
формата
JSON {“name”: “foo”, “strict”: false, …}
XML
<application
name=“foo”>…</application>
ini
[application]
name = “foo"
Yaml
name: foo
paths:
data: app/data
Построение конфигурации
Синтаксический
анализ
Семантический
разбор
Исходный код
Внутренне
представление
Анализатор
(Parser)
PHP
array/object
- parse_ini_file()
- json_decode()
- simplexml_load_file()
- Yaml::parse()
return [
‘name’ => ‘foo’,
‘components’ => [
‘cache’ => [
‘class’ => ‘yiicachingMemCache’,
'servers' => [
[
'host' => 'localhost',
'port' => 11211,
'weight' => 100,
],
],
],
// …
],
];
Конфигурация приложения Yii
Порождение объектов в Yii
function createObject(array $config)
{
$className = $config['class'];
if (empty($className)) {
throw new Exception(‘Missing parameter "class"!');
}
unset($config['class']);
$object = new $className();
foreach ($config as $name=>$value) {
$object->$name = $value; // Конфигурация
}
return $object;
}
$config = [
'class‘ => ‘yiidbConnection',
‘dsn‘ => ‘mysql:host=127.0.0.1;dbname=demo‘,
'schemaCache' => [
‘class' => 'yiicachingMemCache',
'servers' => [
[
'host' => 'localhost',
'port' => 11211,
'weight' => 100,
],
],
],
];
$object = Yii::createObject($config);
Задание любого объекта через массив
Каким будет результат работы
программы?
$arr1 = [1, 2, 3];
foreach ($arr1 as &$value) {
$value *= 2;
}
$arr2 = [4, 5, 6];
foreach ($arr2 as &$value) {
$value *= 2;
}
echo array_sum($arr1) + array_sum($arr2);
PHP - Hypertext Pre-Processor
<?php
$arr1 = [1, 2, 3];
foreach ($arr1 as &$value) {
$value *= 2;
}
$arr2 = [4, 5, 6];
foreach ($arr2 as &$value) {
$value *= 2;
}
echo array_sum($arr1) + array_sum($arr2);
Используйте шаблоны для
построения выходных документов
Smarty
<head>
<title>App Name – {$title}</title>
</head>
Twig
<head>
<title>App Name – {{ title }}</title>
</head>
Blade
<head>
<title>App Name - @yield('title')</title>
</head>
Отображение по шаблону
Анализ:
лексический и
синтаксический
Семантический
разбор
Исходный код
Внутреннее
(временное)
представление
Выполнение
Шаблонизатор
Динамическое
подключение
файлов
- Smarty
- Twig
- Blade
PHP
Отображение на Yii:
PHP + Helpers + Widgets
<html lang="<?= Yii::$app->language ?>">
<head>
<title><?= Html::encode($this->title) ?></title>
</head>
<body>
…
<?= Menu::widget([
'items' => [
['label' => 'Home', 'url' => ['site/index']],
]
]) ?>
…
Пользуйтесь интерфейсами везде,
где это возможно
class Application extends Module implements
ApplicationInterface {…}
class Request extends Component implements
RequestInterface {…}
class Controller extends Component implements
ControllerInterface {…}
class HttpException extends Exception implements
HttpExceptionInterface {…}
Как работает полиморфизм?
Interface ShapeInterface
{
public function draw(int $x, int $y);
}
…
public function drawShape(ShapeInterface $shape)
{
…
$shape->draw($x, $y);
// варианты (таблица) реальных вызовов:
// - Rectangle::draw()
// - Circle::draw()
// - Triangle::draw()
}
Цена интерфейса
namespace app;
// PHP version = 7.1
class Item {}
…
interface EmptyInterface {}
…
class EmptyItem implements EmptyInterface {}
// Yii2 has 336 classes, interfaces, traits
$item = new Item(); // X100
// diffTime = 0.00621s diffMemory = 136424B
$item = new EmptyItem(); // X100
// diffTime = 0.01247s diffMemory = 174872B
namespace app;
// PHP version = 7.1
class FilledItem {…}
…
interface FilledInterface {…}
…
class InterfacedItem implements FilledInterface {…}
// Yii2 has 336 classes, interfaces, traits
$item = new FilledItem(); // X100
// diffTime = 0.05291s diffMemory = 9407848B
$item = new InterfacedItem(); // X100
// diffTime = 0.05937s diffMemory = 10179512B
PHP (Web Server)
Parse request
Prepare SQL
MySQL Server
Request
web page
Return
HTML
Parse query result
Compose HTML
Parse SQL
Execute query
Prepare response
Кто сколько работает?
// yii2-app-basic/index.php
$beginTime = microtime(true);
require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';
$config = require __DIR__ . '/../config/web.php';
(new yiiwebApplication($config))->run();
$endTime = microtime(true);
var_dump($endTime - $beginTime); // ~ 0.01s
// interfaces price = 10 – 50 %
Загрузка сущности (class, interface, trait)
Определение файла
с исходным кодом
Чтение файла
(require)
Анализ исходного
кода
Построение
внутренней модели
сущности
Composer
Autoloader
PHP
Интерпретатор
(+Акселератор)
Разбор имени
сущности и
пространства имен
SOLID vs KISS
Ручка по SOLID
Pen
write()
Case
Корпус
Rod
Стержень
ScrewCap
Колпачковая
гайка
Ink
Чернила
CoverCap
Колпачок
Ball
Шарик
Pointer
Перо
Frame Surface
Поверхность
1
1 1
1
1
1 1
1
1
*
1
1 1
PenFactory
1*
Ручки бывают разные…
Ручка по SOLID, ревизия №2
Pen
write()
Case
Корпус
Rod
Стержень
ScrewCap
Колпачковая гайка
Ink
Чернила
CoverCap
Колпачок
Ball
Шарик
Pointer
Перо
Frame Surface
Поверхность
1
1
1
1
1
1 1
1
1
*
1
1 1
PenFactory
1*
RodSwitcher
*
1
1
Ручка по KISS
Pen
write()
Распределенные приложения
Client
Load
Balancer
Regular
HTTP
requests
Web
Server 1
Web
Server 2
Internal HTTP requests
DBread/write read/write
Microframeworks
Framework Microframework
Symfony Silex
Laravel Lumen
Yii
О крайностях
Принцип «бороться
за каждый байт!»
Vanilla PHP
C-based PHP
extension
Phalcon
Резидентное
приложение, PHP
демоны и LibEvent
ReactPHP
PHP Framework – вопрос баланса
Функциональность Производительность
Используйте ограничения типов
interface RequestParserInterface
{
public function parse(Request $request);
}
interface ResponseFormatterInterface
{
public function format(ResponseInterface $response);
}
class FileHelper
{
public static function copyDirectory(
string $src,
string $dst,
DirectoryCopyOptions $options
) {…}
}
Application – Service Locator
baseComponent
Application
$definitions
$components
*1
Request
Client
get($id)
“Request component
by id”
…
“Create and
store by id”
Response Formatter
Соглашения уменьшают количество
сущностей
interface RequestParserInterface
{
/**
* @param Request $request – request CONVENTION
*/
public function format($request);
}
interface ResponseFormatterInterface
{
/**
* @param Response $response – response CONVENTION
*/
public function format($response);
}
Документация Yii
/*
* PHP Doc
*/
Руководство
пользователя
(Guide)
Комментарии в коде – это плохо
class FileHelper
{
public static function copyDirectory(
string $sourceDirectory,
string $destinationDirectory,
DirectoryCopyOptions $options
) {…}
}
class DirectoryCopyOptions
{
public $caseSensitive = false;
}
Соглашение через PHPDoc вместо
строгой конфигурации
class FileHelper
{
/**
* Copies a whole directory as another one.
* …
* @param array $options options for directory copy.
* Valid options are:
* - recursive: boolean, whether the files under the subdirectories
* should also be copied. Defaults to true.
*/
public static function copyDirectory($src, $dst, $options = [])
{…}
}
Этапы проверки кода
Синтаксический и
семантический
анализ
Модульное
тестирование
Функциональное
тестирование
Ручное
тестирование
Рецензирование
(Code Review)
Разработчик
Интерпретатор
Тестировщик
Ст. разработчик
(Архитектор)
Ф’Yii’лософия
• PHP - это интерпретатор
• С интерпретатором не нужно бороться
• Конфигурация приложения и объектов
• Отображение: Helpers + Widget
• Минимальная декомпозиция
• KISS вместо SOLID
• PHPDoc
• Соглашения вместо конфигурации
http://www.yiiframework.com/

More Related Content

What's hot

DevConf 2012 - Yii, его разработка и Yii2
DevConf 2012 - Yii, его разработка и Yii2DevConf 2012 - Yii, его разработка и Yii2
DevConf 2012 - Yii, его разработка и Yii2Alexander Makarov
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)ZFConf Conference
 
UWDC 2013, Как мы используем Yii
UWDC 2013, Как мы используем YiiUWDC 2013, Как мы используем Yii
UWDC 2013, Как мы используем YiiAlexander Makarov
 
Take more from Jquery
Take more from JqueryTake more from Jquery
Take more from JqueryMagento Dev
 
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОПЧуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОПzfconfua
 
"Жизнь без интернета" Кувалдин Артём, Яндекс
"Жизнь без интернета" Кувалдин Артём, Яндекс"Жизнь без интернета" Кувалдин Артём, Яндекс
"Жизнь без интернета" Кувалдин Артём, Яндексit-people
 
Реализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в MagentoРеализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в MagentoMagecom Ukraine
 
Миша Рудрастых: Введение в HTTP API WordPress
Миша Рудрастых: Введение в HTTP API WordPressМиша Рудрастых: Введение в HTTP API WordPress
Миша Рудрастых: Введение в HTTP API WordPressRuslan Begaliev
 
10 - Web-технологии. MVC фреймворки (продолжение)
10 - Web-технологии. MVC фреймворки (продолжение)10 - Web-технологии. MVC фреймворки (продолжение)
10 - Web-технологии. MVC фреймворки (продолжение)Roman Brovko
 
Сущности в Drupal 7
Сущности в Drupal 7Сущности в Drupal 7
Сущности в Drupal 7Itech4Web
 
Rambler.iOS #8: Как не стать жертвой бэкендеров
Rambler.iOS #8: Как не стать жертвой бэкендеровRambler.iOS #8: Как не стать жертвой бэкендеров
Rambler.iOS #8: Как не стать жертвой бэкендеровRAMBLER&Co
 
jQuery как путь к RIA
jQuery как путь к RIAjQuery как путь к RIA
jQuery как путь к RIAGetDev.NET
 
Индексирование в Magento
Индексирование в MagentoИндексирование в Magento
Индексирование в MagentoMagecom Ukraine
 
Industrial Programming Java - Lection Pack 01 - Building an application - Lav...
Industrial Programming Java - Lection Pack 01 - Building an application - Lav...Industrial Programming Java - Lection Pack 01 - Building an application - Lav...
Industrial Programming Java - Lection Pack 01 - Building an application - Lav...Fedor Lavrentyev
 
Form api в drupal 7
Form api в drupal 7Form api в drupal 7
Form api в drupal 7dimateus
 

What's hot (20)

Crazy owl yii1=> yii2
Crazy owl yii1=> yii2Crazy owl yii1=> yii2
Crazy owl yii1=> yii2
 
DevConf 2012 - Yii, его разработка и Yii2
DevConf 2012 - Yii, его разработка и Yii2DevConf 2012 - Yii, его разработка и Yii2
DevConf 2012 - Yii, его разработка и Yii2
 
UWDC 2013, Yii2
UWDC 2013, Yii2UWDC 2013, Yii2
UWDC 2013, Yii2
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)
 
UWDC 2013, Как мы используем Yii
UWDC 2013, Как мы используем YiiUWDC 2013, Как мы используем Yii
UWDC 2013, Как мы используем Yii
 
Take more from Jquery
Take more from JqueryTake more from Jquery
Take more from Jquery
 
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОПЧуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОП
 
"Жизнь без интернета" Кувалдин Артём, Яндекс
"Жизнь без интернета" Кувалдин Артём, Яндекс"Жизнь без интернета" Кувалдин Артём, Яндекс
"Жизнь без интернета" Кувалдин Артём, Яндекс
 
Почему Mojolicious?
Почему Mojolicious?Почему Mojolicious?
Почему Mojolicious?
 
Реализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в MagentoРеализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в Magento
 
Миша Рудрастых: Введение в HTTP API WordPress
Миша Рудрастых: Введение в HTTP API WordPressМиша Рудрастых: Введение в HTTP API WordPress
Миша Рудрастых: Введение в HTTP API WordPress
 
10 - Web-технологии. MVC фреймворки (продолжение)
10 - Web-технологии. MVC фреймворки (продолжение)10 - Web-технологии. MVC фреймворки (продолжение)
10 - Web-технологии. MVC фреймворки (продолжение)
 
Сущности в Drupal 7
Сущности в Drupal 7Сущности в Drupal 7
Сущности в Drupal 7
 
Rambler.iOS #8: Как не стать жертвой бэкендеров
Rambler.iOS #8: Как не стать жертвой бэкендеровRambler.iOS #8: Как не стать жертвой бэкендеров
Rambler.iOS #8: Как не стать жертвой бэкендеров
 
Perl 5.10 и 5.12
Perl 5.10 и 5.12Perl 5.10 и 5.12
Perl 5.10 и 5.12
 
jQuery как путь к RIA
jQuery как путь к RIAjQuery как путь к RIA
jQuery как путь к RIA
 
Суперсилы Chrome developer tools
Суперсилы Chrome developer toolsСуперсилы Chrome developer tools
Суперсилы Chrome developer tools
 
Индексирование в Magento
Индексирование в MagentoИндексирование в Magento
Индексирование в Magento
 
Industrial Programming Java - Lection Pack 01 - Building an application - Lav...
Industrial Programming Java - Lection Pack 01 - Building an application - Lav...Industrial Programming Java - Lection Pack 01 - Building an application - Lav...
Industrial Programming Java - Lection Pack 01 - Building an application - Lav...
 
Form api в drupal 7
Form api в drupal 7Form api в drupal 7
Form api в drupal 7
 

Similar to Ф'Yii'лософия

Экскурс в мир WEB разработки
Экскурс в мир WEB разработкиЭкскурс в мир WEB разработки
Экскурс в мир WEB разработкиIT-Доминанта
 
Основы "мобильной" разработки на примере платформы iOs (iPhone)
Основы "мобильной" разработки на примере платформы iOs (iPhone)Основы "мобильной" разработки на примере платформы iOs (iPhone)
Основы "мобильной" разработки на примере платформы iOs (iPhone)Pavel Tsukanov
 
Node.JS: возможности для РНР-разработчика
Node.JS: возможности для РНР-разработчикаNode.JS: возможности для РНР-разработчика
Node.JS: возможности для РНР-разработчикаAlexei Smolyanov
 
Alexei Sintsov - "Between error and vulerability - one step"
Alexei Sintsov - "Between error and vulerability - one step"Alexei Sintsov - "Between error and vulerability - one step"
Alexei Sintsov - "Between error and vulerability - one step"Andrew Mayorov
 
Функциональное программирование для разработки распределённых, облачных и веб...
Функциональное программирование для разработки распределённых, облачных и веб...Функциональное программирование для разработки распределённых, облачных и веб...
Функциональное программирование для разработки распределённых, облачных и веб...Dmitri Soshnikov
 
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NETОпыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NETGoSharp
 
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОПЧуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОПKirill Chebunin
 
Remote (dev)tools своими руками
Remote (dev)tools своими рукамиRemote (dev)tools своими руками
Remote (dev)tools своими рукамиRoman Dvornov
 
Устройство фреймворка symfony 2 (http://frontend-dev.ru)
Устройство фреймворка symfony 2 (http://frontend-dev.ru)Устройство фреймворка symfony 2 (http://frontend-dev.ru)
Устройство фреймворка symfony 2 (http://frontend-dev.ru)Александр Егурцов
 
Rich UI on Dojo Toolkit and Zend Framework
Rich UI on Dojo Toolkit and Zend FrameworkRich UI on Dojo Toolkit and Zend Framework
Rich UI on Dojo Toolkit and Zend FrameworkGeorgy Turevich
 
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...Anthony Marchenko
 
Конкурс для разработчиков от Evernote
Конкурс для разработчиков от EvernoteКонкурс для разработчиков от Evernote
Конкурс для разработчиков от EvernoteEvernote
 
WebCamp 2016: Python.Максим Климишин.Типизированный Python
WebCamp 2016: Python.Максим Климишин.Типизированный PythonWebCamp 2016: Python.Максим Климишин.Типизированный Python
WebCamp 2016: Python.Максим Климишин.Типизированный PythonWebCamp
 
Автоматизация SEO-процессов в продуктовых компаниях - DVOMA.pro 30.08
Автоматизация SEO-процессов в продуктовых компаниях - DVOMA.pro 30.08Автоматизация SEO-процессов в продуктовых компаниях - DVOMA.pro 30.08
Автоматизация SEO-процессов в продуктовых компаниях - DVOMA.pro 30.08Vladislav Morgun
 
Web осень 2013 лекция 6
Web осень 2013 лекция 6Web осень 2013 лекция 6
Web осень 2013 лекция 6Technopark
 
Разработка ПО. Введение в специальность 3. Требования
 Разработка ПО. Введение в специальность 3. Требования Разработка ПО. Введение в специальность 3. Требования
Разработка ПО. Введение в специальность 3. ТребованияPavel Egorov
 
Виталий Каторгин, Wamba
Виталий Каторгин, WambaВиталий Каторгин, Wamba
Виталий Каторгин, WambaOntico
 

Similar to Ф'Yii'лософия (20)

Экскурс в мир WEB разработки
Экскурс в мир WEB разработкиЭкскурс в мир WEB разработки
Экскурс в мир WEB разработки
 
php frameworks
php frameworksphp frameworks
php frameworks
 
Основы "мобильной" разработки на примере платформы iOs (iPhone)
Основы "мобильной" разработки на примере платформы iOs (iPhone)Основы "мобильной" разработки на примере платформы iOs (iPhone)
Основы "мобильной" разработки на примере платформы iOs (iPhone)
 
Node.JS: возможности для РНР-разработчика
Node.JS: возможности для РНР-разработчикаNode.JS: возможности для РНР-разработчика
Node.JS: возможности для РНР-разработчика
 
Alexei Sintsov - "Between error and vulerability - one step"
Alexei Sintsov - "Between error and vulerability - one step"Alexei Sintsov - "Between error and vulerability - one step"
Alexei Sintsov - "Between error and vulerability - one step"
 
Функциональное программирование для разработки распределённых, облачных и веб...
Функциональное программирование для разработки распределённых, облачных и веб...Функциональное программирование для разработки распределённых, облачных и веб...
Функциональное программирование для разработки распределённых, облачных и веб...
 
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NETОпыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
 
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОПЧуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОП
 
Remote (dev)tools своими руками
Remote (dev)tools своими рукамиRemote (dev)tools своими руками
Remote (dev)tools своими руками
 
JPHP
JPHPJPHP
JPHP
 
Устройство фреймворка symfony 2 (http://frontend-dev.ru)
Устройство фреймворка symfony 2 (http://frontend-dev.ru)Устройство фреймворка symfony 2 (http://frontend-dev.ru)
Устройство фреймворка symfony 2 (http://frontend-dev.ru)
 
Transpile it.pdf
Transpile it.pdfTranspile it.pdf
Transpile it.pdf
 
Rich UI on Dojo Toolkit and Zend Framework
Rich UI on Dojo Toolkit and Zend FrameworkRich UI on Dojo Toolkit and Zend Framework
Rich UI on Dojo Toolkit and Zend Framework
 
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
 
Конкурс для разработчиков от Evernote
Конкурс для разработчиков от EvernoteКонкурс для разработчиков от Evernote
Конкурс для разработчиков от Evernote
 
WebCamp 2016: Python.Максим Климишин.Типизированный Python
WebCamp 2016: Python.Максим Климишин.Типизированный PythonWebCamp 2016: Python.Максим Климишин.Типизированный Python
WebCamp 2016: Python.Максим Климишин.Типизированный Python
 
Автоматизация SEO-процессов в продуктовых компаниях - DVOMA.pro 30.08
Автоматизация SEO-процессов в продуктовых компаниях - DVOMA.pro 30.08Автоматизация SEO-процессов в продуктовых компаниях - DVOMA.pro 30.08
Автоматизация SEO-процессов в продуктовых компаниях - DVOMA.pro 30.08
 
Web осень 2013 лекция 6
Web осень 2013 лекция 6Web осень 2013 лекция 6
Web осень 2013 лекция 6
 
Разработка ПО. Введение в специальность 3. Требования
 Разработка ПО. Введение в специальность 3. Требования Разработка ПО. Введение в специальность 3. Требования
Разработка ПО. Введение в специальность 3. Требования
 
Виталий Каторгин, Wamba
Виталий Каторгин, WambaВиталий Каторгин, Wamba
Виталий Каторгин, Wamba
 

Ф'Yii'лософия