How Python programmers can uncontroversially approach build, dependency, and packaging tooling (+ a note on Zig)

A few years back, I published The Elements of Python Style, a popular Python code style guide. Since publishing it, friends of mine in the Python community have wondered if I might consider adding a section about package installation, dependency management, and other similar “standard tooling” recommendations.

This is a reasonable request, since Python lacks much in the way of standard tooling. I took a stab at this in a pull request here, but then abandoned my attempt. The length of this “section” started to approach the length of the overall style guide itself! So, I gave up on that. I decided to turn the section into this blog post here, instead. Then, I’ll share one thought about how emerging programming language communities, such as Zig’s, could learn from the Python experience.

On “Standard” Tools

There’s a zoo of tooling options out there, and no “standard” Python tooling beyond the python executable, and, perhaps, pip (for installing packages, which was semi-formalized in Python 3.x with PEP 453 and PEP 508). Here, we’ll discuss an opinionated (yet uncontroversial) approach to “standard” tooling with Python.

Continue reading How Python programmers can uncontroversially approach build, dependency, and packaging tooling (+ a note on Zig)

Turning n/2 + 1

When I turned 27, I wrote the following in my birthday post:

I don’t need stuff. I just need time. Of course, that’s the bittersweet part of one’s birthday. That even as you come to realize the importance of time, the day acts as a reminder of how our time on this earth is limited. 1 day passes, and only n-1 left to make a difference.

The average life expectancy for a US male born in 1984 is 75. I just turned 38 today. Therefore, it’s fair to say, I just turned n/2 + 1.

That is perhaps a bit too fatalistic and reductive. The number n is not guaranteed to be 75. “Don’t be so morbid!” someone might exclaim to me. “After all, many people live to 80, 90, even 100. And medicine improves all the time.”

Well, yes, this is true. But, it’s also likely — and increasingly so — that I might die any minute. Freak accidents, a late-discovered birth defect. Or, just losing the medical lottery in middle age. So, I return to the wisdom of my youth: “I don’t need stuff. I just need time.”

But, toward what end? That has been the interesting riddle of approaching n/2 with the following undeniable privileges:

  • good health
  • professional satisfaction
  • financial security
  • confidence in my irreversible life choices

Many approach this same milestone with none of the above, and many would love for any one of them to be squared away.

The honest truth is, I find myself heavy with the weight of these privileges. History is, as Harold Bloom once put it when describing literature, “a conflict between past genius and present aspiration, in which the prize is […] survival.” Here, he was referring to well-crafted stories. “Survival” meant their perpetuation through the ages via timeless literary relevance, something he referred to as “canonical inclusion”.

But what of my field, software?

Continue reading Turning n/2 + 1

Parse.ly, Automattic: the long view

In 2009, I quit my first programming job after college to work on a startup. That startup eventually became Parse.ly. I’ve written about Parse.ly’s startup beginnings and evolution elsewhere on this blog, including:

It is 2021 now, more than 12 years since the company’s original founding. And much has changed.

Parse.ly “the startup” was a rollercoaster, like all startups are, but it was, ultimately, a success. In 2009, we were a tiny 3-person team hacking away on prototypes at a startup accelarator in Philadelphia. In 2012, Parse.ly had its first handful of customers for the content analytics system that became our core product, and shifted into enterprise SaaS as a business model. In 2013, we raised “Series A” style financing to pursue the ambition of defining and leading the content analytics category.

By 2017, it was clear that Parse.ly had done just that: we had built a valuable product in the market and a beautiful SaaS business model, where our R&D efforts were aligned with our customer needs. There was only a question of total market size. As a result, in 2018 we shifted our efforts to expanding Parse.ly’s market — acting as a content measurement layer not just for major media and entertainment companies, but for all content management systems and all content-rich websites.

By the end of 2019 and heading into early 2020, it was clear that Parse.ly was succeeding in this new vision, and was going to be a SaaS company “in it for the long-term”, serving our customers for years to come.

Continue reading Parse.ly, Automattic: the long view

Managing software teams: the definitive reading list

Frederick Brooks once wrote:

The programmer, like the poet, works only slightly removed from pure thought-stuff. He builds castles in the air, from air, creating by exertion of the imagination.

In his classic essay, “No Silver Bullet”, he also wrote about software’s “essential” complexity:

The complexity of software is an essential property […] Hence, descriptions of a software entity that abstract away its complexity often abstract away its essence. For three centuries, mathematics and the physical sciences made great strides by constructing simplified models of complex phenomena, deriving properties from the models, and verifying those properties by experiment. This paradigm worked because the complexities ignored in the models were not the essential properties of the phenomena. It does not work when the complexities are the essence.

