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

Living with Open Source responsibility

Living with Open Source responsibility

It is straightforward to open source a piece of code and call it a library. It is effortless to maintain it when you are the only user, but what happens when you reach the first hundred or thousand downloads.

Semantic versioning, changelog, stable release, backward compatibility, continuous integration, code coverage probably would be some of the buzzwords that would pop up into your head.

Let's go through the process of being a responsible open-source developer and maintainer.

Mario Blazek

April 23, 2021
Tweet

More Decks by Mario Blazek

Other Decks in Programming

Transcript

  1. About me • Mario Blažek • Senior Backend Developer @QAgency

    • Lead Backend Developer @jenz.app • Married with children • Believes in Open Source • Zagreb PHP Meetup organizer (ZgPHP) • Chief Fire Officer
  2. Day 0 • You have a piece of code that

    solves your problem • Want to reuse it • Want to make it open-source • Street cred
  3. Tests • PHPUnit - https:/ /phpunit.de/ • PHPSpec - http:/

    /www.phpspec.net/ • Kahlan - https:/ /kahlan.github.io/ • Peridot - https:/ /peridot-php.github.io/ • Pest - https:/ /pestphp.com/
  4. Code quality tools • PHP Code Style Fixer - php-cs-fixer

    • PHP Static Analysis Tool - PHPStan • Reconstruction tool - rector • Static Analysis Tool - psalm
  5. PHP CS Fixer • https:/ /github.com/FriendsOfPHP/PHP-CS-Fixer • Coding Standards Fixer

    • Tool fixes your code to follow standards • wget https://cs.symfony.com/download/php-cs-fixer-v2.phar -O php-cs-fixer • php-cs-fixer fix src • .php_cs
  6. Example .php_cs <?php return PhpCsFixer\Config::create() ->setRiskyAllowed(true) ->setRules([ '@PhpCsFixer' => true,

    '@PhpCsFixer:risky' => true, // Overrides for rules included in PhpCsFixer rule sets 'concat_space' => ['spacing' => 'one'], 'method_chaining_indentation' => false, 'multiline_whitespace_before_semicolons' => false, 'native_function_invocation' => false, 'php_unit_internal_class' => false, 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'], 'php_unit_test_class_requires_covers' => false, 'phpdoc_align' => false, 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], 'single_line_comment_style' => false, 'visibility_required' => ['elements' => ['property', 'method', 'const']], 'yoda_style' => false, // Additional rules 'date_time_immutable' => true, 'declare_strict_types' => true, 'list_syntax' => ['syntax' => 'short'], 'mb_str_functions' => true, 'static_lambda' => true, 'ternary_to_null_coalescing' => true, ]) ->setFinder( PhpCsFixer\Finder::create() ->exclude(['vendor', 'node_modules', 'doc']) ->in(__DIR__) ) ;
  7. PHPStan • https:/ /phpstan.org/ • Static analysis tool • composer

    require --dev phpstan/phpstan • vendor/bin/phpstan analyse -l 6 src tests • phpstan.neon
  8. Example phpstan.neon includes: - vendor/phpstan/phpstan-strict-rules/rules.neon parameters: treatPhpDocTypesAsCertain: false ignoreErrors: #

    Symfony Form component - '/Parameter \#1 \$iterator of function iterator_to_array expects Traversable, iterable\<Symfony\\Component\\Form\\FormInterface\> given./' # Doctrine DBAL - '#Cannot call method fetchAllAssociative\(\) on Doctrine\\DBAL\\ForwardCompatibility\\DriverStatement\|int#' - '#expects string\|null, Doctrine\\DBAL\\Query\\Expression\\CompositeExpression given#' - "#Call to function method_exists\\(\\) with Symfony\\\\Component\\\\Console\\\\Application and 'renderThrowable'#" - "#Call to function method_exists\\(\\) with Symfony\\\\Component\\\\HttpKernel\\\\Event\\\\ExceptionEvent and '(get|set)Exception' will always evaluate to false.#" - "#Call to function method_exists\\(\\) with Symfony\\\\Component\\\\HttpKernel\\\\Event\\\\ExceptionEvent and '(get|set)Throwable' will always evaluate to true.#" - message: '#Call to function is_string\(\) with string will always evaluate to true.#' path: lib/Utils/DateTimeUtils.php - message: '#Variable property access on object.#' path: lib/Utils/Hydrator.php - message: '#Unsafe usage of new static\(\).#' path: lib/Utils/HydratorTrait.php
  9. Psalm • https:/ /psalm.dev/ • Static analysis tool • Developed

    by Vimeo • composer require --dev vimeo/psalm • ./vendor/bin/psalm --init • ./vendor/bin/psalm • psalm.xml <?xml version="1.0"?> <psalm errorLevel="3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" > <projectFiles> <directory name="bundles" /> <directory name="lib" /> <directory name="migrations" /> <ignoreFiles> <directory name="vendor" /> </ignoreFiles> </projectFiles> <issueHandlers> <UndefinedClass> <errorLevel type="suppress"> <referencedClass name="Symfony\Component\Debug\Exception\FlattenException" /> <referencedClass name="Symfony\Component\Debug\Exception\FatalThrowableError" /> <referencedClass name="Symfony\Component\Inflector\Inflector" /> </errorLevel> </UndefinedClass> <UndefinedMethod> <errorLevel type="suppress"> <referencedMethod name="Symfony\Component\Intl\Intl::getLocaleBundle" /> </errorLevel> </UndefinedMethod> </issueHandlers> </psalm>
  10. Reconstruction tool - rector • https:/ /getrector.org/ • Provides automated

    way to upgrade and refactor code • composer require rector/rector --dev • vendor/bin/rector init • rector.php
  11. Reconstruction tool - rector • Uses rectors • More than

    450 currently available • Migration from PHPUnit 4 to PHPUnit 8 in seconds
  12. Reconstruction tool - rector <?php // rector.php declare(strict_types=1); use Rector\Renaming\Rector\Name\RenameClassRector;

    use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; return static function (ContainerConfigurator $containerConfigurator): void { $services = $containerConfigurator->services(); $services->set(RenameClassRector::class) ->call('configure', [[ // we use constant for keys to save you from typos RenameClassRector::OLD_TO_NEW_CLASSES => [ 'App\SomeOldClass' => 'App\SomeNewClass', ], ]]); };
  13. And some more • Infection PHP - https:/ /infection.github.io/ •

    PHP Insights - https:/ /phpinsights.com/ • Deptrac - https:/ /github.com/qossmic/deptrac • PHP Mess Detector - https:/ /phpmd.org/
  14. Travis CI • De facto standard for GitHub based repositories

    • Losing tracking when they decided to shutdown travis-ci.org • .travis.yml
  15. .travis.yml language: php cache: directories: - vendor - $HOME/.composer/cache matrix:

    fast_finish: true include: - php: 7.2 - php: 7.3 branches: only: - master before_install: - phpenv config-add travis.php.ini install: - travis_wait composer install script: - ./vendor/bin/phpunit -d memory_limit=-1 --colors -c phpunit.xml --coverage-clover=coverage.xml notification: email: false git: depth: 30 sudo: false after_script: - wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover coverage.clover after_success: - bash <(curl -s https://codecov.io/bash)
  16. GitHub Actions • Provided by GitHub • Free for all

    public repositories • .github/workflows/*.yml
  17. An example workflow name: Static analysis on: push: branches: -

    'master' - '[0-9].[0-9]+' pull_request: ~ jobs: static-analysis: name: ${{ matrix.script }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: script: ['phpstan', 'phpstan-tests', 'psalm'] steps: - uses: actions/checkout@v2 - uses: shivammathur/setup-php@v2 with: php-version: '8.0' coverage: none # Install Flex as a global dependency to enable usage of extra.symfony.require # while keeping Flex recipes from applying - run: composer global require --no-scripts symfony/flex - run: composer config extra.symfony.require ~5.2.0 - run: composer update --prefer-dist - run: composer ${{ matrix.script }}
  18. Scrutinizer CI • Paid, but free for open-source projects •

    Supports code analysis • Code coverage, CI/CD, etc • .scrutinizer.yml filter: excluded_paths: - 'doc/*' - 'tests/*' - 'specs/*' - 'vendor/*' tools: external_code_coverage: true php_analyzer: true sensiolabs_security_checker: true checks: php: true
  19. codecov.io • PHPUnit’s code coverage on steroids • Can’t generate

    code coverage on its own • Other tools need to upload code coverage report • codecov.yml coverage: status: patch: false changes: false project: default: target: auto comment: false
  20. Documentation • Improves the overall package quality • Showcases the

    best practices • Don’t force developers finding their own way into your package
  21. Documentation • Markdown files • https:/ /readthedocs.org/ • https:/ /docusaurus.io/

    • https:/ /www.mkdocs.org/ • https:/ /www.gitbook.com/
  22. Licensing • Choose a proper license • An open source

    license protects contributors and users • Businesses and savvy developers won’t touch a project without this protection • Apache, MIT, GPLv3 • https:/ /spdx.org/licenses/ • https:/ /choosealicense.com/licenses/ • http:/ /www.wtfpl.net/
  23. WTFPL license • Do What the Fuck You Want to

    Public License • Very permissive
  24. Versioning and releases • Try to comply with semantic versioning

    principles • https:/ /semver.org/ • Think about Git strategy
  25. Changelog • Is a MUST • Changelog != a list

    of commits • https:/ /keepachangelog.com/en/1.0.0/ # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ## [1.0.0] - 2017-06-20 ### Added - New visual identity by [@tylerfortune8](https://github.com/tylerfortune8). - Version navigation. - Links to latest released version in previous versions. ### Changed - Start using "changelog" over "change log" since it's the common usage. - Fix phrasing and spelling in German translation. ### Removed - Section about "changelog" vs "CHANGELOG". ## [0.3.0] - 2015-12-03 ### Added - RU translation from [@aishek](https://github.com/aishek). ## [0.2.0] - 2015-10-06 ### Changed - Remove exclusionary mentions of "open source" since this project can benefit both "open" and "closed" source projects equally. ## [0.1.0] - 2015-10-06 ### Added - Answer "Should you ever rewrite a change log?". ### Changed - Improve argument against commit logs. - Start following [SemVer](https://semver.org) properly. ## [0.0.8] - 2015-02-17 ### Changed - Update year to match in every README example.
  26. We are ready to go “live” • Publish your package

    to https:/ /packagist.org/ • And now the real work begins • Be responsible, collaborate
  27. Summary • Do small steps • Lack of time •

    Try to devote 1-2 hours a week • Appreciate the feedback • Rewarding experience • Ignore mean people