5 years at Microsoft

As of the time of writing (2020-06-06), I will have been employed at Microsoft for 5 years. I joined the .NET team when I was 24 years old. Now at 29, I’m still here and thoroughly enjoying it. It’s been a great time overall. I’ve learned so much more than I ever would have imagined, met so many wonderful people, and helped make some things that people enjoy. Here’s what I remember the most in those years.

This turned out to be long. Sorry about that!

Preamble: college and pre-Microsoft

It would be silly of me to not reflect on the things that led to my job at Microsoft, so I figured I’d write about them a bit.

I graduated from college on June 15th, 2015. It took some time to get there. I was a privileged dipshit coming out of high school and I was lucky to have family who chose to support me as I failed college courses and ultimately went back home to continue playing WoW competitively. My dad told me at one point that I was privileged and lucky compared to so many other kids in the world, and it was insulting that I’d waste the opportunities I lucked into in life. My mom didn’t say that, but I know she felt the same way. This is easily the part of my life that I’m least proud of. Not just on a personal level, but because the entire time I was wasting life in a college dorm playing games, someone who deserved to be there could have been studying and pursuing an opportunity I’d effectively robbed them of. It took a few years to understand that.

In retrospect, my dad was cool for letting me live at his house rent-free while I went to a community college to try and figure stuff out. Despite not having to pay rent or for food at home, I had to find a job - not an easy task post-2008 financial crisis with no actual skills - and figure out my own transportation to/from school and work. I eventually got a job at my stepdad’s pet store earning 8 dollars per hour, which was enough to cover gas to drive to/from work and buy myself some food here and there.

Life from that point was simple:

Ride the bus for 2.5 hours every weekday to go to class (I lived far away from campus) Eat food at my mom’s or my dad’s house for free Work on weekends and some weekdays if I could afford it Do homework Somewhere along the line, I got an android phone for my birthday and learned how to build apps for it. I built a scientific calculator that could parse arbitrary mathematical expressions in my spare time (at the expense of some homework), which I think marks the time when I learned that software engineering was for me.

Eventually I transferred to Oregon State University and began life as a student living off student loans. After a month, I got a job writing .NET code for the university for 20 hours a week during the school year, and 40 hours a week during summer/spring/winter break. Life here was straightforward: lots of school, lots of homework, lots of work, and more money than I’ve ever earned before (a whole 12 dollars per hour).

My senior year was kind of terrifying. I had an amazing girlfriend (who is now my amazing wife), did well in classes, and I had become a mentor for other students at my work. But I had no job prospects. I submitted job applications every single evening for months but heard nothing back. During the winter term career fair, Microsoft had some folks at a booth (which I understood was a rarity). I showed them a mobile app I built that tracked buses in the city in real-time, which evidently impressed them enough to get me an interview. Lots of stress and studying later, I eventually interviewed on campus at Microsoft. I was pulled aside for an extra lunch-time interview and given a pitch on being a technical PM, which was compelling to me. The next day I got an offer and considering that I had no other offers nor interviews lined up at all, I took it immediately and without negotiation.

My perspective on this was that I got lucky. Lucky that I existed in an environment where Microsoft showed up, lucky that my app seemed compelling, and lucky that I had good interviewers who didn’t feel like torturing candidates. I became determined to prove that I wasn’t some fluke who slipped into the system by accident, so I spent the rest of the year learning as much as I could about various software engineering practices and the PM discipline.

First year - 2015-2016 - work life is very different

I’ll be honest, my first year wasn’t very good. The cash Microsoft offered me to help with moving emptied out really quickly after buying some basic furniture, an apartment rental (they are very expensive here), food, and bus fares (the Microsoft “bus card” wasn’t ready for me until like a month for some reason). I didn’t have a car, and I was also happy about that because cars are expensive. I was told that we get paid twice a month, but since practically nothing had “flowed through the system” for me, I wasn’t convinced that would happen. In hindsight it was irrational of me to doubt that I’d get paid, but I could only afford living in the Bellevue-Redmond region for the remainder of the month, so that weighed heavily in my mind. In those first two weeks, I was focused primarily on wondering what to do all day at work and wondering if I’d have to live in my office after failing to pay the next month’s rent. I was extremely happy to have been paid when they told me it would happen.

Side note: this brief period of my life is just a small taste of the kind of stress that millions of Americans go through every day. Throughout college and during this time, I would read elitist things some of the things people in tech (often those in the bay area) would say about poor or homeless people online. If you are in tech and feel that poor people do “irrational” things or should just “practice better personal responsibility”, please exercise some tiny effort and google the topic before expressing your useless opinions online.