It’s therefore no surprise that once a team develops expertise in a technical domain and starts to evolve a product from that foundation, there is still a huge heap of complexity left over.

This is made worse on bigger problems where more people are involved, thanks to Brooks’s Law. In addition to the software’s essential complexity, you also need to navigate the built-in complexity of human communication, and the associated combinatorial explosion of information pathways on growing teams.

Modern software management practices have thus evolved two distinct skillsets for navigating the problems of team coordination around complex software delivery. These two areas are product management and software engineering management.

Product management centers around areas like market positioning, product strategy, and customer-focused iterative development. The product manager, working closely with the engineers, determines the “what”, aligns the team around the “why”, and acts as a liaison to users and the wider market.

Software engineering management focuses on the practice of coordinating teams of programmers in the delivery of high-quality shipped software, often leveraging programming languages, tools, frameworks, cloud services, and lots of open source technology. Pithily, this is “the how”, as well as the art of making informed engineering tradeoffs, e.g. as relates to time-to-market, performance, quality, and cost.

This post will cover some of my favorite reading materials spanning product management and software engineering management, as disciplines. A preview of some of the titles is here:

I have curated these resources carefully, and I have recommended them at various times to my own product managers and my own software engineering managers over the years. I hope you find this a useful starting point for your own study.

Continue reading Managing software teams: the definitive reading list

New essay: The case for a vote to restore jobs and health

It’s not a “left” or a “right” thing. It’s about jobs and health. If you study the data, you’ll learn this is what’s at stake in 2020.

We can restore our country’s health. We can rebuild our economy. We can do both of these things.

Continue reading New essay: The case for a vote to restore jobs and health

Learning about babashka (bb), a minimalist Clojure for building CLI tools

A few years back, I wrote Clojonic: Pythonic Clojure, which compares Clojure to Python, and concluded:

My exploration of Clojure so far has made me realize that the languages share surprisingly more in common than I originally thought as an outside observer. Indeed, I think Clojure may be the most “Pythonic” language running on the JVM today (short of Jython, of course).

That said, as that article discussed, Clojure is a very different language than Python. As Rich Hickey, the creator of Clojure, put it in his “A History of Clojure”:

Most developers come to Clojure from Java, JavaScript, Python, Ruby and other OO languages. [… T]he most significant […] problem  [in adopting Clojure] is learning functional programming. Clojure is not multiparadigm, it is FP or nothing. None of the imperative techniques they are used to are available. That said, the language is small and the data structure set evident. Clojure has a reputation for being opinionated, opinionated languages being those that somewhat force a particular development style or strategy, which I will graciously accept as meaning the idioms are clear, and somewhat inescapable.

There is one area in which Clojure and Python seem to have a gulf between them, for a seemingly minor (but, in practice, major) technical reason. Clojure, being a JVM language, inherits the JVM’s slow start-up time, especially for short-lived scripts, as is common for UNIX CLI tools and scripts.

As a result, though Clojure is a relatively popular general purpose programming language — and, indeed, one of the most popular dynamic functional programming languages in existence — it is still notably unpopular for writing quick scripts and commonly-used CLI tools. But, in theory, this needn’t be the case!

Continue reading Learning about babashka (bb), a minimalist Clojure for building CLI tools

Python 3 is here and the sky is not falling

James Bennett, a long-time Python developer, blogger, and contributor to Django, recently wrote a nice post about the “end” of Python 2.x, entitled “Variations on the Death of Python 2.” It’s a great read for anyone who, like me, has been in the Python community a long time.

I’ve been a Python user since the early 2.x days, first discovering Python in a print copy of Linux Journal in the year 2000, where a well-known open source developer and advocate described his transition from Perl to Python. He wrote:

I was generating working code nearly as fast as I could type. When I realized this, I was quite startled.

An important measure of effort in coding is the frequency with which you write something that doesn’t actually match your mental representation of the problem, and have to backtrack on realizing that what you just typed won’t actually tell the language to do what you’re thinking. An important measure of good language design is how rapidly the percentage of missteps of this kind falls as you gain experience with the language. When you’re writing working code nearly as fast as you can type and your misstep rate is near zero, it generally means you’ve achieved mastery of the language.

But that didn’t make sense, because it was still day one and I was regularly pausing to look up new language and library features!

This was my first clue that, in Python, I was actually dealing with an exceptionally good design.

Python’s wonderful design as a language has always been a source of inspiration for me. I even wrote “The Elements of Python Style”, as an ode to how good Python code, to me, felt like good written prose. And, of course, many of my personal and professional projects are proudly Python Powered.

