Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Devkit. By the People, For the People.

Devkit. By the People, For the People.

We are still not working together on our projects. And that leads to frustration and hinders productivity.

See how by using a common developer tool you enforce a common process and a common language, boosting your projects and making developers happier.

Vítor Brandão

April 11, 2018
Tweet

More Decks by Vítor Brandão

Other Decks in Programming

Transcript

  1. We ought to get rid of wasteful processes and strive

    for efficiency. But we should. I'm committed to this.
  2. ah you need to run the db script too Hi,

    how do I setup my environment? I see... oh, just git clone the app repo and run docker-compose up sometimes it fails so make sure you clear the cache
  3. I have a zsh script for this hmm, Matt might

    have a more complete script ...but it needs ruby, I think
  4. Collaboration requires individual effort.
 
 You have to be mindful

    of others. 
 And you'll need to make concessions.
  5. Introducing a common tool may be hard.
 But it's worth

    it.
 
 common tool ↝ common process
  6. •Pick the mainstream programming language, not just the in-house ninja-

    rockstar favourite.
 •Be inclusive: make it work across different OSes and setups and invite everyone to contribute.

  7. •Pick the mainstream programming language, not just the in-house ninja-

    rockstar favourite.
 •Be inclusive: make it work across different OSes and setups and invite everyone to contribute.
 •...but don't go too far, apply standard setups where needed. Compromise.
  8. •Make it dead easy to push fixes. This ain't production

    code.
 •Think about non-devs.

  9. •Make it dead easy to push fixes. This ain't production

    code.
 •Think about non-devs.
 •Self-documentation is nice.

  10. •Make it dead easy to push fixes. This ain't production

    code.
 •Think about non-devs.
 •Self-documentation is nice.
 •Documentation is even nicer. A simple README.md will suffice.
  11. •Fix it once, fix it everywhere, for everybody.
 •Speak a

    common language.
 •The setup is now (self-)documented.
 

  12. •Fix it once, fix it everywhere, for everybody.
 •Speak a

    common language.
 •The setup is now (self-)documented.
 
 On-boarding will be much easier, much faster.
  13. // devkit/DevkitApplication.php abstract class DevkitApplication extends SymfonyConsoleApplication { public function

    __construct(?string $name = null, ?string $version = null) { // ... $this->container = new \Pimple\Container(); $this->buildContainer(); $this->registerCommands(); } private function buildContainer(): void { $this->setService('app_settings', function () { return AppSettings::fromConfig(); }); $this->setService('env', function (Container $c) { return new Environment($c['app_settings']); }); $this->setService('local_executor', function () { return new LocalExecutor(); }); $this->setService('docker_remote_executor', function (Container $c) { return new DockerRemoteExecutor($c['env']->getDockerDir()); }); $this->setService('vagrant_remote_executor', function (Container $c) { return new DockerRemoteExecutor($c['env']->getVagrantDir()); }); }
  14. // devkit/DevkitApplication.php abstract class DevkitApplication extends SymfonyConsoleApplication { // ...

    public function setService(string $name, $service): void { $this->container[$name] = $service; } public function getService(string $name): string { if (!isset($this->container[$name])) { throw new RuntimeException(sprintf('Service "%s" is not available.', $name)); } return $this->container[$name]; } private function registerCommands(): void { $this->addCommands([ new Command\Docker\DockerLogs, new Command\Docker\DockerShell, new Command\Docker\DockerStart, new Command\Docker\DockerStop, new Command\PhpQa\Phan, new Command\PhpQa\Phpstan, new Command\Phpqa\QaList, new Command\Vagrant\VagrantHalt, new Command\Vagrant\VagrantUp, ]); } }
  15. // devkit/Infra/Command/DockerCompose.php /** * Define and run multi-container applications with

    Docker. */ class DockerCompose { /** * build: Build or rebuild services. */ public static function build(?string $service = null, ?string $command = null, array $options = []): DockerRemoteCommand { return self::buildDockerCommand('build', $service, $command, $options); } /** * exec: Execute a command in a running container. */ public static function exec(string $service, string $command, array $options = []): DockerRemoteCommand { return self::buildDockerCommand('exec', $service, $command, $options); } /** * run: Run a one-off command. */ public static function run(string $service, string $command, array $options = []): DockerRemoteCommand { return self::buildDockerCommand('run --rm', $service, $command, $options); } // ...
  16. // app/bin/devkit <?php use Noiselabs\DevkitApp\Application; $autoloadFilePath = __DIR__ . '/../../vendor/autoload.php';

    require_once $autoloadFilePath; $application = new Application(); $application->run();
  17. <?php namespace Noiselabs\DevkitApp; use Noiselabs\Devkit\DevkitApplication; use Noiselabs\DevkitApp\Command as Command; class

    Application extends DevkitApplication { const APP_NAME = 'DevkitApp'; const APP_VERSION = '0.1.0'; public function __construct( ?string $name = self::APP_NAME, ?string $version = self::APP_VERSION) { parent::__construct($name, $version); $this->setService('remote_executor', $this->getService('docker_remote_executor')); $this->addCommands([ new Command\EnvDown, new Command\EnvReload, new Command\EnvSetup, new Command\EnvUp, ]); } }
  18. // app/src/Command/EnvUp.php namespace Noiselabs\DevkitApp\Command; // ... class EnvUp extends DevkitCliCommand

    { protected function configure() { $this->setName('env:up'); $this->setDescription('Boots the development environment'); } protected function execute(InputInterface $input, OutputInterface $output): void { $io = $this->getConsoleIo($input, $output); $io->writeln(Environment::OUTPUT_TITLE_PREFIX . 'Booting the development environment...'); $this->getApplication()->find('cache:clear')->run(new ArrayInput([]), $output); $this->executeRemoteCommand(DockerCompose::up(null, ['-d']), $input, $output); $this->getApplication()->find('database:reset')->run(new ArrayInput([]), $output); } }