During that first month, my time at Microsoft during the day was confusing and boring. On the first day we had to go to New Employee Orientation, where we got a presentation on some stuff and free lunch. Some guy from marketing named Bryan wouldn’t stop going on and on about how much he loved Microsoft, and although I appreciated his enthusiasm I think it had the opposite effect on me. The presentation felt more like a sales pitch than an actual orientation. Whatever. After orientation we were supposed to meet our managers, but mine never showed up. Me and about about 5 other people whose managers weren’t there got some lunch together. I then went to the help desk to verify my manager’s email (I had his name on a little piece of paper), how I could get my ID, and what I should do the next day. I got the contact info confirmed and emailed my manager from my personal email when I got home.

I didn’t realize it at the time, but my manager was already on his way out of the company and clearly didn’t care about what I did or what I worked on. I was told I would investigate “.NET Native and UWP” but had no idea what to actually do, so I built a UWP clone of the android app I wrote in college. I was transferred to another manager before my current one left for vacation, which apparently was a code word for “I’m just fucking leaving” because he never returned when he said he would.

For a while during my first year, I eventually felt that nobody on my team had really planned for me to be there. Nobody who I interviewed with was a part of the org I was in, so I must have just been placed there randomly. At the time, it was typically interns and people the team knew from industry who were hired into the .NET PM org. Since I was neither, I definitely felt out of place. My manager at the time helped guide me towards improving documentation, where I eventually befriended a few people and had some legitimate work to do. The docs team was completely underwater at the time, so they were thankful for anyone who could help them document .NET Core 1.0 concepts.

I remember during September people were talking about “Connects” and bonuses and stuff. I had no idea what that was and why they were talking about it. Maybe it was because I had only been on the team for a few months, but the lack of any conversation during that time felt like I was just along for the ride rather than a part of any team.

Until April of the next year, I was primarily a documentation writer and occaisonally talked about product stuff with other members of my team mostly just to learn things. My manager at the time pointed out some of my work to our director that he that he thought was good, which I appreciated a lot.

That April is when things changed a lot. The PM who had been responsible for the F# tools for Visual Studio was on my immediate team and he was leaving. Since I liked F#, used it in college for fun, and even wrote some docs with F# examples, he recommended that I fill the position. So I took it, partly because I really liked F# as a language, but mostly because I wanted to do something related to product development rather than chasing people around trying to learn how to document the things they were building. I was so completely in over my head, but luckily folks like Kevin Ransom and Don Syme were patient and gracious and accommodating of my inexperience.

I spent the next few months primarily focused on learning the F# language. I already knew it a bit and used it to build a bespoke DSL and parser that integrated with a larger codebase, so it wasn’t like I was starting from scratch. But my PM peers for VB.NET and C# were (and still are) quite literally world experts in the languages they were responsible for. When your peers are the top of their respective fields in the entire planet, it’s hard not to feel a little in over your own head. However, the pressure I felt was entirely self-created because everyone around me was supportive and treated me just how they’d like to be treated. This was a good (if intense) couple of months where I learned a lot.

Second year - 2016-2017 - things can be exciting (but hard)

My second year couldn’t have been any different from the first. I was now the PM for the F# tools for Visual Studio, and my scope had immediately increased beyond that:

Are we going to ship a new version of the F# language? We can only afford to make F# work well on .NET Core or .NET Native. Which do we pick? Additionally, I was added to a division-wide project to re-design and build the system by which Visual Studio acquires and installs components on a machine. Prior to Visual Studio 2017, acquisition and installation was the highest cause of failures for the product and the largest source of customer dissatisfaction. This was an extremely ambitious effort that required nearly every team to refactor their tooling components into manageable pieces that could be logically grouped together. I was made into one of the “owners” for .NET components and responsible for delivering the smallest possible set of components that could be reasonably used together to build .NET applications.

Going from practically no responsibility to “owning” the future of a programming language and being responsible for the way the largest cohort of Visual Studio users installs things was a whirlwind. Luckily, I had some amazing folks to work with who helped and trusted me in the following months:

Andrew Hall - my manager, also co-“owner” of another installation scenario Kevin Ransom - my friend and developer counterpart for F#, whose experience I rely on to this day Don Syme - creator of F# and ultimate example of patience and kindness Anthony D. Green - my friend and officemate, master of VB.NET and guru of developer experiences Jonathon Marolf - my friend and developer counterpart who knew (and still knows) how everything in VS works Kasey Uhlenhuth - my friend and teammate, responsible for C# IDE experiences and master of telemetry The Summer of 2016 was spent mostly learning, emailing, writing F# code, and slowly but steadily reducing the payload .NET developers had to download when installing Visual Studio from a minimum of 10GB to a minimum of 2.3GB. This included Visual Studio itself, .NET Framework developer packs most people used, desktop frameworks, compilers, tooling, NuGet, MSBuild, .NET Core SDK, the Portable Class Library developer pack, and more. Frustratingly, F# was not installed by default and this was something I couldn’t control because inclusion was determined by telemetry, and F# didn’t have enough users at the time, nor was it a part of a required component.

That Summer I also worked with others to ultimately focus F# on .NET Core instead of .NET Native. The reasoning was twofold:

