Рубрики
Uncategorized

Вернуться к корням: к истинной непрерывной интеграции (часть одной)

В этой статье я хотел бы показать вам, что многие верят, что CI, что … Помечено AgileWebandappde, Agiledevelopment, AnductiveGrati, DevOps.

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

Что такое CI?

CI (Акроним для непрерывной интеграции) представляет собой практику разработки программного обеспечения, в которой непрерывный интеграционный сервер опрос репозиторий управления версиями создает артефакт и проверяет артефакт с набором определенных тестов. Это обычная практика для большинства предприятий и частных лиц … И это не настоящее определение непрерывного интеграции, извините за шутку.

Что такое настоящая постоянная интеграция?

Ну, истинная непрерывная интеграция не «просто» какая-то «Дженкинс | Трэвис | Go | Teamcity», которые опросают репозиторий Git проекта, компилирует его и запустить кучу испытаний против артефакта. На самом деле, это менее интересная часть CI, которая не является технологией (Дженкинс), но провилегированная практика, созданная Гарди Боч и принята и предписана Экстремальная методология программирования Отказ

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

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

Методология гласит, что каждый член команды интегрируется в основные линии, насколько это возможно. Каждый вклад в VCS (система контроля версий) потенциально является выпуском, поэтому каждый вклад не должен нарушать функциональность и должен пройти все известные тесты.

Сервер CI построит артефакт из последних источников магистрали и пройдет все известные тесты. Если есть неудача, то Ci предупреждает всех членов команды штата Создать (красный).

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

Что не CI?

Как только мы поняли, что CI гораздо больше, чем простое использование CI Server, мы можем утверждать, что:

  • Работа с функциональными ветвями и иметь CI Checking Master не CI
  • Работа с запросами по тяги не CI

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

Обе функциональные ветви и запросы на тягу полагаются на разных ветви, чем мастер (тот, который контролируется сервером Ci), это приводит к более длинным циклам, прежде чем они могут быть объединены в Master.

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

Пример интеграции ада: У нас есть следующий код, два класса, которые используют обратные вызовы API для внешнего API:

APIUsersAccessor
class APIUsersAccessor
{
    const USERS_API_PATH = "/users";
 /**
     * @var string
     */
    private $host;
    /**
     * @var string
     */
    private $username;
    /**
     * @var string
     */
    private $password;
    public function __construct(string $host, string $username, string
$password)
    {
        $this->host = $host;
        $this->username = $username;
        $this->password = $password;
}
    public function getAllUsers(): array
    {
        $data = array(
            "email" => $this->username,
            "password" => $this->password
        );
        $headers = array(
            "Content-Type" => "application/json;charset=UTF-8"
        );
        $request = \Requests::GET($this->host.self::USERS_API_PATH,
$headers, json_encode($data));
        return json_decode($request->body);
    }
}

APIProductsAccessor
class APIProductsAccessor
{
    const PRODUCTS_API_PATH = "/products";
    /**
* @var string
     */
    private $host;
    /**
     * @var string
     */
    private $username;
    /**
     * @var string
     */
    private $password;
    public function __construct(string $host, string $username, string
$password)
    {
        $this->host = $host;
        $this->username = $username;
        $this->password = $password;
}
    public function getAllProducts(): array
    {
        $data = array(
            "email" => $this->username,
            "password" => $this->password
        );
        $headers = array(
            "Content-Type" => "application/json;charset=UTF-8"
        );
        $request = \Requests::GET($this->host.self::PRODUCTS_API_PATH,
$headers, json_encode($data));
        return json_decode($request->body);
    }
}

Как вы можете видеть, оба кода очень похожи (является дублирование классического кода). Теперь мы собираемся начать две функции развития с 2 филиалами разработки. Первое разработка должна добавить номер телефона к запросу на API продуктов, второй должен создать новую API для запроса всех автомобилей, доступных в магазине. Это код в API продуктов после добавления номера телефона:

