$30 off During Our Annual Pro Sale. View Details »

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. Devkit
    By the People, For the People.
    @noiselabs
    Vítor Brandão
    April 2018
    ·

    View Slide

  2. https://noiselabs.io
    @noiselabs
    Vítor Brandão
    member
    since January
    2015!
    member
    Noiselabs Consulting

    View Slide

  3. We are still not
    working together

    View Slide

  4. But we should.

    View Slide

  5. We ought to get rid of wasteful processes
    and strive for efficiency.
    But we should.

    View Slide

  6. We ought to get rid of wasteful processes
    and strive for efficiency.
    But we should.
    I'm committed to this.

    View Slide

  7. View Slide

  8. 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

    View Slide

  9. I have a zsh script for this

    hmm, Matt might have a more
    complete script
    ...but it needs ruby, I think

    View Slide

  10. Enough.

    View Slide

  11. Sounds familiar?
    (if not, I'm happy for you)

    View Slide

  12. team
    "A group of individuals
    working together to
    achieve a goal."
    noun \ ˈtēm \

    View Slide

  13. Why are we not
    cooperating?

    View Slide

  14. Collaboration requires
    individual effort.


    View Slide

  15. Collaboration requires
    individual effort.


    You have to be mindful of others.

    View Slide

  16. Collaboration requires
    individual effort.


    You have to be mindful of others.

    And you'll need to make
    concessions.

    View Slide

  17. Introducing a common tool
    may be hard.


    View Slide

  18. Introducing a common tool
    may be hard.

    But it's worth it.


    View Slide

  19. Introducing a common tool
    may be hard.

    But it's worth it.


    common tool ↝ common process

    View Slide

  20. Devkit
    developer toolkit

    View Slide

  21. This talk is not about a tool.
    It's about your team's tool.

    View Slide

  22. By the People,
    For the People*
    * s/People/Team

    View Slide

  23. View Slide

  24. •Pick the mainstream programming
    language, not just the in-house ninja-
    rockstar favourite.


    View Slide

  25. •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.


    View Slide

  26. •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.

    View Slide

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


    View Slide

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

    •Think about non-devs.


    View Slide

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

    •Think about non-devs.

    •Self-documentation is nice.


    View Slide

  30. •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.

    View Slide

  31. What do I get in return?

    View Slide

  32. •Fix it once, fix it everywhere, for
    everybody.


    View Slide

  33. •Fix it once, fix it everywhere, for
    everybody.

    •Speak a common language.


    View Slide

  34. •Fix it once, fix it everywhere, for
    everybody.

    •Speak a common language.

    •The setup is now (self-)documented.


    View Slide

  35. •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.

    View Slide

  36. "There should be
    one-- and preferably
    only one --obvious
    way to do it."
    -- The Zen of Python

    View Slide

  37. devkit@noiselabs
    (a devkit to get you started)

    View Slide

  38. https://github.com/noiselabs/devkit

    View Slide

  39. View Slide

  40. View Slide

  41. View Slide

  42. View Slide

  43. View Slide

  44. View Slide

  45. View Slide

  46. View Slide

  47. // 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());
    });
    }

    View Slide

  48. // 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,
    ]);
    }
    }

    View Slide

  49. // 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);
    }
    // ...

    View Slide

  50. // app/bin/devkit
    use Noiselabs\DevkitApp\Application;
    $autoloadFilePath = __DIR__ . '/../../vendor/autoload.php';
    require_once $autoloadFilePath;
    $application = new Application();
    $application->run();

    View Slide

  51. 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,
    ]);
    }
    }

    View Slide

  52. // 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);
    }
    }

    View Slide

  53. View Slide

  54. Before you go

    View Slide

  55. •communicate
    •collaborate
    •be efficient
    •be happy

    View Slide

  56. By the People, For the People.
    Devkit
    Thank You
    https://joind.in/talk/96595
    @noiselabs
    Vítor Brandão

    View Slide