We believed that the long-term future of F# was cross-platform and open source, and .NET Native was not (and still is not) either of those things. .NET Core is a means of independence for .NET (and by extension, F#). Not being tied to Windows and the internal politics of development platforms for Windows coming and going meant less throwaway work in the short-term and long-term for the people who maintain and evolve F# at Microsoft. This was a very hard call to make, because at the time .NET Core really sucked for most .NET developers. .NET Native wasn’t that much better, but there was (at the time) a clearer short-term vision for it and an application platform that existed and served a purpose via UWP. I’m happy that it appears to have been the right decision 4 years later.

Later that year I was faced with an even more challenging situation. The development team F# was a part of is centered around the Roslyn project, where the C# and VB IDE teams united and built brand-new compilers and Visual Studio tooling. The Visual Studio tooling was not just features for C#, but massive amounts of language-agnostic infrastructure that TypeScript and XAML tools had successfully adopted.

It was decided that F# tooling would also use this infrastructure. At the time, F# language integration in Visual Studio was extremely complex and almost impossible to evolve unless you were a seasoned Microsoft employee. It was stable, but the amount of work needed to add .NET Core tooling support dwarfed the work that it would take to integrate with the language-agnostic infrastructure that the Roslyn team had built. That same infrastructure was the basis for all .NET Core tooling support for C# and would steadily improve over time, so F# would get many things “for free” in the long term if we adopted it.

Thus, this work was started and moved along quite well. Unfortunately, the developer who worked on it had already planned to move to another team and it was decided that his work needed to be merged for fear that it would bit-rot indefinitely. This was a very controversial call, because the integration was very much incomplete but merged and shipped with the first Release Candidate of VS 2017. Although it had good foundations, it unsettled so many experiences and had huge gaps that were obvious within just a few moments of using F# with an existing codebase. To make matters worse, the F# infrastructure had to change a lot to accomodate the installation changes being made. The build was also in a terrible state: it would take a day or more to produce a build of the compiler and tools that could feasibly be integrated into Visual Studio. In practice, maybe 50% of those builds were actually successful and could get integrated. With many features significantly regressed and the team unable to reliably produce new builds where issues were fixed, F# tooling for Visual Studio was arguably in its worst state ever in those first RCs of VS 2017. Fun times.

Internally, we were completely focused on ensuring our setup infrastructure was sound for VS 2017 and improving the F# build infrastructure because the single worst thing you can have is a product that cannot reliably build itself. This took months to resolve. In that time, we were incredibly lucky to have an active OSS community fix numerous problems with the tooling integration and even add a handful of new features ported over from the community project, F# Power Tools for VS. Don Syme, Vasily Kirichenko, Steffen Forkmann, Saul Rennison, Ahn-Dung Phan, Jared Hester, Vladimir Matveev, and Robert Jeppesen submitted a storm of pull requests in the coming months, and all we had time to do was to pull them down, test them out, and merge them if they worked. Eventually, their incredibly hard work combined with our success in getting a reliable F# build meant that F# tooling could exist in VS 2017 alongside a brand-new F# language version (F# 4.1).

2016 was an exciting and challenging year that unfortunately got pretty bad for F# users of Visual Studio near the end. Yes, they got a new language version (still preview at the time) and some new tooling features they’d never had before. But it would take well over a year before most F# users could enjoy F# tooling in VS again, and longer for others. In hindsight, I think it would have been possible to freeze existing F# tooling, shelve the Roslyn integration work and reprioritize the limited resources we had towards completing it incrementally, ship it as off-by-default and build infrastructure to allow for turning it on as a preview feature, and roll it out at an “appropriate” time. But this kind of plan would have been extremely difficult to actually execute on and is the sort of thing that only senior-level PMs at Microsoft can usually do. I don’t believe I would have been able to lead such an effort successfully, especially considering there was no support for properly shipping and loading experimental versions of Visual Studio tooling at the time. Some kind of infrastructure for that would need to have been built, which also would have been very difficult and time-consuming. Given all of this, I’m fairly positive that we never would have had support for F# and .NET Core projects in Visual Studio had we tried to take this route.

The beginning of 2017 was much like the end of 2016: testing contributions from the F# OSS community, reviewing pull requests, fixing issues, and preparing for the release of VS 2017. Due to the efforts of F# contributors, the tooling support was usable for some codebases (though not all…) and despite its flaws could exist in the product and reliably be updated.

I then got to draft a blog post announcing F# 4.1 and its feature set (which I frankly was not terribly involved in) and the updated F# tools for Visual Studio, which at this point had accumulated a lot of new features compared to previous versions.

In the months following the initial release, things didn’t go too well from a product quality standpoint. More people installed it and filed more bugs, and it was apparent that things were nowhere near the expectations people had. A lot of people have avoided to previews altogether, and it turns out there were more gaps than were identified at that time. But not all was bad: bugs were fixed, features were adjusted, and we got new contributors regularly. We were even able to roll out a “nightly” feed where you could install whatever was merged into the main branch on GitHub 24 hours ago on your own machine. Because the F# codebase evolved more rapidly than the F# release in Visual Studio, and there were many bugs fixed in place but not yet shipping in Visual Studio, lots of F# users installed these nightly releases because they were a significant upgrade.

