Leadership, Failure, and Erlang

I’ve been reflecting on leadership recently and recalled an idea that struck me during my time leading organizations in the Texas A&M University Memorial Student Center Student Programs Office. In organizations that turned over leadership each year, the leadership followed a predictable pattern of flipping from strong leadership to weak leadership, then from weak to strong, as if on a loop. I developed the idea that in subsequent generations, strong leaders beget weak leaders, and weak leaders beget strong leaders. Based on this observation and idea, I developed a practice of being intentionally weak in certain circumstances in order to develop leadership in those I led.

Before we continue, let me define terms as I’m using them:

  • strong – proactive, decisive, quick to correct, and minimize risk of failure
  • weak – passive, indecisive, leaves a gap that needs to be filled, risk of failure

When I’ve searched for these terms online, I typically see something that looks more like a contrast of “good” versus “bad” leaders, for varying definitions of “good” and “bad.” When I use “strong” and “weak,” I assume both exhibit “good” leadership qualities, for whatever definition you wish to use for “good.”

The practice I tried to develop while at Texas A&M was to identify and intentionally give space for others to step up and grow as leaders. I provided backup to minimize the impact of failure and follow-up with a retrospective to learn and grow. This was moderately successful, in large part because I had a lot of room to learn and grow myself. Thankfully, the advisors at Texas A&M were wonderful and provided the same kind of environment to grow as leaders.

I’ve found this approach continues to work well throughout my career, though I have forgotten to use it at times. I recently started exploring new (to me) programming languages and came across Gleam, a typed, functional programming language for the Erlang runtime. Erlang is known for its resilience and fault tolerance, yet it achieves this by means of a “Let it Crash” philosophy. This seems counterintuitive. Success through failure? In Programming Erlang, Joe Armstrong notes that the difference is in expecting failure, one can focus instead on planning how to identify and recover.

My great concern is not whether you have failed, but whether you are content with your failure. - Abraham Lincoln

There is a correlation between the “Let it Crash” philosophy and growing leadership abilities. We tend to think of success as good and failure as bad, but failure is only bad if it does not translate into a learning opportunity. Successful and unsuccessful outcomes can both be positive outcomes, but they need to be planned. Planning involves identifying opportunities for each person you want to grow in leadership, assessing risk, and providing for contingencies.

You may be wondering how this is different than coaching. I see the difference in coaching is an explicitly communicated opportunity, whereas what I propose above is not explicit. You have to make room for others to identify and then pursue the opportunity on their own. Coaching should certainly be part of the process, but it falls into the “strong” leadership category.

Leaving room for others is challenging. It means waiting on making improvements. You may get only a partial solution. However, your people will struggle to make it to the next step without opportunities. I’ve enjoyed reflecting on and rediscovering this approach. I’d love to know how others approach leadership development in their people. Let me know in the comments.

Azure Functions with Swift

I’ve been a bit busy lately with several projects, but I’ve tried to carve out time to continue learning. As I’ve been writing some Azure Functions for work projects, I was looking to leverage see how easy it would be to use the Custom Handlers preview to add support for Swift. Turns out Saleh Albuga already built a tool for building and deploying Swift Azure Functions called swiftfunc! The only downside is this tool currently only works on macOS.

Undaunted, I decided to try a different approach. While looking for OSS Swift compilers, I happened upon RemObjects Elements Compiler. I was surprised I had not heard of them before. Their compiler platform is worth investigating, as it supports many languages, even within one project! However, I was interested in Swift, and their Silver compiler is kept very close to the latest Swift spec, including extensions for things like async/await. As the Elements compiler can be used to build apps for mobile, .NET, Java, WebAssembly, and more platforms, I wondered whether I could use Silver to build a Swift Azure Function against the .NET libraries. With a little help from Marc Hoffman, the answer is a resounding YES!

Continue reading
Aside

Loose Coupling and High Cohesion in Teams