python-powered

Thus, I was always a little worried about the Python 2 to 3 transition. I was concerned that this one big risk, taken on by the core team, could imperil the entire language, and thus the entire community. Perl 5 had embarked on a language schism toward Perl 6 (now Raku), and many believe that both communities (Perl 5 and Raku) became weaker as a result.

But, here we are in 2020, and Python 2 is EOL, and Python 3 is here to stay. A lot of the internet debates about Python 2 vs Python 3 (like this flame war on lobste.rs) now seem to boil down to this question: was Python 3 a good idea, in retrospect?

Continue reading Python 3 is here and the sky is not falling

Best remote work equipment in 2020

If you’re working on a fully distributed team, partially remote team, or even just working from home occasionally, this is a selection of low-cost equipment you can use to get your home office setup to a “professional” level.

All of this equipment has been tested extensively to work on:

  • Google Hangouts
  • Google Meet
  • Zoom Video Conferencing
  • Microsoft Teams
  • Skype
  • Slack
  • FaceTime (on OSX)
  • Alternative video tools, like WhereBy, Loom, or Jitsi Meet

And, all of this equipment has further been tested on every operating system:

  • Mac OS X (including Catalina)
  • Linux (including Ubuntu 18.04 and beyond)
  • Windows 10

All of the recommendations here also work without special drivers or software.

The main reason for the compatibility is the use of standard USB 2.0 interfaces, which are really the best way to go for the equipment to work well.

The best remote work webcam: Logitech C925e

You should always prefer an external webcam & mic combo to your built-in webcam and mic on your laptop or desktop machine.

The Logitech C920+ models are extremely good and reliable on every operating system.

I recommend the Logitech C925e. This model has a great built-in stereo mic and 720p / 1080p video. It also supports hardware acceleration (aka h.264 encoding) on many platforms and with many video conference tools, which reduces the load on your computer’s CPU (and keeps your computer running cooler and using less battery). This particular model also features a simple built-in privacy shutter, excellent monitor mount, and a long USB cable.

logitech-c925e

If you can’t find the C925e, your best alternative is the Logitech C920. This is the consumer version of the same hardware — the webcam looks a little different but is also a 720p / 1080p HD cam with built-in mics. It doesn’t have the privacy shutter, however.

Continue reading Best remote work equipment in 2020

Chat with me for 30 minutes about distributed team management

Have you been trying to figure out this new world order with regard to work-from-home (WFH), remote work, distributed teams, and the like? I’ve opened up my calendar for 30-minute chats. You can schedule them with me here:

https://calendly.com/amontalenti/distributedUpdate: after over a year, I’ve now shut down this link on May 27, 2021

If you want to read up on distributed teams, here are some past posts from my blog and the Parse.ly blog on the subject. Open up these links and skim to get a sense of my past writings.

Continue reading Chat with me for 30 minutes about distributed team management

Work is a Queue of Queues

Do you ever get that feeling like no matter how hard you work, you just can’t keep up?

This isn’t a problem uniquely faced by modern knowledge workers. It’s also a characteristic of certain software systems. This state — of being perpetually behind on intended work-in-progress — can fall naturally out of the data structures used to design a software system. Perhaps by learning something about these data structures, we can learn something about the nature of work itself.

Let’s start with the basics. In computer science, one of the most essential data structures is the stack. Here’s the definition from Wikipedia:

… a stack is a data type that serves as a collection of elements, with two principal operations: (1) “push”, which adds an element to the collection; and (2) “pop”, which removes the most recently added element that was not yet removed. The order in which elements come off [is known as] LIFO, [or last in, first out]. Additionally, a “peek” operation may give access to the top without modifying the stack.

From here on out, we’ll use the computer science (mathematical) function call notation, f(), whenever we reference one of the operations supported by a given data structure. So, for example, to refer to the “push” operation described above, we’ll notate it as push().

I remember learning the definition of a stack in college and being a little surprised at “LIFO” behavior. That is, if you push() three items onto a stack — 1, 2, and 3 — when you pop() the stack, you’ll get the last item you added — in this case, 3. This means the last item, 3, is the first one pop()‘ed off the stack. Put another way, the first item you put on the stack, 1, only gets processed once you pop() all the other items — 3, 2 — off the stack, and then pop() once more to (finally) remove item 1.

Practically speaking, this seems like a “frenetic” or “unfair” way to do work — you’re basically saying that the last item always gets first service, and so, if items are push()’ed onto the stack faster than they are pop()’ed, some items will never be serviced (like poor item 1, above).

Continue reading Work is a Queue of Queues