contributed to Pylint. Transition: you test it, you document it, but how often have you gotten grief for regressions that didn't break tests? Deliver Your Software In An Envelope Augie Fackler & Nathaniel Manista Google, Inc. 13 April, 2014 Deliver Your Software in an Envelope http://localhost:8080/print/ 1 of 59 4/13/14, 12:57 PM
ways that don't break any promises but still gotten grief from your clients? Image source: http://commons.wikimedia.org/wiki/File:Angry_mob_of_four.jpg Deliver Your Software in an Envelope http://localhost:8080/print/ 2 of 59 4/13/14, 12:57 PM
like other systems, there are right ways and wrong ways to use it. Deliver Your Software in an Envelope http://localhost:8080/print/ 6 of 59 4/13/14, 12:57 PM
DO NOT BOTHER TALKING ABOUT imaginary numbers. Transition to "but at another level of abstraction..." Deliver Your Software in an Envelope http://localhost:8080/print/ 9 of 59 4/13/14, 12:57 PM
run with 4G of RAM, but you'd better close your browser and other RAM hogs before you do, or it'll be a somewhat swappy experience. I've got a low end GPU, so I have to turn the texture quality down. "System Requirements" Deliver Your Software in an Envelope http://localhost:8080/print/ 10 of 59 4/13/14, 12:57 PM
can be a on object in a language interpreter, a process on a machine, or a machine itself. HTTP server (multiple levels of abstraction) Deliver Your Software in an Envelope http://localhost:8080/print/ 11 of 59 4/13/14, 12:57 PM
here is done value-by-value because we don't have types to differentiate. Deliver Your Software in an Envelope http://localhost:8080/print/ 15 of 59 4/13/14, 12:57 PM
for a system's domain (its inputs). It turns out that it is helpful to define one for its outputs as well, --TRANSITION-- though not so much for systems that have exact (deterministic) outputs Deliver Your Software in an Envelope http://localhost:8080/print/ 19 of 59 4/13/14, 12:57 PM
commercial systems exposing only an API * Game systems for which implementation details would give cheaters an advantage --TRANSITION-- So what does this add up to generally? Deliver Your Software in an Envelope http://localhost:8080/print/ 25 of 59 4/13/14, 12:57 PM
the state of the world. Output dimensions: return values, raised exceptions, side effects. We will say "behavioral envelope" to mean the sum of "input envelope" and "output envelope". Deliver Your Software in an Envelope http://localhost:8080/print/ 26 of 59 4/13/14, 12:57 PM
Output ranges. Blocking and non-blocking semantics. Thread safety. The pressure we're putting on you here is that if you state your envelope, you're guaranteed to have thought about it first. We see a lot of code that was written without such thinking. This is how you hold off the angry mob. Weak Thesis: You should state your system's behavioral envelope. Strong Thesis: Your statement of your system's behavioral envelope should be your only statement of your system's behavior. Deliver Your Software in an Envelope http://localhost:8080/print/ 27 of 59 4/13/14, 12:57 PM
static double sqrt(double n) { // code goes here } def sqrt(n): """Returns the square root of N. >>> sqrt(5) 2.23606797749979 >>> sqrt(-1) ValueError """ # code goes here Deliver Your Software in an Envelope http://localhost:8080/print/ 28 of 59 4/13/14, 12:57 PM
another mechanism of expression available to both machines and programmers. map map: (a0 -> b0) -> [a0] -> [b0] Deliver Your Software in an Envelope http://localhost:8080/print/ 29 of 59 4/13/14, 12:57 PM
in the way it demands a certain kind of agreement between the types of the inputs. Deliver Your Software in an Envelope http://localhost:8080/print/ 30 of 59 4/13/14, 12:57 PM
this doesn't look like something you'd want to share with your clients as part of your system's definition... --TRANSITION-- Pycurracy test in something more like natural language. def testPageLoads(self): """Tests that page loads properly.""" user = profile_utils.seedNDBUser( host_for=[self.program]) profile_utils.loginNDB(user) response = self.get(_getOrgAppShowUrl(self.org)) self.assertResponseOK(response) Deliver Your Software in an Envelope http://localhost:8080/print/ 31 of 59 4/13/14, 12:57 PM
of your system as persuasive evidence that your system is suitable for some purpose. Given I go to GSoC Home Page When I click "Apply_Org" link and wait Then I see "test_org" title Deliver Your Software in an Envelope http://localhost:8080/print/ 32 of 59 4/13/14, 12:57 PM
input is not allowed". Or "this function will never...", or "overriding subclasses must...". --TRANSITION-- How do these systems interact? Are they redundant? Complementary? DO NOT COVER INTEGRATION WITH TYPE SYSTEM YET Deliver Your Software in an Envelope http://localhost:8080/print/ 33 of 59 4/13/14, 12:57 PM
defined by a continuous barrier on one side and a single point on the other side. Transition into exploring this as software, rather than metaphor. Deliver Your Software in an Envelope http://localhost:8080/print/ 34 of 59 4/13/14, 12:57 PM
strings. class HttpServer(object): def __call__(client_string): """string -> string""" # code goes here Deliver Your Software in an Envelope http://localhost:8080/print/ 35 of 59 4/13/14, 12:57 PM
and only allow strings. The edge of the envelope is smooth because we're using a type system. Deliver Your Software in an Envelope http://localhost:8080/print/ 36 of 59 4/13/14, 12:57 PM
requests and some don't. We represent those as points because type systems can't make this discrimination within the string type. Deliver Your Software in an Envelope http://localhost:8080/print/ 37 of 59 4/13/14, 12:57 PM
tests serve to illustrate the edge of our envelope that cannot be described by the type system. --TRANSITION-- to javadoc showing how these types and documentation can work together. Deliver Your Software in an Envelope http://localhost:8080/print/ 38 of 59 4/13/14, 12:57 PM
documentation - in this case the type system and documentation system are working together. Deliver Your Software in an Envelope http://localhost:8080/print/ 39 of 59 4/13/14, 12:57 PM
the engineering reality is that we would like our clients to have some assurance that our software achieves something. Live, running code in the context of a demo is a great way to persuade that our software does something useful. What conducts a demonstration of live, running code? A test. So ship your tests to your clients. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. Deliver Your Software in an Envelope http://localhost:8080/print/ 40 of 59 4/13/14, 12:57 PM
Go’s [example test functions](http://golang.org/pkg/testing/), and [cram](https://pypi.python.org/pypi/cram) for shell tools, Docs are good, but explaining is losing. Bonus points if your docs are automatically tested. def sqrt(n): """Returns the square root of N. >>> sqrt(5) 2.23606797749979 >>> sqrt(-1) ValueError """ # code goes here Deliver Your Software in an Envelope http://localhost:8080/print/ 41 of 59 4/13/14, 12:57 PM
the library's functionality as a user, and it's less to maintain for an author. Aim for the least-committed envelope possible without crippling your clients or hampering their performance. Narrow the input side but widen the output side. Transition to examples. Good/bad envelope definition examples. Difference between what must be and what happens to be. Less (Guarantees) Is More (Freedom To Keep Those Guarantees) Deliver Your Software in an Envelope http://localhost:8080/print/ 42 of 59 4/13/14, 12:57 PM
fit on the slide, but that's not really what's important here. (null) | | HTTPConnection() v Idle | | putrequest() v Request-started | | ( putheader() )* endheaders() v Request-sent | | response = getresponse() v Unread-response [Response-headers-read] |\____________________ | | | response.read() | putrequest() v v Idle Req-started-unread-response ______/| / | Deliver Your Software in an Envelope http://localhost:8080/print/ 45 of 59 4/13/14, 12:57 PM
the internals of this package, because you've told clients how to abuse your internals. This would have been a great thing to change in Python 3, but it [didn't happen](http://hg.python.org /cpython/file/b466fd273625/Lib/http/client.py). Python 4, I guess? "HTTPResponse class does not enforce this state machine, which implies sophisticated clients may accelerate the request/response pipeline." Deliver Your Software in an Envelope http://localhost:8080/print/ 46 of 59 4/13/14, 12:57 PM
could be exposed on Object" and the input envelope was built too widely. Java's Object methods Object.clone Object.finalize Deliver Your Software in an Envelope http://localhost:8080/print/ 47 of 59 4/13/14, 12:57 PM
(38) are defined. Status-Code = "200" ; OK | "201" ; Created | "202" ; Accepted | "204" ; No Content | "301" ; Moved Permanently | "302" ; Moved Temporarily | "304" ; Not Modified | "400" ; Bad Request | "401" ; Unauthorized | "403" ; Forbidden | "404" ; Not Found | "500" ; Internal Server Error | "501" ; Not Implemented | "502" ; Bad Gateway | "503" ; Service Unavailable Deliver Your Software in an Envelope http://localhost:8080/print/ 50 of 59 4/13/14, 12:57 PM
codes than RFC 2616 (HTTP/1.1), which came 3 years later. 402 (Payment required), 206 (Partial content), etc all introduced later, and are safe for existing clients only because of the above defensive specification. RFC 1945: HTTP status codes are extensible[...]. HTTP applications are not required to understand the meaning of all registered status codes[...]. However, applications must understand the class of any status code, as indicated by the first digit, and treat any unrecognized response as being equivalent to the x00 status code of that class, with the exception that an unrecognized response must not be cached. Deliver Your Software in an Envelope http://localhost:8080/print/ 51 of 59 4/13/14, 12:57 PM
lets you work around the GIL, but has a limitation in that it has to pickle arguments to send them to other processes. Easy to envision something that'd use Stackless's microthreads. Maybe even one that used any PEP3156 event loop. ThreadPoolExecutor ProcessPoolExecutor Deliver Your Software in an Envelope http://localhost:8080/print/ 53 of 59 4/13/14, 12:57 PM
operation in Python? Once came up in a Google-internal debate. It turns out that it is in the current version of Python - but as an implementation detail. There's no formal support for it. Our position in the debate was that you should program to the envelope of behavior that Python's documentation guarantees rather than some specific behavior that it implements. my_dict[my_key] = new_value Deliver Your Software in an Envelope http://localhost:8080/print/ 54 of 59 4/13/14, 12:57 PM
started programming, it felt like a bunch of discrete circuits. Source Code Is The Best Documentation! Deliver Your Software in an Envelope http://localhost:8080/print/ 55 of 59 4/13/14, 12:57 PM
connecting exact bits of behavior into larger, still very precise systems. Deliver Your Software in an Envelope http://localhost:8080/print/ 56 of 59 4/13/14, 12:57 PM
it feels more like plumbing a variable-flow system. You're still connecting outputs to downstream inputs, but when you do you're ensuring simple compatibility between them rather than making an exact match. Mature software creation is about assembling, transforming, and convolving behavioral envelopes. Deliver Your Software in an Envelope http://localhost:8080/print/ 57 of 59 4/13/14, 12:57 PM