Hi Kyle,

6) The name of the method
7) How the method is called throughout the codebase
10) relying on convention inside, and outside, the application

Sorry, by formulating 2) as "docstring" I excluded names of the methods as well as variables. Please assume that 2) actually entails those as well. They are human text and hence not automatically verifiable, hence qualify as 2).

8) observing input and output values during debugging
9) observing input and output values in production

Sorry, again I implicitly subsumed 8-9 under 4), reading the implementation code (including the trial-and-error). My assumption was that it is incomparably more costly to apply trial-and-error than read the contracts given that contracts can be formulated. Of course, not all contracts can be formulated all the time.

11) Don't communicate - Sometimes <complexity>/<num_customers> is too high; code is not repaired, only replaced.

I don't see this as an option for any publicly available, high-quality module on pypi or in any organization. As I already noted in my message to Hugh, the argument in favor of undocumented and/or untested code are not the arguments. I assume we want a maintainable and usable modules. I've never talked about undocumented throw-away exploratory code. Most of the Python features become futile in that case (type annotations and static type checking with mypy, to name only the few).

Does it work on Windows?
This is probably impossible to write as a contract, but needs to be tested (though maybe there is a way to check it and encapsulate the check in a separate function and put it into the contract).

What is_absolute()?  is "file:///" absolute?
Since the type is pathlib.Path (as written in the type annotation), it's pathlib.Path.is_absolute() method. Please see https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.is_absolute

At a high level, I can see the allure of DbC:  Programming can be a craft, and a person can derive deep personal satisfaction from perfecting the code they work on. DbC provides you with more decoration, more elaboration, more ornamentation, more control.  This is not bad, but I see all your arguments as personal ascetic sense.  DbC is only appealing under certain accounting rules.  Please consider the possibility that "the best code" is: low $$$, buggy, full of tangles, and mostly gets the job done.   :)
Actually, this goes totally contrary to most of my experience. Bad code is unmaintainable and ends up being much more costly down the line. It's also what we were taught in software engineering lectures in the university (some 10-15 years ago) and I always assumed that the studies presented there were correct. 

Saying that writing down contracts is costly is a straw-man. It is costly if you need to examine the function and write them down. If you are writing the function and just keep adding the contracts as-you-go, it's basically very little overhead cost. You make an assumption of the input, and instead of just coding on, you scroll up, write it down formally, and go back where you stopped and continue the implementation. Or you think for a minute what contracts your function needs to expect/satisfy before you start writing it (or during the design). I don't see how this can be less efficient than trial-and-error and making possibly wrong assumptions based on the output that you see without any documentation by running the code of the module.

Cheers,
Marko

On Tue, 25 Sep 2018 at 23:59, Kyle Lahnakoski <klahnakoski@mozilla.com> wrote:


I use DbC occasionally to clarify my thoughts during a refactoring, and then only in the places that continue to make mistakes. In general, I am not in a domain that benefits from DbC.

Contracts are code: More code means more bugs. Declarative contracts are succinct, but difficult to debug when wrong; I believe this because the debugger support for contracts is poor; There is no way to step through the logic and see the intermediate reasoning in complex contracts.  A contract is an incomplete duplication of what the code already does: at some level of complexity I prefer to use a duplicate independent implementation and compare inputs/outputs.

Writing contracts cost time and money; and that cost should be weighed against the number and flexibility of the customers that use the code.  A one-time script, a webapp for you team, an Android app for your startup, fraud software, and Facebook make different accounting decisions.  I contend most code projects can not justify DbC.


On 2018-09-24 03:46, Marko Ristin-Kaufmann wrote:
When you are documenting a method you have the following options:
1) Write preconditions and postconditions formally and include them automatically in the documentation (e.g., by using icontract library).
2) Write precondtions and postconditions in docstring of the method as human text.
3) Write doctests in the docstring of the method.
4) Expect the user to read the actual implementation.
5) Expect the user to read the testing code.


There are other ways to communicate how a method works.

6) The name of the method
7) How the method is called throughout the codebase
8) observing input and output values during debugging
9) observing input and output values in production
10) relying on convention inside, and outside, the application
11) Don't communicate - Sometimes <complexity>/<num_customers> is too high; code is not repaired, only replaced.


This is again something that eludes me and I would be really thankful if you could clarify. Please consider for an example, pypackagery (https://pypackagery.readthedocs.io/en/latest/packagery.html) and the documentation of its function resolve_initial_paths:
packagery.resolve_initial_paths(initial_paths)

Resolve the initial paths of the dependency graph by recursively adding *.py files beneath given directories.

Parameters:

initial_paths (List[Path]) – initial paths as absolute paths

Return type:

List[Path]

Returns:

list of initial files (i.e. no directories)

Requires:
  • all(pth.is_absolute() for pth in initial_paths)
Ensures:
  • len(result) >= len(initial_paths) if initial_paths else result == []
  • all(pth.is_absolute() for pth in result)
  • all(pth.is_file() for pth in result)

How is this difficult to read,[...]?

This contract does not help me: 
Does it work on Windows?
What is_absolute()?  is "file:///" absolute?
How does this code fail? 
What does a permission access problem look like? 
Can initial_paths can be None?
Can initial_paths be files? directories? 
What are the side effects?

resolve_initial_path() is a piece code is better understood by looking at the callers (#7), or not exposing it publicly (#11).  You can also use a different set of abstractions, to make the code easier to read: 
  
UNION(file for p in initial_paths for file in p.leaves() if file.extension=="py")

At a high level, I can see the allure of DbC:  Programming can be a craft, and a person can derive deep personal satisfaction from perfecting the code they work on. DbC provides you with more decoration, more elaboration, more ornamentation, more control.  This is not bad, but I see all your arguments as personal ascetic sense.  DbC is only appealing under certain accounting rules.  Please consider the possibility that "the best code" is: low $$$, buggy, full of tangles, and mostly gets the job done.   :)
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/