I’ve been meaning to write my thoughts on software leadership for a while. I’ll try to do tht here with a series of posts on the topic. Let’s start with fostering a strong team.
First of all, most teams are already great, they may just not know or show it. The talent is usually already in the building. I’m confident in the abilities and potential of most engineering team members to succeed with any project we throw at them.
But all teams can do better. We can do better as organizations leaders by setting a good example. And we can start by setting an example in 3 key ways: Transparency, Respect, and Accountability.
One thing I am not confident in most teams to do, is communicate the company vision. I think very few of developers could tell you how what they’re currently working on lines up with company goals, or what priority it is.
We can start to change this with transparency, which happens to also be a core tenet of Scrum. By being transparent, as leaders, as an organization, we can empower our product development teams to make good, informed decisions about their projects. And we can show them the visible importance of their work on our backlog.
In setting this example, we can expect the same from them. It is as simple as professional courtesy. We can show our steps in decision making, and they can show theirs. The same goes for progress. This expected transparency will increase mutual understanding between product development and all other departments and department heads.
By increasing this communication and buy-in, we will provide our teams with intrinsic motivation. We will all be purpose-driven, and we will see better results in quality and productivity.
Respect may be the hardest thing to foster in our product development team. From my perspective, mutual respect between all members of a team is often missing in many of the relationships. Sometimes it is simply person to person, but other times it is person to department. A lot of the time it is person to organization. And again, we can fix this by setting an example. We can lean on our teams harder than we have to date. We can expect great things, and we can communicate our expectations. And not just verbally. We really need to trust our teams to solve problems, and not to simply follow instructions.
I often see team members hesitating to make suggestions or question the projects goals. This is a bad thing. We should be fostering these conversations, because these conversations lead to innovation and creative solutions. Let’s encourage questions, and expect great solutions from our development teams.
With our freshly conveyed respect, we gain accountability.
Most notions of accountability come from negative perspectives. We only need to foster accountability because we need someone to be accountable for something that has gone wrong. It’s true, and from time to time we need in our organizations. It’s also a key part of coaching. And sometimes, it’s a good motivator to know that if a project fails, some person or group can be held accountable.
The concept I think everyone misses with accountability, though, is that it’s a two way street. Early in my career, I worked on a team for 18 months before I knew about my accountability for someone’s positive experience with our software. That’s right, for a year and a half, the only post-release feedback I received for my code was the negative type. Obviously my team appreciated my work, but all I really ever saw beyond that were the bugs.
The feedback loop needs to continue regardless of the feedback.
We all go to many postmortems when something our team worked on broke. We rarely go to a meeting to explain why or how something our team worked on was produced so well. As engineering leaders, we need to be asking a lot more questions of the successful teams than the unsuccessful ones. We should maximize our success instead of minimizing our failure.
It’s amusing how little software leadership has to do with the actual software sometimes. I promise I will have some more technical leadership topics in the future, but many will be like this. I hope some of this will help you with your teams. As always feel free to send any comments to me on Twitter at @clintcparker.
I love the persistence of a host machine! I’m too cheap to get a VPS. I really like the windows 11 OS but really love mac laptops. I left
3389 open on my router (with DDNS) and found myself getting brute forced. I saw this post around the same time, and realized tunnelling could be a great alternative.
I wrote this for my situation. While setting it up, I found there was not a central guide, so I made one. If it doesn’t perfectly fit your situation, hopefully a part of it will help.
Assumptions About You
- You have administrator access to both machines
- You are comfortable with the command line on both systems
- You have VSCode installed on both machines
- You’re aware of the concept of SSH
- You have a Cloudflare account and a website there
- You’re using brew
Assumptions About This Guide
- I’ve got
example.comon my cloudflare account (I don’t, obvs)
- My tunnel is named
- My tunnel id is 123455677890asdf
- My macOS username is
get pwsh (i used
PS> winget install Microsoft.PowerShell
- At the time of writing, should be v7.2
install chocolatey at https://chocolatey.org/
PS> Set-ExecutionPolicy Bypass -Scope Process -Force [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
install cloudflared via chocolatey
PS> choco install cloudflared
PS> cloudflared login
- you may need to manually open the link in the output and select the site you’d like to add the tunnel to
- create a tunnel
PS> cloudflared tunnel create wormhole
- setup cloudflared as a service
PS> cloudflared service install PS> mkdir C:\Windows\System32\config\systemprofile\.cloudflared
- create a config
PS> code C:\Windows\System32\config\systemprofile\.cloudflared\config.yml
tunnel: 123455677890asdf credentials-file: C:\Windows\System32\config\systemprofile\.cloudflared\123455677890asdf.json ingress: - hostname: wormhole.example.com service: ssh://localhost:22 - service: http_status:404
set service as automatic
PS> Set-Service -Name Cloudflared -StartupType "Automatic" PS> Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\Cloudflared\ -Name ImagePath -Value "C:\ProgramData\chocolatey\lib\cloudflared\tools\cloudflared.exe --config=C:\Windows\System32\config\systemprofile\.cloudflared\config.yml tunnel run" PS> cloudflared tunnel route dns wormhole.example
add a non-admin user (for ssh only). enter a paasword when prompted
PS> New-LocalUser -Name me-ssh
set pwsh as your default shell
PS> New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Program Files\PowerShell\7\pwsh.exe" -PropertyType String -Force
create external user .ssh directory to house authorized_keys
PS> mkdir C:\Users\me-ssh\.ssh
PS> code C:\ProgramData\ssh\sshd_config
- enable publickey authentication, uncomment this line
setup sshd & ssh-agent as automatic services, and start them
PS> Set-Service -Name sshd -StartupType "Automatic"; Set-Service -Name ssh-agent -StartupType "Automatic"; Start-Service sshd; Start-Service ssh-agent
make sure developer tools are up to date
$> brew install cloudflare/cloudflare/cloudflared
- to confirm install
$> cloudflared -v
- Login (just like on the host setup)
$> cloudflared login
A browser window should have opened.
If the browser failed to open, please visit the output URL directly in your browser.
- Select the site you want to to log in to
- after selecting you’ll see in the terminal
You have successfully logged in. If you wish to copy your credentials to a server, they have been saved to: /Users/yourusername/.cloudflared/cert.pem
- next, update your hosts file
$> code ~/.ssh/config
- add the following
Host *.example.com ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h
- now you can ssh into the box directly
$> ssh [email protected]
But let’s take this further for RDP and setup local forwarding
$> ssh -L 56789:127.0.0.1:3389 [email protected]
- Setup pub key and add to host
cat ./.ssh/id_rsa.pub | ssh [email protected] "echo | Out-File -FilePath ~/.ssh/authorized_keys -Append"
- Connect to the tunnel from the client machine on startup https://mpharrigan.com/2016/05/17/background-ssh.html
- Remove the password from the newly created user
- Change default ports (ssh, RDP)
- Restrict RDP access to 127.0.0.1 only
- Create a host and client scripts to just take care of all of this
I recently created name-on using the DotNetCore command line tools and VS Code. It was surprisingly easy, and I love scaffolding from the command line.
I also recently got my WSL setup working, which involved setting fish as my default shell, and revisiting some of the functions I have made in the past.
My quick experience with the DNC CLI seemed like the perfect thing to functionalize. I like having a standard structure to my apps:
- class library
- command line
- web app / API
- test project
DNC has the concept of tmeplates and extensions, but what can I say, I wanted to write this with fish. So I did.
I picked the name belvedere by looking up scaffolding in a thesaurus. Apparently its a “raised turret atop a house,” and comes from 1590’s italian.
Belvedere will create all the necessary projects, with the correct intra-project references, a solution, gitignore, and README. It also intializes a git repo and commits the created files.
You can find the code here: https://github.com/clintcparker/fish_functions/blob/master/belvedere.fish
But Y tho?
I needed a unique name generator, so I built one.
I had used the Heroku unique-name generator before, when building bad ideas. I loved how it removed a mental hurdle from getting something out the door; coming up with a name. Personally, I’m horrible at naming things, so this was a necessity. I don’t want to get hung up on picking a good name, and the defaults are equally as bad (ConsoleApplication23, anybody?).
I’d also been wanting to get back to dot net core. The last time I had played around with it, they were still using the
dnx command line tool and
project.json files. So this project seemed small enough, and valuable enough, to actually keep me on task for the duration of v1.
The command line
I was stoked to be able to layout the project structure from the command line. I’m just so much more optimistic about a tool when there’s a CLI behind it. Even if I’ll never script it, the idea that i could is very appealing.
I scaffolded the whole project via the
dotnet new and
dotnet add commands. I was also able to build and test in the same manner. It was a nice break from VS 2017.
I found lists of adjectives and nouns online. And thank to some recent practice with regex crosswords, quickly stripped everything but the words themselves.
I added some tests for uniqueness, which is about 99.985%. I also added protection for never getting the same name twice in a row.
I was able to create a CLI for OS X, which was came in handy when publishing to Azure, and needing names for everything.
For the web app the
dotnet help lists a template called
razor with the description “mvc with razor pages.” I’ve used the Razor syntax since it debuted, and thought, “of course I want razor, not
aspx.” Apparently though, Razor Pages is a new thing. I actually really liked it for build the web app component. I still created a controller for the API, but was happy I stumbled onto this new paradigm.
I really went over the top with the completeness. Azure for hosting. Custom domain through NameCheap. SSL through CloudFlare.
The README has a roadmap, which includes packaging the CLI and improving the site. PRs are welcomed.
While at //build I was inspired to update my extensions to support VS 2017. I meant to do it last year, but got distracted. The process was really simple, and is outlined on the new hotness that is MS Docs. It took me about 10 minutes to get it all configured an tested. But then…I was sidelined by my CI config.
For some reason, my AppVeyor builds were failing. They were clearly pulling the latest from my repo, but for some reason, the nuget restore stopped working. I probably should’ve googled the issue, and I think I did, but I was asking the wrong questions. I finally gave up and manually configured the build via the GUI, and then exported that config to YAML. When I went to do the next extension, I finally realized what the problem was. I used the exact same exported YAML, and got the exact same initial errors with the nuget restore.
Googling “appveyor not using yaml” led me to this help article. I still don’t understand why permissions were an issue to read the
appveyor.yml, when it was clearly reading an updated
csproj file. But I do now have extensions that support VS 2017.