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

Developer Ergonomics

Developer Ergonomics

Keynote for PyCaribbean

José Padilla

February 18, 2017
Tweet

More Decks by José Padilla

Other Decks in Programming

Transcript

  1. You'll eventually
    want to
    install third party
    packages...

    View full-size slide

  2. Enter easy_install

    View full-size slide

  3. Enter easy_install

    View full-size slide

  4. $ pip install Django==1.8

    View full-size slide

  5. You just installed
    Django globally.

    View full-size slide

  6. $ pip install Django==1.10

    View full-size slide

  7. You just installed
    Django globally.

    View full-size slide

  8. Developer
    Ergonomics

    View full-size slide

  9. Package Managers
    and Environments

    View full-size slide

  10. José Padilla

    View full-size slide

  11. Work
    Training
    Open Source

    View full-size slide

  12. Work
    Training
    Open Source

    View full-size slide

  13. Work
    Training
    Open Source

    View full-size slide

  14. Lets begin...

    View full-size slide

  15. Node.js + NPM

    View full-size slide

  16. Node Package
    Manager

    View full-size slide

  17. Installing packages
    with npm is easy.

    View full-size slide

  18. $ npm install express

    View full-size slide

  19. └─┬ [email protected]
    ├─┬ [email protected]
    │ ├─┬ [email protected]
    │ │ └── [email protected]
    │ └── [email protected]
    ├── array-fl[email protected]
    ├── [email protected]
    ├── [email protected]
    ├── [email protected]
    ├── [email protected]
    ├─┬ [email protected]
    │ └── [email protected]
    ├── [email protected]
    ├── [email protected]
    ├── [email protected]
    ├── [email protected]
    ├─┬ fi[email protected]
    │ ├── [email protected]
    │ └── [email protected]
    ├── [email protected]
    ├── [email protected]
    ├── [email protected]
    ├─┬ on-fi[email protected]
    │ └── ee-fi[email protected]
    ├── [email protected]
    ├── [email protected]
    ├─┬ [email protected]
    │ ├── [email protected]
    │ └── [email protected]
    ├── [email protected]
    ├── [email protected]
    ├─┬ [email protected]
    │ ├── [email protected]
    │ ├─┬ [email protected]
    │ │ ├── [email protected]
    │ │ └── [email protected]
    │ ├── [email protected]
    │ └── [email protected]
    ├── [email protected]
    ├─┬ [email protected]
    │ └── [email protected]
    ├── [email protected]
    └── [email protected]
    └─┬ [email protected]
    ├─┬ [email protected]
    │ ├─┬ [email protected]
    │ │ └── [email protected]
    │ └── [email protected]
    ├── array-fl[email protected]
    ├── [email protected]
    ├── [email protected]
    ├── [email protected]
    ├── [email protected]
    ├─┬ [email protected]
    │ └── [email protected]
    ├── [email protected]
    ├── [email protected]
    ├── [email protected]

    View full-size slide

  20. $ npm install express --save

    View full-size slide

  21. {
    "name": "pycaribbean",
    "version": "1.0.0",
    "dependencies": {
    "express": "^4.14.1"
    }
    }

    View full-size slide

  22. $ npm uninstall express --save

    View full-size slide

  23. {
    "name": "pycaribbean",
    "version": "1.0.0",
    "dependencies": {}
    }

    View full-size slide

  24. The default behavior
    of npm is to install
    packages locally to
    the current directory.

    View full-size slide

  25. global = CLI tools

    View full-size slide

  26. $ npm install eslint --global

    View full-size slide

  27. $ npm install supertest --save-dev

    View full-size slide

  28. {
    "name": "nodejs",
    "version": "1.0.0",
    "dependencies": {},
    "devDependencies": {
    "supertest": "^3.0.0"
    }
    }

    View full-size slide

  29. $ npm install

    View full-size slide

  30. $ npm install --production

    View full-size slide

  31. Dependency Conflicts

    View full-size slide

  32. $ npm install package-a --save

    View full-size slide

  33. $ npm install package-b --save

    View full-size slide

  34. $ npm shrinkwrap

    View full-size slide

  35. {
    "name": "A",
    "version": "1.1.0",
    "dependencies": {
    "B": {
    "version": "1.0.1",
    "from": "B@^1.0.0",
    "resolved": "..."
    }
    }
    }

    View full-size slide

  36. Node.js + Yarn

    View full-size slide

  37. Installing packages
    with yarn is easy.

    View full-size slide

  38. $ yarn add express

    View full-size slide

  39. $ yarn add --dev mocha

    View full-size slide

  40. $ yarn global add eslint

    View full-size slide

  41. # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE
    DIRECTLY.
    # yarn lockfile v1
    package-1@^1.0.0:
    version "1.0.3"
    resolved "https://registry.npmjs.org/package-1/-/
    package-1-1.0.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c2
    84ca"
    package-2@^2.0.0:
    version "2.0.1"
    resolved "https://registry.npmjs.org/package-2/-/
    package-2-2.0.1.tgz#9a5f699051b1e7073328f2a008968b64ea29
    55d2"
    dependencies:
    package-4 "^4.0.0"

    View full-size slide

  42. Rust + Cargo

    View full-size slide

  43. Cross-pollination at
    its best.

    View full-size slide

  44. [package]
    name = "package_a"
    version = "0.1.0"
    authors = ["root"]
    [dependencies]
    package_b = "0.0.1"

    View full-size slide

  45. [root]
    name = "package_a"
    version = "0.0.1"
    dependencies = [
    "package_b 0.0.1 (...)",
    ]
    [[package]]
    name = "package_b"
    version = "0.0.1"
    source = "..."
    [metadata]
    "checksum package_b 0.0.1 (...)"
    = "7507624b29483431c0ba2d82aece"

    View full-size slide

  46. Python + PIP

    View full-size slide

  47. Installing
    packages with pip
    is easy.

    View full-size slide

  48. $ pip install flask

    View full-size slide

  49. $ pip install flask
    $ pip freeze > requirements.txt

    View full-size slide

  50. click==6.7
    Flask==0.12
    itsdangerous==0.24
    Jinja2==2.9.5
    MarkupSafe==0.23
    Werkzeug==0.11.15

    View full-size slide

  51. $ pip uninstall flask
    $ pip freeze > requirements.txt

    View full-size slide

  52. click==6.7
    itsdangerous==0.24
    Jinja2==2.9.5
    MarkupSafe==0.23
    Werkzeug==0.11.15

    View full-size slide

  53. ├── requirements
    │ ├── common.txt
    │ ├── dev.txt
    │ └── prod.txt
    └── requirements.txt

    View full-size slide

  54. $ cat requirements.txt
    -r requirements/prod.txt

    View full-size slide

  55. $ cat requirements/prod.txt
    -r common.txt
    gunicorn==19.6.0
    newrelic==2.74.0.54

    View full-size slide

  56. $ cat requirements/common.txt
    Django==1.10.5

    View full-size slide

  57. $ cat requirements/dev.txt
    pytest==3.0.6

    View full-size slide

  58. $ pip install -r requirements.txt

    View full-size slide

  59. $ pip install -r requirements/dev.txt

    View full-size slide

  60. The default behavior
    of pip is to install
    packages globally.

    View full-size slide

  61. Installing local
    dependencies

    View full-size slide

  62. $ pip install virtualenv

    View full-size slide

  63. $ virtualenv .venv

    View full-size slide

  64. $ source .venv/bin/activate

    View full-size slide

  65. $ .venv/bin/python
    Python 2.7.9 (default, Dec 21 2016, 01:15:20)
    [GCC 4.2.1 Compatible Apple LLVM 8.0.0
    (clang-800.0.42.1)] on darwin
    Type "help", "copyright", "credits" or "license" for more
    information.
    >>>

    View full-size slide

  66. (.venv) $ which python
    /path/to/.venv/bin/python

    View full-size slide

  67. (.venv) $ pip install flask

    View full-size slide

  68. (.venv) $ deactivate

    View full-size slide

  69. $ which python
    /usr/bin/python

    View full-size slide

  70. $ python3 -m venv .venv

    View full-size slide

  71. $ source .venv/bin/activate

    View full-size slide

  72. (.venv) $ pip install flask

    View full-size slide

  73. (.venv) $ deactivate

    View full-size slide

  74. Dependency Conflicts

    View full-size slide

  75. package-a
    Depends on requests==1.0.0

    View full-size slide

  76. package-b
    Depends on requests==2.12.4

    View full-size slide

  77. $ pip install package-a
    $ pip install package-b
    $ pip freeze

    View full-size slide

  78. package-a==0.1
    package-b==0.1
    requests==2.12.4

    View full-size slide

  79. Packages and
    dependencies are
    flat.

    View full-size slide

  80. $ pip check
    package-a has requirement requests==1.0.0, but you have
    requests 2.12.4.

    View full-size slide

  81. $ pip install flask && pip check

    View full-size slide

  82. function pip-install() {
    pip install $@ && pip check
    }

    View full-size slide

  83. $ pip-install flask

    View full-size slide

  84. Going forward

    View full-size slide

  85. Changing the
    defaults of tools
    like pip without
    creating chaos is
    hard.

    View full-size slide

  86. Installing
    packages in
    Python could be
    easier.

    View full-size slide

  87. "One of the hurdles that new Python
    developers have to get over is
    understanding the Python packaging
    ecosystem."
    – Jamie Matthews (@j4mie)

    View full-size slide

  88. "Variables in Python are local by default,
    so why aren't packages? You have to
    go out of your way to make a global
    variable. You should also have to go out
    of your way to install a package
    globally."
    – Trey Hunner (@treyhunner)

    View full-size slide

  89. My ideal
    scenario

    View full-size slide

  90. Default to
    installing
    packages
    locally.

    View full-size slide

  91. Improved
    dependency
    resolving.

    View full-size slide

  92. Fully specified
    and deterministic.

    View full-size slide

  93. $ pip install flask

    View full-size slide

  94. $ pip install --dev pytest

    View full-size slide

  95. $ pip install

    View full-size slide

  96. How does it work?

    View full-size slide

  97. "There's someone
    already working
    on a similar idea"

    View full-size slide

  98. Kenneth Reitz
    open sourced
    pipenv on
    January 19 2017

    View full-size slide

  99. Python + Pipenv

    View full-size slide

  100. More than 15
    hours on Hacker
    News' front page.

    View full-size slide

  101. More than 2500
    stars on GitHub.

    View full-size slide

  102. Dogfooding
    kennethreitz/requests

    View full-size slide

  103. Sacred Marriage of
    Pipfile, Pip, &
    Virtualenv

    View full-size slide

  104. Cross-pollination at
    its best.

    View full-size slide

  105. Requirements 2.0

    View full-size slide

  106. Pipfile will be superior
    to requirements.txt file
    in a number of ways...

    View full-size slide

  107. TOML syntax for
    declaring all types of
    Python dependencies.

    View full-size slide

  108. One Pipfile, as
    opposed to multiple
    requirements.txt files.

    View full-size slide

  109. [dev-packages]
    pytest = "*"
    [packages]
    flask = "*"

    View full-size slide

  110. Pipfile.lock

    View full-size slide

  111. {
    "default": {
    "MarkupSafe": {
    "version": "==0.23",
    "hash": "sha256:a4ec1aff59b95a1..."
    },
    "Jinja2": {
    "version": "==2.9.5",
    "hash": "sha256:a7b7438120dbe76..."
    },
    "Werkzeug": {
    "version": "==0.11.15",
    "hash": "sha256:c6f6f89124df051..."
    },
    "flask": {
    "version": "==0.12",
    "hash": "sha256:7f03bb2c2554524..."
    },
    "itsdangerous": {
    "version": "==0.24",
    "hash": "sha256:cbb3fcf8d3e33df..."
    },
    "click": {
    "version": "==6.7",
    "hash": "sha256:29f99fc6125fbc9..."
    }
    },
    "develop": {
    "packaging": {
    "version": "==16.8",
    "hash": "sha256:99276dc6e3a7851..."
    },
    "pytest": {
    "version": "==3.0.6",
    "hash": "sha256:da0ab50c7eec068..."
    },
    "setuptools": {
    "version": "==34.1.1",
    "hash": "sha256:5f74aabe68c441b..."
    },
    "pyparsing": {
    "version": "==2.1.10",
    "hash": "sha256:67101d7acee6929..."
    },
    "py": {
    "version": "==1.4.32",
    "hash": "sha256:2d4bba2e25fff58..."
    },
    "six": {
    "version": "==1.10.0",
    "hash": "sha256:0ff78c403d9bccf..."
    },
    "appdirs": {
    "version": "==1.4.0",
    "hash": "sha256:85e58578db8f295..."
    }
    },
    "_meta": {
    "sources": [
    {
    "url": "https://pypi.python.org/simple",
    "verify_ssl": true
    }
    ],
    "requires": {},
    "hash": {
    "sha256": "c755a9d5787ce2fdc70f7..."
    }
    }
    }
    {
    "default": {
    "MarkupSafe": {
    "version": "==0.23",
    "hash": "sha256:a4ec1aff59b95a1..."
    },
    "Jinja2": {
    "version": "==2.9.5",
    "hash": "sha256:a7b7438120dbe76..."
    },
    "Werkzeug": {
    "version": "==0.11.15",
    "hash": "sha256:c6f6f89124df051..."
    },
    "flask": {
    "version": "==0.12",
    "hash": "sha256:7f03bb2c2554524..."
    },
    "itsdangerous": {
    "version": "==0.24",
    "hash": "sha256:cbb3fcf8d3e33df..."
    },
    "click": {
    "version": "==6.7",
    "hash": "sha256:29f99fc6125fbc9..."
    }
    },
    "develop": {
    "packaging": {
    "version": "==16.8",
    "hash": "sha256:99276dc6e3a7851..."
    },

    View full-size slide

  112. pypa/pipfile

    View full-size slide

  113. Enables truly
    deterministic builds,
    while easily specifying
    what you want.

    View full-size slide

  114. Automatically
    generates and checks
    file hashes for locked
    dependencies.

    View full-size slide

  115. Automatically finds
    your project home,
    recursively, by looking
    for a Pipfile.

    View full-size slide

  116. Automatically
    generates a Pipfile, if
    one doesn’t exist.

    View full-size slide

  117. Automatically
    generates a
    Pipfile.lock, if one
    doesn’t exist.

    View full-size slide

  118. Automatically creates
    a virtualenv in a
    standard location.

    View full-size slide

  119. Automatically adds
    packages to a Pipfile
    when they are
    installed.

    View full-size slide

  120. Automatically removes
    packages from a
    Pipfile when they are
    un-installed.

    View full-size slide

  121. Also automatically
    updates pip.

    View full-size slide

  122. Installing
    packages with
    Pipenv is easy.

    View full-size slide

  123. $ pipenv install flask

    View full-size slide

  124. $ pipenv install pytest --dev

    View full-size slide

  125. $ pipenv install

    View full-size slide

  126. $ pipenv shell

    View full-size slide

  127. Current drawbacks?

    View full-size slide

  128. $ pipenv install flask
    $ pipenv lock

    View full-size slide

  129. $ pipenv install --lock flask

    View full-size slide

  130. Its our job to build
    the best software
    possible using the
    best tools for it.

    View full-size slide

  131. We go out there and
    learn from other
    communities to make
    ours better.

    View full-size slide

  132. Python is not only for
    those that've been
    using it for the past
    10 years...

    View full-size slide

  133. ...its also for those
    that will begin using
    it for the next 10.

    View full-size slide

  134. There are smart
    people already
    working on how to
    improve this.

    View full-size slide

  135. Awesome work
    already done.

    View full-size slide

  136. Thank you to
    everyone helping
    make Python and it's
    ecosystem better.

    View full-size slide

  137. From The Zen of
    Python

    View full-size slide

  138. Beautiful is better
    than ugly.

    View full-size slide

  139. Simple is better than
    complex.

    View full-size slide

  140. There should be one
    and preferably only
    one obvious way to do
    it.

    View full-size slide

  141. Now is better than
    never.

    View full-size slide