Third year - 2017-2018 - finding my identity

The beginning of my third year at Microsoft was spent mostly working on F# support in VS 2017, especially in the first half. Although I don’t like how it happened, one positive outcome was a significant uptick in OSS activity. Some of the goals of integrating with Roslyn tooling were paying off from a technical standpoint, because it was actually feasible for anyone to add new features or improve existing ones. Well, that is if they were willing to pay the cost of an awful and error-prone first-time setup process for contributing to the repository. Our infrastructure may have improved, but it had a long way to go, especially for code contributions.

In addition to spending enormous amounts of time continually reviewing code, testing things, and even submitting some fixes of my own, there were also a few of bugs introduced by F# 4.1 that had to gradually be fixed. It was clear to myself and the engineering management around me that we needed to get more people on the team to get on top of the bugs and stabilize things. However, budgets were tight and adding another engineer to the F# team meant not adding one to another team.

What a lot of people on the outside don’t understand is that at large companies, there isn’t some giant bucket of money any arbitrary team can just take as much as they want from. Most teams at Microsoft have big ambitions and if they could just take as much money as they wanted, the company would go bankrupt within a year. Individual divisions have their own budgets to balance, and that is also true for engineering groups within those divisions. The F# compiler and tools (if you consider VS Community) are 100% free and open source. We don’t directly contribute to any revenue figures. We do have an impact, but it’s impossible to measure because we don’t track our users obsessively like Google or Facebook does. Teams in my working group are not particularly large, and we all do a lot more than most people think we do.

In light of this, I spent some time reasonably estimating how much money F# as product brought into Microsoft and I was able to help the management folks who already wanted to increase the size of the team, but just needed some “ammunition”. This was the first time I’d ever had to grasp the complexity of a compiler, language tooling, OSS ecosystem, and business processes and it was extremely hard. I was stressed and overhwhelmed.

Another new thing happened in the Spring of 2017: I was invited to give a keynote at F# eXchange , a commercial conference focused on F# developers in Europe. I was nervous and frightened: “Hello everyone, I’m the new and inexperienced person who fucked up your IDE and colluded in some bugs being shipped, please listen to what I have to say”. Despite being a little spooked, I practiced my talk with my manager, got on a plane to London, and took some trains to Cambridge to meet with some F# users who were going to attend a meetup there that evening.

The F# community is filled to the brim with kind, intelligent, and welcoming people. Sleep-deprived and in a country I’d never been in before, I definitely didn’t expect to be greeted so warmly by Krzysztof Cieślak and Mark Gray , then later Tomas Petricek and Evelina Gabasova . This was but a taste of the many friends I would make over the years.

The week I spend in the UK at the conference and among new friends was unforgettable. Dinners and drinks across London with (now) friends at G-Research , exploring Cambridge, accidentally booking a hotel for the wrong month and having the gracious staff put me up in an empty room at no cost while I got my true lodging sorted, and countless hours spent with new friends who all shared in our passion for the F# language and its community. I can’t name them all right now, but some of those I spent the most time with include Alfonso Garcia-Caro , Enrico Sada , Gien Versatche , Scott Wlaschin , Isaac Abraham , and Mathias Brandewinder . They’re all welcome to stay in my home any time they’re in the Pacific Northwest.

Once back, Spring went by quickly with more of the same work as before. I helped handle surges of tooling improvement contributions and get bugs fixed. I also started to take on F# documentation and helped move the F# language reference and tutorials to the new documentation site .

In the Summer of 2017, we made a strategic call that may have been the most important thing to happen for F# in a long time: changing the .NET SDK to include F# by default with .NET core. Prior to this point, the F# integration into .NET Core was via a component built by the F# community that packaged our .NET Core compiler into a component that could optionally be brought into a project. This worked fine in the early days of F# support for .NET Core, but as our support stabilized, we needed to be “in the box”. Additionally, this would allow F# to be installed by default for anyone installing .NET with Visual Studio, since Visual Studio required .NET Core and .NET Core now required F#. To this day, getting started with F# on any OS is trivial: just install .NET Core and create and F# project. If you install .NET, you get F#. End of story.

With the new year, I also got a new responsibility. My boss was the primary person responsible for growing the number of Visual Studio users who use Azure. He needed help, since this was a daunting task that was poorly understood by most people, and required significant time learning all kinds of things. What Azure services make sense for people building new apps? What about existing apps? What do people struggle with the most? Is our documentation and guidance matching what developers try to do? Is everything up to date? Are we even exploring at the right thing? Are we measuring the right actions via telemetry? What new things are teams in the Azure org cooking up, and should we focus on those things? What do MVPs say? What do existing Azure users say? What do AWS users say? What does this new AWS service do and is it compelling to our customer base? Why or why not? Etc.

