Development tools and practices =============================== Working in a team ----------------- Most software is developed in teams, and working effectively in a development team requires certain skills and practices. At a planning level: - Examine the required tasks, then discuss and decide on the dependencies between tasks. To start, allocate independent tasks to team members. - Let your team know when a task or piece of functionality is complete. - Discuss frequently. At the implementation level: - Use a version control system, such as Git. With Git: - Work that is committed cannot be lost (unless you try really hard) - your team members cannot accidentally delete your code. - Commit changes frequently and in small chunks. This makes clear to others what you are working on, and any conflicts will be easier to resolve. - It is easy to switch between computers. - Add tests as functionality is developed. This: - Builds confidence that your implementation is correct. - Can detect if a change by you or a team member has affected your implementations. (One of the most frustrating situations in team development is when a change by another team members breaks your carefully constructed functionality.) .. _using-git: Using Git --------- `Git `_ is modern widely used *version control system* (VCS). A version control system tracks changes to source code. It can show what has changed, and who has made changes and when they made them. Git is very powerful and can be challenging to learn. Elementary Git usage for getting started is summarised below. Git is generally used from the command line (terminal), but here are tools that provide graphical interfaces and some editors (e.g. VS Code) have built-in Git support. VS Code ^^^^^^^ VS Code provides helpers for the operations in the following section. Command-line use ^^^^^^^^^^^^^^^^ Creating or cloning a repository ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To clone a repository (typically hosted by an online service), e.g.: .. code-block:: bash git clone https://github.com/CambridgeEngineering/PartIA-Computing-Michaelmas.git The location for a particular repository can be found on the online repository page. To create a new repository, create a directory and execute in the directory the command: .. code-block:: bash git init Adding a new file or adding file changes to the staging area ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The command: .. code-block:: bash git add myfile.py instructs Git that we want to track the file ``myfile.py``, or if the file is already tracked that we will want to add any changes to the repository history. Committing changes to the project history ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``commit`` command commits changes to the project history, and each commit has a 'commit message' associated with it: .. code-block:: bash git commit -m "Complete Task 1C" It is possible at any time to see the changes between any two commits, and to revert a repository to a particular commit. Collaborating: merging changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To fetch remote changes into your repository, e.g. changes made by your team mate: .. code-block:: bash git pull In general, you should ``commit`` your changes before using ``pull``. To send your changes to the remote server: .. code-block:: bash git push If team members have 'pushed' changes, you will need to use ``git pull`` before you can push. Once you have pushed changes, other team members will receive your changes when they next 'pull'. Seeing changes in your working directory ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The command: .. code-block:: bash git diff shows any changes to your code since the last commit. The command: .. code-block:: bash git status will show any changes to files that are (a) tracked but have changed since the most recent commit, and (b) files that are not tracked (have not been added using ``git add``). Project history ~~~~~~~~~~~~~~~ The log of project commits is displayed by the command: .. code-block:: bash git log The output will include the commit messages and the author of each commit. Project history is shown by online services, like GitHub, and this the simplest way to examine project change. It is also possible to add comments and suggestions on particular code changes to discuss with team members. How often should I commit changes? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Often. Structure your work into small chunks, and commit after completing each 'chunk'. At the very least, you should commit changes at the completion of each *Task* in the *Deliverables* section. Also, pull and push frequently. Getting help with Git ~~~~~~~~~~~~~~~~~~~~~ There are many online resources for learning Git, and search engines for very useful. Helpful tutorials for beginners are: - https://guides.github.com/introduction/git-handbook/ - https://code.visualstudio.com/docs/sourcecontrol/overview - https://learngitbranching.js.org/ - https://swcarpentry.github.io/git-novice/ .. _using-pytest: Test framework -------------- Testing is critical for high quality software development, and there are many tools for helping with this. In this project you will use `pytest `__. Some tests are in the project starter repository. Write tests as you go, and run the tests frequently to check that nothing has been inadvertently broken. Running tests ^^^^^^^^^^^^^ ``pytest`` is very simple to use: #. Put tests in files starting with ``test_``, e.g. ``test_data.py``. #. In the test file, prefix test function with ``test_``, e.g.:: def test_sum(): a, b = 2, 3 assert a + b == 5 #. To run all tests in all ``test_*.py`` files in a directory, use: .. code-block:: bash pytest . To run all tests in the file ``test_data,py``: .. code-block:: bash pytest test_data.py ``pytest`` will print a summary of the number of tests run, with the number that pass and the number that fail. Writing tests ^^^^^^^^^^^^^ Aim to have at least one test for every function in your library. Some tests will just check that a function can be called successfully, e.g.:: import mymodule def test_call(): x = mymodule.do_something(4) More useful test will check results, e.g.:: import mymodule def test_my_sum(): sum = mymodule.sum(7, -8) assert sum == -1 Take care when comparing floating point values, since round-off errors can make precise comparison difficult. Use rounding to compare floats, e.g:: import math def test_math_sine(): x = math.sin(0.0) assert round(x, 8) == 0 # 'round' keep 8 digits after the decimal point pi = 3.14159265359 x = math.sin(pi) assert round(x, 8) == 0 pi = 3.14159265359 x = math.sin(pi/2.0) assert round(x - 1, 8) == 0