Most software engineers are familiar with the OK design principle of loose coupling and high cohesion from the Gang of Four Design Patterns book. I have been reflecting on my experiences leading teams while reading Leading with Honor by Lee Ellis and realized a correlation of this same principle for high performing teams.

Highly coupled teams are like an assembly line. Everyone is specialized, and everything moves along well until something breaks. In a team with low cohesion, the only ones who can fix the break are those responsible for the area of the assembly line that broke, which means most of the team is not working while the problem is identified and fixed. If a team has high cohesion, then some members can switch roles to help out with the area that is broken, but the rest of the assembly line is still stopped.

Highly cohesive teams are those that have high collaboration with one another and typically are composed of members with different specializations. Everyone can contribute to any part of the work. If the team is highly coupled, however, then the loss of one team member or the need for that team member on any given task causes the rest of the team to grind to a halt while waiting on that team member to free up. A loosely coupled team can continue working on multiple tasks concurrently with no hard dependencies on any one person.

Much like in software, my experience suggests highly cohesive but loosely coupled teams are far more efficient and effective at achieving their objectives. I’m curious whether you’ve had a similar or different experience, and I’m interested in any research on this topic. Please share in the comments.

Custom Site Generation with Azure Static Web Apps

While fooling around with Azure Static Web Apps — which went into public preview today — I found a trick to working with any front-end build tool, not just npm install && npm run build. In this post, I’ll work through adding a new build step and using a custom static site generator. To keep things interesting, I’ll use an F# script to generate the site.

Continue reading

My Take on FAKE in 2020

I’ve been using FAKE since roughly 2009 when Steffen Forkmann first introduced it. I’ve used it for OSS and work projects, builds and deployments, and even committed features to it. I think FAKE is a fantastic tool, and I loved the changes that came in FAKE 5.

However, I’ve been reconsidering my use of FAKE as a default build scripting tool in smaller projects and wanted to write up my reasons for switching to dotnet CLI builds for new projects and migrating some OSS projects to do the same.

Continue reading
Aside

Blazor Server Tip: Sometimes you need Task.Delay(1)

I recently encountered an issue with server-side Blazor in which the UI didn’t refresh after calling StateHasChanged. The UI refreshed just fine until I added about 30k more records to a database table, which caused a query to take a bit longer to run. I filed an issue here.

I debugged through the issue by trying different things like using an in-memory data store, re-checking against a smaller data set, and wrapping StateHasChanged to make sure it was actually called. Everything was working as expected with the in-memory store and smaller data set, and StateHasChanged was always called. However, with the larger data set, the components’ lifecycle methods were not called.

I finally stumbled upon a solution using an old JavaScript trick: adding await Task.Delay(1); This magically worked. If you run into something similar, you may try await Task.Delay(1); and see whether that resolves the issue.

Revisiting Microsoft Forms: WinForms

This is a series of posts on older Microsoft forms technologies and reflections on what is really good about them. When I first used these platforms, I had strong biases against them, which were encouraged by co-workers and friends. Having spent over a decade building software in .NET, I’ve come to appreciate at least certain aspects of these tools, some of which are moving forward to .NET 5. Windows Forms, or WinForms, is one of those platforms, and I would like to spend some time talking through some really nice aspects of the framework.

Continue reading

Azure Static Web Apps with Sapper + Azure Functions

In the last post, I walked through setting up a simple Sapper application on Microsoft’s new Azure Static Web Apps. In this post, I’ll walk through my experience adding and deploying an Azure Functions API.

TL;DR Azure Static Web Apps currently only supports Azure Functions v3 with Node.js v12 and HttpTrigger bindings for APIs. See the docs.

Continue reading

Revisiting Microsoft Forms: WebForms

This is the first of several reflections on Microsoft’s original forms solutions for .NET. In this post, I want to look back at ASP.NET WebForms, or more specifically System.Web and the Page life cycle. In hindsight, I think there were some really good ideas that were just hard to understand clearly given the dominance of OO, TDD, and DDD that were at the rising to the height of popularity while WebForms was the primary ASP.NET solution.

Continue reading