The details of this stuff are kind of boring, and frankly, not my cup of tea. But I learned a whole lot about what people struggle with and how we measure things. I had to write out a report every other week about what we learned, measured, etc. We were consistently under our growth targets and/or within the margin of error for measurement at the time, which I view as a success largely because we tried really hard to make sure we were measuring things as accurately as possible. My boss later convinced the management folks in the organization that we were focused on the wrong things, and my understanding is that there is now a far greater alignment between how our division measures that cohort of developers and how the Azure division does.

Something that stood out to me about this is that at no point did our management poke and prod and try to push us to “make number go up”. They wanted to read our hypotheses we developed, what we tried, what we learned, and what our new hypotheses to test were going to be. They understood just as well as we did that this was an extremely complicated and difficult space, and so the focus was on learning things and sharing what we learned with others instead of being “right” and “growing”. This has been a consistent theme with my management throughout my career at Microsoft: prioritizing people learning and trusting them to do good work with what they learned. I may not have enjoyed this project at the time, but the environment it existed in was one that helped me grow and I’m happy about that.

In the Fall of 2017, I also helped move along a proposal to move the F# Core Library package on NuGet to be built and published from the Microsoft development repository. It was a package built and packaged by the F# community to support cross-platform development before .NET Core, but also to integrate more cleanly with F# projects than referencing an assembly placed on a machine by Visual Studio.

A brief history lesson: Microsoft has traditionally “seen” F# as “Visual F#"; that is, a language and tooling that is incorporated into Visual Studio. The F# community has always treated F# as something more than that. This manifested itself in very real ways in the past, including with how the F# Core Library was distributed. Microsoft would build and distribute a binary via Visual Studio to build F# applications within Visual Studio that would run on Windows. This was fine in 2010 when the first F# release in Visual Studio happened, but in 2017 this was not acceptable anymore. F# was transitioning to be “not only Visual Studio” and ultimately become cross-platform, open source functional language for .NET . A necessary step on this path was to consistently build and deploy the F# Core Library for all scenarios.

This was an extremely difficult task firstly because it ultimately meant the F# community had to give up some control they had back to Microsoft. Everyone involved was kind and agreeable, but it took some time. Secondly, we had to make massive changes to our build infrastructure and Visual Studio tooling to make all things FSharp.Core center around deploying as a NuGet package. We messed things up a few times and had to unlist some bad package versions. The system is still not perfect today, but it’s stable and things mostly make sense.

That fall, I was invited to speak at Open F# , an incredible community-run conference that I prioritize attending every year. I had an absolute blast, made new friends, was honored to be named a “Community Hero” . One thing I definitely won’t forget is staying up until 3am talking F#, community, and life with Rick Minerich in Mathias Brandewinder’s kitchen. We both had to leave, so we accidentaly walked into the room where Gien Versatche was sleeping and she was pretty mad at us for waking her up (she was an organizer of the conference and deserved to rest without interruption). We apologized profusely and got into an Uber before parting ways until next year when Rick was kind enough to host me for his meetup in New York.

In the fall, the F# team also got a new hire, Will Smith. He’s a friend of mine and one of the most incredible F# programmers I’ve ever met. With his help, we were finally able to make F# tooling support in Visual Studio when using .NET Core to be at part with non-.NET Core.

Near the end of 2017 is when I finally felt like I belonged in the role I was in. A lot of this was maturing and growing professionally. But I think most of it was so many people in the F# community choosing to welcome me as a part of their community and place trust in me to do right by them with the language and tools. Had it not been for them, I’m positive that I would have ultimately changed roles or left Microsoft if a company waved enough money in my face. Conversely, one of the major reasons why I’m not tempted by recruiters at Facebook or Amazon or whatever is that I’d have to give up one of the most personal and meaningful aspects of my job.

The beginning of 2018 was unremarkable. We were able to deliver proper support for .NET Core projects using F# in Visual Studio, and there was still a flood of OSS contributions to keep on top of. More features, but this time of the “polish this up” variety, more bug fixes, and more infrastructure improvements. We began planning out what the next F# language version would be, and we ultimately landed on F# 4.5 because we wanted to unify a hilariously confusing versioning system that F# had developed over the years. That meant jumping from F# 4.1 to F# 4.5. Oh well!

I got to attend F# eXchange again, but this time I left home for 2 weeks. I gave a talk with my manager at a Microsoft conference in Orlando, then flew up to New York City to meet some customers and speak at a meetup. I then flew to Dublin, Ireland to meet more customers and take notes on what things could be improved with the F# language and tools. Dublin is a pretty cool city. I then spent a week in London and met with old friends, made some new ones, cavorted around town a lot, and had an amazing time at the F# eXchange conference.

Near the end of my third year at Microsoft, I finished my “help grow Visual Studio Azure users” duties. F# 4.5 was in full swing heading into the Summer, and I was able to spend a lot of time learning about how the F# compiler works (at least some parts of it) in the final weeks of my third year at Microsoft. It was a good time.

