Software Freedom Conservancy filed multiple exemptions in the USA Copyright Office Triennial Rulemaking Process under the Digital Millennium Copyright Act (DMCA). In this episode, Karen and Bradley explore the details of Conservancy's filing to request permission to circumvent technological restriction measures in order to investigate infringement of other people's copyright, which is a necessary part of investigations of alleged violations of the GPL and other copyleft licenses.
Show Notes: Segment 0 (00:39)If you are a Conservancy Supporter as well as being a FaiFCast listener, you can join this mailing list to receive announcements of live recordings and attend them through Conservancy's Big Blue Button (BBB) server.
Send feedback and comments on the cast to <oggcast@faif.us>. You can keep in touch with Free as in Freedom on our IRC channel, #faif on irc.freenode.net, and by following Conservancy on on Twitter and and FaiF on Twitter.
Free as in Freedom is produced by Dan Lynch of danlynch.org. Theme music written and performed by Mike Tarantino with Charlie Paxson on drums.
The content of this audcast, and the accompanying show notes and music are licensed under the Creative Commons Attribution-Share-Alike 4.0 license (CC BY-SA 4.0).
We'll have 2 presentations this month, A conversation with Bradley Kuhn about the Software Freedom Conservancy and (ab)Using DNS
Attend the meeting on Thursday November 12th at 7PM by visiting: https://lufthans.bigbluemeeting.com/b/plu-yuk-7xx
Bradley Kuhn: A conversation with Bradley Kuhn about the Software Freedom Conservancy
Description:
We're going to start the new year off with an interview. Bradley and our host will chat about the Software Freedom Conservancy, Free Software and licensing and his history in the Free Software movement.
Biography:
Bradley M. Kuhn is the Policy Fellow and Hacker-in-Residence at Software Freedom Conservancy and editor-in-chief of copyleft.org. Kuhn began his work in the software freedom movement as a volunteer in 1992, when he became an early adopter of Linux-based systems, and began contributing to various Free Software projects, including Perl. He worked during the 1990s as a system administrator and software developer for various companies, and taught AP Computer Science at Walnut Hills High School in Cincinnati. Kuhn's non-profit career began in 2000, when he was hired by the FSF. As FSF's Executive Director from 2001–2005, Kuhn led FSF's GPL enforcement, launched its Associate Member program, and invented the Affero GPL. Kuhn was appointed President of Software Freedom Conservancy in April 2006, was Conservancy's primary volunteer from 2006–2010, and has been a full-time staffer since early 2011. Kuhn holds a summa cum laude B.S. in Computer Science from Loyola University in Maryland, and an M.S. in Computer Science from the University of Cincinnati. Kuhn's Master's thesis discussed methods for dynamic interoperability of Free Software programming languages. Kuhn received the O'Reilly Open Source Award in 2012, in recognition for his lifelong policy work on copyleft licensing. Kuhn has a blog and co-hosts the audcast, Free as in Freedom.
Donald Mac McCarthy: (ab)Using DNS
Description:
Let's take a look at DNS from a new perspective. In this presentation we will discuss using DNS for cost savings and speed increases in datastore operations. We will also take advantage of DNS's unique architecture and capabilities to improve redundancy and increase distribution for near zero cost. Finally, I will show how to push security farther toward the entry into the technology stack and make our applications a part of our security posture.
The last month of the old year showed a lot of activity on the border of AI and biology. The advances in protein folding with deep learning are a huge breakthrough that could revolutionize drug design. It’s important to remember the role AI had in developing the vaccine for COVID—and also worth remembering that we still don’t have an anti-viral. And while I didn’t list them, the other big trend has been all the lawyers lining up to take shots at Google, Facebook, et al. Some of these are political posturing; others address real issues. We said recently the tech industry has had a free ride as far as the law goes; that’s clearly over.
AI, ML, and Data2020 has been a year of great challenges for so many, but it’s not all negative. Around the world, organizations and their workforces have risen to the occasion, recognizing the importance of expanding their knowledge, taking on new tasks, and bettering themselves both personally and professionally. With the uptick in virtual conferencing, remote work, and, for some, reentering the job market, new technology adoption was accelerated, driving the workforce to build new skills. While 2020 was the year of the global COVID-19 pandemic, it will also be commemorated as the year online learning prevailed. As vaccine development persists and life gets back to normal, with it will come a more future-proof workforce ready to share their new knowledge with the world.
Since the onset of the pandemic, online courses and programs have seen dramatic spikes in consumption and enrollment, and O’Reilly has been no different. A big contributor to O’Reilly’s continued success during these unprecedented times has been its live virtual training courses. This year, more than 900,000 users have registered for live events through O’Reilly online learning—a 96% increase from last year. This functionality also allowed O’Reilly to introduce its Superstream Series, a new lineup of virtual conferences featuring expert speakers delivering talks and training sessions on the most important topics and emerging trends in technology.
So what are the trends driving this uptick in learning? Companies are increasingly interested in understanding how to successfully adjust to remote work and effectively manage time. And individual O’Reilly members are looking to build and expand on their technical skills in everything from software architecture and microservices to AI and programming languages. But which topics are the brightest minds in technology most focused on? We’ve compiled the top 20 live online training courses of 2020 to shed some light on what those in the know want to know.
Top 20 live online training courses of 2020
For a more in-depth analysis of the hot technology topics of 2020, based on data from O’Reilly online learning, stay tuned for our upcoming report, Wrapping Up 2020 (and What to Expect for 2021): Trends on O’Reilly online learning.
It has long seemed to me that functional programming is, essentially, programming viewed as mathematics. Many ideas in functional programming came from Alonzo Church’s Lambda Calculus, which significantly predates anything that looks remotely like a modern computer. Though the actual history of computing runs differently: in the early days of computing, Von Neumann’s ideas were more important than Church’s, and had a tremendous influence on the design of early computers—an influence that continues to the present. Von Neumann’s thinking was essentially imperative: a program is a list of commands that run on a machine designed to execute those commands.
So, what does it mean to say that functional programming is programming “viewed as mathematics”? Von Neumann was a “mathematician,” and programming of all kinds found its first home in Mathematics departments. So, if functional programming is mathematical, what does that mean? What kind of math?
I’m not thinking of any specific branch of mathematics. Yes, the Lambda Calculus has significant ties to set theory, logic, category theory, and many other branches of mathematics. But let’s start with grade school mathematics and assignment statements; they’re basic to any programming language. We’re all familiar with code like this:
i = i+1 # or, more simply i += 1 # or, even more simply i++ # C, Java, but not Python or RubyMathematically, this is nonsense. An equation is a statement about a relationship that holds true. i can equal i; it can’t equal i+1. And while i++ and i+=1 no longer look like equations, they are equally nonsensical; once you’ve said that i equals something, you can’t say it equals something else. “Variables” don’t change values; they’re immutable.
Immutability is one of the most important principles of functional programming. Once you’ve defined a variable, you can’t change it. (You can create a new one in a different function scope, but that’s a different matter.) Variables, in functional programming, are invariant; and that’s important. You may be wondering “what about loops? How can I write a for loop?” Not only do you have to do without index variables, you can’t modify any of the variables in the loop body.
Setting aside the (solvable) problem of iteration, there’s no reason you can’t write code in (almost) any non-functional language that has this same effect. Just declare all your variables final or const. In the long run, functional programming is more about a specific kind of discipline than about language features. Programming languages can enforce certain rules, but in just about any modern language it’s possible to follow those rules without language support.
Another important principle of functional programming is that functions are “first class entities.” That is, there are minimal restrictions about where you can use a function. You can also have functions without names, often called “lambdas” (which refers directly to the Lambda Calculus, in which functions were unnamed). In Python, you can write code like this:
data.sort(key=lambda r: r[COLUMN])The “key” is an anonymous function that returns a specific column of an array; that function is then used for sorting. Personally, I’m not overly fond of “anonymous functions”; it’s often clearer to write the anonymous function as a regular, named function. So I might write this:
def sortbycolumn(r): return r[COLUMN] data.sort(k=sortbycolumn)The ability to use functions as arguments to functions gives you a very nice way to implement the “strategy pattern”:
def squareit(x): return x*x def cubeit(x): return x*x*x def rootit(x): import math; return math.sqrt(x) def do_something(strategy, x) ... do_something(cubeit, 42) weird = lambda x : cubeit(rootit(x)) do_something(weird, 42)I often get the sense that all programmers really want from functional programming is first-class functions and lambdas. Lambdas were added to Python very early on (1.0) but didn’t reach Java until Java 8.
Another consequence of thinking mathematically (and possibly a more important one) is that functions can’t have side-effects and, given the same arguments, will always return the same value. If a mathematician (or a high school trig student) writes
y = sin(x)they don’t have to deal with the possibility that sin(x) sets some global variable to 42, or will return a different value every time it’s called. That just can’t happen; in math, the idea of a “side-effect” is meaningless. All the information that sin(x) provides is encapsulated in the return value. In most programming languages, side-effects happen all too easily, and in some, they’re almost an obsession. Again, creating functions that have no side-effects is a matter of exercising discipline. A programming language can enforce this rule, but you can follow it whether or not your language makes you do it. We don’t have cartoon devils looking over our shoulders saying “Go ahead; make a side effect. No one will notice.”
Functional languages vary the degree to which they enforce the lack of side-effects. If you’re a purist, anything that interacts with the real world is a side-effect. Printing a document? Changing a row in a database? Displaying a value on the user’s screen? Those are all side-effects (they aren’t completely encapsulated in the value returned by the function), and they have to be “hidden” using a mechanism like monads in Haskell. And that’s the point at which many programmers get confused and throw up their hands in despair. (I’ll only point you to Real World Haskell.) In both Java and Python, lambda functions can have side-effects, which means that, strictly speaking, they aren’t really “functional.” Guido van Rossum’s discussion of the addition of Lambdas to Python is worth reading; among other things, he says “I have never considered Python to be heavily influenced by functional languages, no matter what people say or think.”
Streams are often associated with functional languages; they’re essentially long (perhaps infinite) lists that are evaluated lazily—meaning that elements of the string are only evaluated as they’re needed. Maps apply a function to every element of a list, returning a new list—and that includes streams, which (for these purposes) are specialized lists. That’s an incredibly useful feature; it’s a great way to write a loop without having to write a loop—and without even knowing how much data you have. You can also create “filters” that choose whether to pass any element of the stream to the output, and you can chain maps and filters together. If you think this sounds like a Unix pipeline, you’re right. Streams, maps, filters, and the act of chaining them together really have as much to do with the Unix shell as they do with functional languages.
Another way to avoid writing loops is to use “comprehensions,” a feature of Python. It’s easy to get very fond of list comprehensions; they’re compact, they eliminate off-by-one errors, and they’re very flexible. Although comprehensions look like a compact notation for a traditional loop, they really come from set theory—and their closest computational “relatives” are to be found in relational databases, rather than functional programming. Here’s a comprehension that applies a function to every element of a list:
# pythonic examples. First, list comprehension newlist = [ somefunction(thing) for thing in things ]The most general way to avoid traditional loops is to use recursion: a function that calls itself. Here’s the recursive equivalent to the previous comprehension:
def iterate(t, l) : if len(t) == 0 : return l # stop when all elements are done return iterate(t[1:],l + [somefunction(t[0])]) # process remainderRecursion is a mainstay of functional languages: you don’t have indices being modified, and you’re not even modifying the resulting list (assuming that append doesn’t count as modification).
However, recursion has its own problems. It’s hard to wrap your mind around recursion; you still need to do a lot of your own bookkeeping (in this case, passing in a vector so a result can be returned); and except in one (common) special case, called “tail recursion,” it can be a performance nightmare.
I started by saying that functional programming was programming considered as “math,” and that’s at least partially correct. But is that claim useful? There are many branches of mathematics that map onto programming concepts in different ways. Functional programming only represents one of them. If you’re a topologist, you may well like graph databases. But discussing which branch of mathematics corresponds to which programming practices isn’t really helpful. Remembering high school algebra may help when thinking about immutability, statelessness, and the absence of side-effects; but most programmers will never study the real mathematical origins of functional programing. Lambdas are great; functions as arguments in method calls is great; even recursion is (sometimes) great; but we’re fooling ourselves if we think programmers are going to start using Java as if it were Haskell. But that’s OK; for Java programmers, the value of Lambdas isn’t some mathematical notion of “functional,” but in providing a huge improvement over anonymous inner classes. The tools to be functional are there, should you choose to use them.
In college, I learned that engineering was about making tradeoffs. Since then, I’ve heard very few programmers talk about tradeoffs—but those tradeoffs are still central to good engineering. And while engineering uses a lot of mathematics, engineering isn’t mathematics, in part because mathematics doesn’t deal in tradeoffs. Using “mathematics” as a way to think about a particular style of disciplined coding maybe be useful, particularly if that discipline leads to fewer bugs. It’s also useful to use the tools of mathematics to make good tradeoffs between rigor, performance, and practicality—which may lead you in an entirely different direction. Be as functional as you need to (but no more).
This month’s collection of interesting articles that point to important trends is dominated by AI. That’s not surprising; AI has probably been the biggest single category all year. But its dominance over other topics seems to be increasing. That’s partly because there’s more research into why AI fails; partly because we’re beginning to see AI in embedded systems, ranging from giant gas and oil wells to the tiny devices that Pete Warden is working with.
Artificial Intelligence
If software is such stuff as dreams are made on, how do we talk about nightmares? Software is not the tangible, kickable stuff our senses are tuned to, so we draw on metaphor to communicate and reason about it.
The 1970s offered up spaghetti code to describe the tangle of unstructured control flow. This has inspired many software-as-pasta descriptions, from lasagne for layered architectures to ravioli for—pick a decade—objects, components, modules, services, and microservices. Beyond its disordered arrangement, however, spaghetti has little to offer us as a metaphor. It doesn’t provide us with a useful mental model for talking about code, and has far too many positive associations. If you love both ravioli and spaghetti, it’s not obvious that one of these is worse for your software architecture than the other.
A metaphor is a mapping that we use to describe one thing in terms of another—sometimes because we want to show something familiar from an unfamiliar angle, as in poetry, but sometimes because we want to show something unfamiliar or abstract in a more familiar light, as in software. To be considered good, a metaphor has to offer a number of points of useful correspondence with what is being described. Pasta doesn’t quite do this.
Another quality of a good metaphor is that it should not have too many obvious points of conflict. It will never map its target perfectly—a metaphor is a conceit not an identity—but a good metaphor is one whose key qualities don’t contradict the very thing we are trying to say, whose points of difference don’t distract from the mental model being shared.
We sometimes talk about code decay and software rot. These terms give a sense of degradation over time. This seems accurate and relatable. They also suggest a response: cleaning (we brush our teeth to reduce the chance of tooth decay) or treatment (we treat wood to avoid it rotting). So far so good… but the problem with these metaphors is they refer to natural processes that happen independently of anything we do. If you don’t brush your teeth, you will experience decay. If you don’t touch code, it doesn’t intrinsically degrade.
The third quality of a metaphor that makes it effective is familiarity to its audience. Explaining something unfamiliar in terms of something else that is also unfamiliar can be a long road to travel a short distance (or to end up where you started). If you are familiar with the concept of entropy in statistical mechanics, with the second law of thermodynamics, and with the idea that work is needed to reduce entropy and increase order in a system, then software entropy might strike you as a descriptive metaphor—and not simply because the word work transfers happily from the world of thermodynamics to the day-to-day experience of developers. If, however, these concepts are not accessible and require explanation, then, regardless of its other merits, software entropy may not be the best way to talk about accidental complexity in code.
Perhaps the most popular metaphor in use is based on financial debt, originating with Ward Cunningham in 1992. As Martin Fowler described in 2003:
Technical Debt is a wonderful metaphor developed by Ward Cunningham to help us think about this problem. In this metaphor, doing things the quick and dirty way sets us up with a technical debt, which is similar to a financial debt. Like a financial debt, the technical debt incurs interest payments, which come in the form of the extra effort that we have to do in future development because of the quick and dirty design choice.
When we look at technical debt, we see a metaphor that checks all three boxes: it has a number of useful points of correspondence; the points of difference don’t overwhelm the core idea; it is familiar. Furthermore, it brings with it a useful working vocabulary. For example, consider what the following debt-related words suggest to you in a software context: repayment, consolidation, creditworthiness, write-off, borrowing.
Although we know that by definition no metaphor is perfect, there are two common ways in which the metaphor is misapplied: assuming technical debt is necessarily something bad; equating technical debt with a financial debt value. The emphasis of the former is misaligned and the latter is a category error.
If we are relying on the common experience of our audience, financial debt is almost always thought of as a burden. If we take that together with the common experience of code quality and nudge it with leading descriptions such as “quick and dirty,” it is easy to see how in everyday use technical debt has become synonymous with poor code and poor practice. We are, however, drawing too heavily on the wrong connotation.
Rather than reckless debt, such as from gambling, we should be thinking more along the lines of prudent debt, such as a mortgage. A mortgage should be offered based on our credit history and our ability to pay and, in return, we are able to buy a house that might otherwise have been beyond our reach. Similarly, Ward’s original motivation was to highlight how debt in code can be used for competitive advantage:
Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite.
This comes with a clear caveat and implication: a debt is a loan. A debt is for repayment, not for running up:
The danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt. Entire engineering organizations can be brought to a stand-still under the debt load of an unconsolidated implementation.
As in the real world, how we run up debt and how we manage it turn out to be more complex than the simplicity of our best intentions. There are teams that make time-saving decisions wisely, revisiting and addressing them later in a timely manner. But in most cases where debt is incurred, discussed, and lamented, codebases reflect the firefight of different priorities, skills, and people. It’s still technical debt, but it lacks the prudence and intention of Ward’s original purpose.
There are also teams and tools that embrace the debt metaphor so tightly that they forget it’s a metaphor. They treat it literally and numerically, converting code quality into a currency value on a spreadsheet or dashboard. The consequences of this thinko range from being a harmless fiction largely ignored by developers and managers to a more damaging numerology that, even though it’s well intentioned, can mislead development effort.
If we’re going to quantify it, what is it we’re quantifying? Do we list off code smells? What is the debt value of a code smell? Is it constant per kind of code smell? For example, is duplicate code characterised by a single cost? And are code smells independent of one another? Consider that, for example, duplication is sometimes used to reduce coupling, so the debit becomes a credit in that context. We can conclude that a code smell is not an isolated thing with a single look-up debt value, so this is clearly a more complex problem dependent on many factors. As a multivariable problem, what does it depend on? And how? And how do we know? And what would the value or—more likely—value distribution reflect? The cost of fixing? Or, more honestly, an estimate of the cost of fixing?
But even if we are somehow able to conjure a number out of this ever-growing list of considerations—and even if that number has some relation to observed reality—we have put a number to the wrong quantity. We have, in fact, missed the whole point of the metaphor.
Technical debt is not the cost of repaying the debt: it is the cost of owning the debt. These are not the same. That is the message of the technical debt metaphor: it is not simply a measure of the specific work needed to repay the debt; it is the additional time and effort added to all past, present, and future work that comes from having the debt in the first place.
By taking the metaphor literally, we have robbed it of its value. Its value is to offer us a figure of speech not of currency, a mental model for talking and reasoning about qualities of our code that are not simply stated in code. No matter how well meant, pushing any metaphor beyond its applicability leads to metaphor shear. It is, after all, metaphor and not identity.
The programming world used to be split into functional languages, object-oriented languages, and everything else (mostly procedural languages). One “was” a functional programmer (at least as a hobby) writing Lisp, Haskell, or Erlang; or one “was” an OO programmer (at least professionally), writing code in Java or C++. (One never called oneself a “procedural programmer”; when these names escaped from academia in the 1990s, calling yourself a “procedural programmer” would be akin to wearing wide ties and bell-bottom jeans.)
But this world has been changing. Over the past two decades, we’ve seen the rise of hybrid programming languages that combine both functional and object-oriented features. Some of these languages (like Scala) were multi-paradigm from the beginning. Others, like Python (in the transition from Python 2 to 3) or Java (with the introduction of Lambdas in Java 8) are object-oriented or procedural languages to which functional features were added. Although we think of C++ as an object-oriented language, it has also been multi-paradigm from the beginning. It started with C, a procedural language, and added object-oriented features. Later, beginning with the Standard Template Library, C++ was influenced by many ideas from Scheme, a descendant of LISP. JavaScript was also heavily influenced by Scheme, and popularized the idea of anonymous functions and functions as first class objects. And JavaScript was object-oriented from the start, with a prototype-based object model and syntax (though not semantics) that gradually evolved to become similar to Java’s.
We’ve also seen the rise of languages combining static and dynamic typing (TypeScript in the JavaScript world; the addition of optional type hinting in Python 3.5; Rust has some limited dynamic typing features). Typing is another dimension in paradigm space. Dynamic typing leads to languages that make programming fun and where it’s easy to be productive, while strict typing makes it significantly easier to build, understand, and debug large systems. It’s always been easy to find people praising dynamic languages, but, except for a few years in the late 00s, the dynamic-static paradigmatic hasn’t attracted as much attention.
Why do we still see holy wars between advocates of functional and object-oriented programming? That strikes me as a huge missed opportunity. What might “multi-paradigm programming” mean? What would it mean to reject purity and use whatever set of features provide the best solution in any given context? Most significant software is substantial enough that it certainly has components where an object-oriented paradigm makes more sense, and components where a functional paradigm is superior. For example, look at a “functional” feature like recursion. There are certainly algorithms that make much more sense recursively (Towers of Hanoi, or printing a sorted binary tree in order); there are algorithms where it doesn’t make much of a difference whether you use loops or recursion (whenever tail recursion optimizations will work); and there are certainly cases where recursion will be slow and memory-hungry. How many programmers know which solution is best in any situation?
These are the sort of questions we need to start asking. Design patterns have been associated with object-oriented programming from the beginning. What kinds of design patterns make sense in a multi-paradigm world? Remember that design patterns aren’t “invented”; they’re observed, they’re solutions to problems that show up again and again, and that should become part of your repertoire. It’s unfortunate that functional programmers tend not to talk about design patterns; when you realize that patterns are observed solutions, statements like “patterns aren’t needed in functional languages” cease to make sense. Functional programmers certainly solve problems, and certainly see the same solutions show up repeatedly. We shouldn’t expect those problems and solutions to be the same problems and solutions that OO programmers observe. What patterns yield the best of both paradigms? What patterns might help to determine which approach is most appropriate in a given situation?
Programming languages represent ways of thinking about problems. Over the years, the paradigms have multiplied, along with the problems we’re interested in solving. We now talk about event-driven programming, and many software systems are event-driven, at least on the front end. Metaprogramming was popularized by JUnit, the first widely used tool to rely on this feature that’s more often associated with functional languages; since then, several drastically different versions of metaprogramming have made new things possible in Java, Ruby, and other languages.
We’ve never really addressed the problem of how to make these paradigms play well together; so far, languages that support multiple paradigms have left it to the programmers to figure out how to use them. But simply mixing paradigms ad hoc probably isn’t the ideal way to build large systems–and we’re now building software at scales and speeds that were hard to imagine only a few years ago. Our tools have improved; now we need to learn how to use them well. And that will inevitably involve blending paradigms that we’ve long viewed as distinct, or even in conflict.
Thanks to Kevlin Henney for ideas and suggestions!
Nathan Cluff: Space Night Talk Show
Description:
PLUG is hosting it's first ever talk show. Tune in as Hans asks guest Nathan Cluff about FLOSS in space and other geeky topics.
der.hans will interview Nathan Cluff for PLUG's first ever talk show as they talk about throwing things at other planets, our first spacecopter and whatever else comes up
First Space Night video: https://www.youtube.com/watch?v=bnxge96YO3A
Perseverence: https://mars.nasa.gov/mars2020/
Spacecopter: https://mars.nasa.gov/technology/helicopter/
Planetary Society: https://www.Planetary.org/
NASA: https://www.NASA.gov/
Mastcam-Z: https://mastcamz.asu.edu/
About Nathan:
Nathan is the Lead Systems Administrator for the Mastcam and Mastcam-Z cameras on the Mars Science Laboratory and Mars 2020 rovers in addition to supporting operations for various other missions such as the Luna Polar Hydrogen Mapper (LunaH-map) mission. Nathan has been involved in various Linux administrative positions for the last 18 years and has been in the School of Earth and Space Exploration at ASU for the last 4 years.