APIUsersAccessor (with telephone)
class APIUsersAccessor
{
....
    public function __construct(string $host, string $username, string
$password)
{
.......
  $this->telephone = $telephone;
    }
    public function getAllUsers(): array
    {
        $data = array(
            "email" => $this->username,
            "password" => $this->password,
   "tel" => $this->telephone
        );
..... }
}

Хорошо, разработчик добавил недостающее поле и добавил его к запросу. Разработчик филиала 1 ожидает, что этот различий в качестве слива с мастером:

Но проблема в том, что Developer1 не знает, что разработчик 2 сделал рефактором, чтобы уменьшить дублирование кода, потому что Carapi слишком похож на USERAPI и ProductaPi, поэтому код в его ветке будет таким:

BaseAPIAccessor
abstract class BaseAPIAccessor
{
    private $apiPath;
    /**
* @var string
     */
    private $host;
    /**
     * @var string
     */
    private $username;
    /**
     * @var string
     */
    private $password;
    protected function __construct(string $host,string $apiPath, string
$username, string $password)
    {
        $this->host = $host;
        $this->username = $username;
        $this->password = $password;
        $this->apiPath = $apiPath;
}
    protected function doGetRequest(): array
    {
        $data = array(
            "email" => $this->username,
            "password" => $this->password
        );
        $headers = array(
            "Content-Type" => "application/json;charset=UTF-8"
        );
        $request = \Requests::GET($this->host.$this->apiPath, $headers,
json_encode($data));
        return json_decode($request->body);
    }
}
concrete APIs
class ApiCarsAccessor extends BaseAPIAccessor
{
    public function __construct(string $host, string $username, string
$password)
    {
        parent::__construct($host, "/cars", $username, $password);
}
    public function getAllUsers(): array
    {
        return $this->doGetRequest();
    }
}
class APIUserAccessor extends BaseAPIAccessor
{
    public function __construct(string $host, string $username, string
$password)
    {
        parent::__construct($host, "/users", $username, $password);
}
    public function getAllUsers(): array
    {
        return $this->doGetRequest();
    }
}
class APIProductsAccessor extends BaseAPIAccessor
{
    public function __construct(string $host, string $username, string
$password)
    {
        parent::__construct($host, "/products", $username, $password);
}
    public function getAllProducts(): array
    {
        return $this->doGetRequest();
    }
}

Так что реальное слияние будет:

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

Некоторые утверждают, что Developer2 не должен был сделать рефактору, потому что планирование заявило, что он должен развивать только Carapi, а планирование четко заявляло, что не должно быть столкновения с USERAPI. Ну да… Но сделать то, что такого рода экстремальные планификационные работы должны быть хорошее планирование всех ресурсов, у нас должно быть много архитектурных встреч с участием Developer1 и Developer2.

В этих архитектурных встречах Developer1 и Developer2 должны были реализовать, что существует какой-то дублирование кода, и они должны решать o intermene и repens, или ничего не делайте и увеличивают техническую задолженность, перемещая решение рефакторов на будущие итерации. Это может не звучать на Agile, верно? Но точка в том, что трудно смешать Agile и неимущие практики.

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

Agile — это все о связи, все о непрерывном улучшении, и это все о обратной связи как можно скорее. В Agile Acke Developer1 будет знать о рефакторинге Developer2 в начале, возможность начать диалог с разработчиком1 и проверить, является ли тип абстракции, который он предлагает, будет правильным, чтобы соответствовать также добавлению номера телефона.

Да, но ждать! Мне нужна функция ветви! Что если не все функции доставлены в конце итерации?

Функциональные ветви — это решение проблемы: что делать, если не все код доставляется в конце итерации, но это не единственное решение.

CI имеет другое решение этой проблемы — «Обновление функций». Функциональные филиалы изолируют функцию прогресса работы от конечного продукта через ветку (W.I.P. Живет в отдельной копии кода), функция переключается изолировать функцию от остальной части кода, используя .. Code!