Fourth year - 2018-2019 - owning initiatives

The beginning of my fourth year was dominated by shipping F# 4.5. We had recently merged a feature to enable proper use of the Span<'T> type, a new primitive in .NET Core that would serve as the foundational type that all kinds of buffers (arrays, strings, etc.) could be treated as. Because it is a foundational type instead of just some addition to the .NET core libraries, it was critical for F# to deeply understand this data type and doing so meant a lot of compiler analysis to ensure that the code you write doesn’t allocate on the managed heap.

We (mostly me) faced some criticism from some F# users for focusing on this, largely because it came at the expense of features that they wanted for everyday F# programming, like Anonymous Records. And for anyone using .NET Framework, none of this work would be useful to them because the Span<'T> type and its associated runtime enhancements are not on .NET Framework. I struggled a lot to express that F# was effectively “replatforming” with .NET Core as its foundational base for doing things, and this was necessary for that. This necessarily came at the expense of people who have no need or desire for .NET Core; or rather, it meant that their world was effectively frozen. Sure, they’d get new features that could work for them over time, but all the energy being poured into F# was (and still is) centered around .NET Core.

In mid-Summer, we shipped F# 4.5 with more ways to write high-performance, low-allocation F# code alongside a handful of other nice features. We even had a community member implement a feature end-to-end, from suggestion to design to implementation. Overall, it was a good release with few problems - a stark contrast to F# 4.1 and the first of a series of releases (F# 4.5, F# 4.6, F# 4.7) where we shipped good stuff people mostly liked and we didn’t have a bad time dealing with bugs that came afterwards.

In the fall, I was given a new assignment. Throughout Visual Studio 2017, various teams had tried - and sometimes failed - to improve the time it takes to load a codebase before you can start writing code. In fact, an entirely new way of working with VS called Lightweight Solution Load was first shipped in VS 2017 update 15.0, and then removed from the product in VS 2017 update 15.5. It correctly identified that developers don’t want to load absolutely everything all at once before touching a single file, but the approach taken was ultimately too complex from a user experience standpoint. But that didn’t mean we were going to abandon the idea that load times needed improvement, and I was tasked with being an “owner” for .NET tooling in the renewed initiative to figure things out.

At the same time, there was a big push to improve the memory usage of F# tooling for larger codebases, especially based on feedback from industrial users. The F# compiler and language service has had some very serious, latent issues that were now getting uncovered as the F# developer base grew and codebases expanded in size. The performance characteristics were fine for most users in 2015, but it wouldn’t cut it in 2018. The work to improve F# tooling for large codebases is still ongoing, and there are still some ways you can make Visual Studio break down from the sheer weight of memory allocations with F#. But we fixed a lot of these issues in the Fall and Winter of 2018, which I’m proud of.

When not doing F#, I spent a lot of my time running user studies where I essentially tortured people with an intentionally broken Visual Studio to explore user behaviors when things were still being initialized. I learned a lot and helped contribute to a deeper understanding of user behaviors when they’re first starting to code for the day. I then wrote a document detailing an experience for Visual Studio when things were still being initialized in the background, much of which now exists in Visual Studio today. That said, my heart wasn’t 100% in that proposal. I believed in aggressive caching of data and lettings users work with “stale” information from a cache until background work is done and data is up to date, without notifying people in the UI. Unfortunately, I didn’t put together an alternative proposal and associated work to show that it would be a better approach, so it was ultimately just another opinion.

One thing I found myself running up against at this stage in my career was a cultural difference across teams. On the .NET team, we try to be “agile”: process is usually minimized, and we like to try things and then react to change. And within the PM subset of the .NET group there is variance from PM to PM, but I would say that we generally tend to prioritize using the product we work on daily, especially those of us who work on tooling. There is a culture of having a deep understanding of how users use what you work on, and one of the best tools for developing that understanding is to use the product yourself. Additionally, it’s often a virtue to know how what you work on operates under the covers, at least to a reasonable degree. This last part is often necessary because many things users want are inherently technical and you cannot make a good decision on something unless you understand it at least as deeply as the user does. Very often a request will come in that has implications for use cases that the user did not account for in their request. It’s the responsibility of a PM on the .NET team, ultimately, to have the context to understand what implementing a request would imply for other scenarios or other parts of the product they’re working on. That understanding doesn’t have to originate from the PM, but it’s the PM’s responsibility to develop that understanding (however works best for them) and communicate with their users and peers. This kind of deep knowledge takes a long time to develop, so we encourage people to stick around for a while. I’ve found that I thrive in this environment.

This culture is not uniform for every team and individual across the division I work in, and I ran headfirst into that on this project. I very strongly empathized with individual users because I used the product daily and understand how it works under the covers (to the degree necessary to make decisions about it), but this was not viewed as valuable or relevant to the work I was assigned to. Instead, user studies and related things (typically survey results) are what mattered most, and the lack of these things would be used as a tool to prevent any work from being done on something. I thrive in minimal process environments where we react to feedback and don’t thrive so much in more process-heavy environments. I can understand its value and have come to appreciate user studies, surveys, and customer calls as effective tools in my toolbelt. I use these as tools myself, but not to the degree that other teams do or expect them to be used. This was ultimately the root of my frustration at the time.

Collaboration was respectful and ultimately fruitful, but it was also challenging and frustrating for me. But at the end of the day, engineers put in a lot of hard work and the product improved in time for a very excellent Visual Studio 2019 release (and excellent subsequent releases). I still believe we could have had an even better short-term and long-term outcome had we taken a different technical route, but “our good release could have been better” is not a hill worth dying on, and making a stink about that would only serve to diminish the work other people had done.

That fall, I got to attend Open F# again and it was an incredible time. I have decided that it’s my favorite conference to attend. The whole thing is community-organized, and the organizers are my friends. They care about every single little detail, especially about the “feel” of the event being community-focused, and it really shows. I got to spend more time with my friends in the F# community and that continued to validate that my job was the right one for me.

The F# 4.6 release for VS 2019 also went well. We shipped with a pretty egregious bug where defining an anonymous record would break all ability to debug your program, though. It’s really embarrassing that this one slipped through. But overall, performance was improved so much that many users completely abandoned VS 2017 because VS 2019 was so much better for them. We worked towards another successful VS 2019 update 16.1 release with more performance improvements and fixed a few bugs along the way.

In 2019, I decided to branch out a bit with my conferences and submitted talks to LambdaConf and Compose Conference. They are functional programming-focused conferences that have traditionally had little or no F# presence (at least in recent years), so it was kind of scary to be going into spaces where I was mostly on my own. In addition to that, some of the folks speaking at these conferences are some of the smartest and most talented functional programmers in the US. I rolled into Boulder, Colorado completely intimidated but ended up having a great time, learned a lot, and made some friends along the way. Soon after LambdaConf, I few over to NYC to talk with some customers and speak at Compose Conference, where I also had a great time with some of the excellent folks in the NYC functional programming scene.

In the middle of the NYC trip, I was pinged on Slack by Don Syme to look over an “AI language strategy” set of documents that loosely laid out various things he had been working on to better define what we could do to impact Machine Learning from the perspective of languages. The general premise was that Python is not great at expressing what people in this space care about, and although it has excellent libraries and frameworks, they force a “everything must be a tensor” view of their world on any problem people solve with no regards to if that’s actually the appropriate way to model the problem. There is also the problem that it isn’t really Python being used to execute models but practically another language with its own semantics grafted onto Python via a framework (Tensorflow and Torch are examples). I lacked (and still lack) deep understanding of this space, but it all smelled like “this is an immature subfield of software engineering” to me which was exciting. I spent some time working with Don and others to identify things we could materially do in F# to improve using F# for interactive and “analytical” workloads near the end of this fourth year.

Fifth year - 2019-2020 - becoming senior

I started off my fifth year without a direct manager, instead reporting directly to my director. This is somewhat common at Microsoft when managers leave, and at this point in my career I understood that and didn’t think much of it. I’ve always had a high degree of autonomy so far in my career, but it felt like that was dialed up even more which was pretty great. I spent some time in various meetings discussing various strategies for addressing language-related gaps for machine learning and that was pretty neat. The fact that I was treated as an expert in this space is still kind of wild to me, but I guess it’s hard to find people who have spent years working on programming languages anyways.

Leadership at Microsoft has been burned in the past on grand, multi-year strategies that fell apart because those strategies (shocker) didn’t predict the future and were incredibly expensive. So, the task at this point was to define incremental things we could do in languages and tooling to make today’s machine learning tasks (and everything that surrounds ML) better. More long-term goals were also defined, but we were careful to think about them in a way that was loose and able to change based on how the world changed, rather than follow some rigid path beautifully laid out with millions of assumptions about how the world would operate in a few years. I really liked this work and it took up the bulk of my energy that Summer. Much of what we planned has become concrete in F# 5 and the .NET Interactive initiative that brings F# and C# to Jupyter Notebooks and VSCode Notebooks.

Heading into the fall, we worked on F# 4.7 and introduced the ability to add preview features to the language. This has been critical work for us to release F# 5 features early and will likely serve us well for all future F# releases. F# 4.7 wasn’t that big of a deal from a languag evolution standpoint but it contained some nice improvements like Implicit Yields that people like.