Самая простая функция Toggle можно написать — это страшный, если он-else-else, является примером, который вы найдете в большинстве сайтов, когда вы погружаетесь «Функция Toggle». Это не единственный способ реализации, так как любой другой тип программного обеспечения, которую вы можете заменить эту условную логику с полиморфизмом.

В этом примере в Slim мы создаем нынешнюю итерацию новую конечную точку отдыха, мы не хотели быть готовыми к производству, у нас есть этот код:

code prior the toggling
 [
        'displayErrorDetails' => true,
        'logger' => [
            'name' => "dexeus",
            'level' => Monolog\Logger::DEBUG,
            'path' => 'php://stderr',
], ],
];
$app = new \Slim\App(
$config );
$c = $app->getContainer();
$c['logger'] = function ($c) {
    $settings = $c->get('settings');
    $logger = LoggerFactory::getInstance($settings['logger']['name'],
$settings['logger']['level']);
    $logger->pushHandler(new
Monolog\Handler\StreamHandler($settings['logger']['path'],
$settings['logger']['level']));
    return $logger;
};
$app->group("", function () use ($app){
 OriginalEndpoint::get()->add($app); //we are registering the endpoint
in slim });

Мы можем определить переключательную функцию простым предложением

if clause feature toggle
group("", function () use ($app){
 OriginalEndpoint::get()->add($app);
    if(getenv("APP_ENV") === "development") {
        NewEndpoint::get()->add($app); // we are registering the new
endpoint if the environment is set to development (devs machines should
have APP_ENV envar setted to development)
} });

И мы можем уточнить наш код, чтобы лучше выразить то, что мы делаем, и сможем иметь несколько сред (возможно, для того, чтобы иметь ситуацию с тестом AB?)

configuration map feature toggle
add($app);
};
$aEnvironment = function ($app){
    productionEnvironment($app);
    NewEndpointA::get()->add($app);
};
$bEnvironment = function ($app){
    productionEnvironment($app);
    NewEndpointB::get()->add($app);
};
$develEnvironment = function ($app){
    productionEnvironment($app);
    NewEndpointInEarlyDevelopment::get()->add($app);
};
$configurationMap = [
    "production" => $productionEnvironment,
    "testA" => $aEnvironment,
    "testB" => $bEnvironment,
    "development" => $develEnvironment
];
$app->group("", function () use ($app, $configurationMap){
    $configurationMap[getenv("APP_ENV")]($app);
});

Преимущества этого метода согласованы с главной целью CI (имеющие постоянную обратную связь о интеграции кода/проверки/и столкновения с другими событиями), код в процессе разработан и развернут в производство, и у нас постоянные отзывы о интеграции Новая функция с остальной частью кода, используя риск включения функции, когда она разработана.

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

Хорошо, мы приехали в конце этой первой части истинной непрерывной интеграции. Мы заново открыли, что непрерывная интеграция — «не только», используя CI Server, но принятие практики с настойчивостью и дисциплиной. Во второй части мы поговорим о том, как моделировать хороший поток Ci.

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

Если вы нашли эту статью о истинной постоянной интеграции, вам может понравиться …

Scala Generics I: Границы типа Scala

Scala Regrics II: ковариация и контравариация

BDD: тестирование пользовательского интерфейса

F-связанный над универсальным типом в Scala

Минервисов против монолитной архитектуры

» Почти бесконечное «масштабируемость

Преимущества истинной непрерывной интеграции

Рабочее программное обеспечение над количеством функций

Преимущества TDD

Преимущества Дженкинс

Истинная постоянная интеграция с Fastlane & Jenkins в iOS

Пост Вернуться к корням: к истинной непрерывной интеграции (часть одной части) появился первым на Apiumhub Отказ

Оригинал: «https://dev.to/apium_hub/back-to-the-roots-towards-true-continuous-integration-part-one-14m7»