At the same time, I was tasked with developing a tool that could convert a .NET Framework project into a .NET Core project. Conversion tooling has long been a touchy subject for a lot of folks, so it was steeped in politics, but my director gave me air cover to just work on it, so I built the initial version of try-convert and have been a co-maintainer of the tool ever since. The result spooked some people and that was stressful. One of the problems with working at Microsoft is we have incredibly smart people who are, in a way, damaged by having to support halfway-broken things that weren’t thought out completely. The don’t react well to seeing new things built by someone else that encroach upon “their space” in large part because historically, they have been asked to maintain half-baked things other people built and subsequently abandoned. Additionally, conversion tooling for .NET is something multiple engineers have wanted to do before, but they were told at a different time by a different management chain that they weren’t allowed to do it. I was apparently lucky to be able build try-convert , and after speaking to some people it ended up being fine. Customers liked it and it’s been used by a lot of people to help converting to .NET Core, so I’m happy about it and continue to maintain the tool today.

That September, I was given a great review by my management and told that I was on the path to becoming Senior. This was wild to me, because I still felt like a junior PM. There are a lot of people on the .NET team with much more experience and knowledge than me, and the thought that I would start to be considered a peer to them rather than some junior who’s still learning how to do stuff was kind of a shock. I was happy, but also had a lot of imposter syndrome. I still have that feeling, and I know that it’s not rational to compare myself to people who literally have a decade or more experience than I do, but it still happens.

Also that September, I got to attend Open F# again and once more had an incredible time. There were some spooky circumstances involved with a former F# community member who had threatened the lives of some F# users over email, so I had to speak with security people and spend time with other members of the F# Software Foundation board to help organize paid security for the event given that at least one of the victims was attending. Happily, nothing happened, and the security guards were very bored. I made some new friends again, ate incredible food, and got more drunk than I’ve ever been before with a friend from college. I think I’ve had like one beer since that time and the idea of alcohol still isn’t appealing to me.

The following Winter was kind of a blur and not notable in terms of any big projects I was working on. I spent a lot of time contributing to the F# codebase and learning more about how some of the internals of the compiler worked, which was great.

In the Spring of 2020, I was promoted to Senior. This still feels kind of surreal to me, but it also then hit me that every single junior PM I’d interact with would consider me a Senior PM. I remember what I thought of Senior (and higher ranked) PMs when I was fresh out of college, so I promised myself that I would work to try and not intimidate junior PMs I worked with. One thing I try to do now is ask “dumb” questions about things “every PM should know” in large, public email aliases that I know junior PMs will see. It doesn’t happen often, but if I have the opportunity to ask a question on a broader email alias I try to do that rather than just ask specific people. I want people who are new (or new-ish) to understand that just because they don’t know something doesn’t mean they are stupid, and there are lots of people at Microsoft who also don’t know certain things. I don’t know if this is the best possible approach, but I know it’s something that would have made me feel better when I was junior. This is something I’m seeing as a new phase in my career: how to “act senior” but also make it so that junior PMs can feel less self conscious about their lack of experience.

One thing I’ve cared about for a long time is the .NET (and F#) development experience in Visual Studio Code. VSCode is my favorite editor, but it has a subpar .NET experience. There are very deep technical reasons for this, but what it all boils down to is that Visual Studio has critical infrastructural components (often called a “project system”) that are extremely robust, but stuck inside of devenv.exe today for both technical and nontechnical reasons. Neither the C# nor F# plugin has a system that is even remotely as robust, and this unfortunately affects nearly everything you can do with a C# or F# codebase. Small codebases work fine, but once you start incorporating many different dependencies and your codebase grows into distinct layers/components, management of these assets can get cumbersome and/or just fall over when you’re not in Visual Studio. This is not the fault of the OmniSharp nor Ionide plugins; it’s just that they’re missing years and years of engineering time spent in this space that Visual Studio has.

This spring, I was tasked with writing up a proposal to identify how to make the .NET experience in VSCode better in light of VSCode being a primary editor with the Visual Studio Codespaces initiative. Additionally, we’ve seen at various times that people who aren’t long-time .NET and Microsoft customers gravitate towards VSCode first, and it would only make sense for .NET to have a good experience there if .NET is to attract new users. I spent a long time doing “Customer Development” to identify who was already using VSCode compared to VS, what they were doing, what they wanted to do, what they struggled with or found unsatisfying, and what they felt was missing. I also kicked off an ongoing triage session with other developers to classify numerous issues filed on the C# extensions so that we could get a better technical understanding of the problems the plugin faces today.

Leading right up to the end of my fifth year, I lead a discussion around a long proposal I wrote about making .NET better for VSCode with various directors. It was a successful proposal that they all accepted, which meant we could start getting tactical about how to see it through. It was ambitious but also incremental, which I’ve learned over the years is often a path to success. I don’t know at all how this will ultimately pan out since it is in such early stages, but I’m excited for the challenge and I hope to make VSCode great for .NET users, continue to move more things into the open source space, and build pluggable components that community members can use.

The next five years

I’ve had a great time at Microsoft. I made so many friends and have learned so many things I could not have possibly anticipated. I’m looking forward to the next five years of learning more things and making new friends. I don’t have much of an idea of what the next 5 years will be like, but I hope it involves a lot of the kinds of things that made the previous 5 years so great.