This post is a retrospective on my transition from being a native Android developer to becoming a “polyglot” full-stack web developer. I’m presenting this from my (obviously subjective) point of view because I hope this information will be beneficial to both native and mobile developers with ambitions of exploring web and backend development, and web developers wishing to expand their own views based on the perspective of a person coming from a radically different background.
Polyglot is a term usually used to describe someone who is proficient in multiple real-life languages, but we can borrow this term and use it in the context of programming languages. It’s not unusual for any of us IT professionals to be in contact with multiple languages and environments over the course of our careers. However, most of us stick with the preferred set of languages required to get our jobs done in a particular domain and environment. Because of this, I’ll adapt the literal definition slightly and treat a polyglot developer as someone who’s proficient in multiple languages and can maintain this proficiency when working in multiple different domains.
I spent most of my career developing native apps for mobile. I started with the now-defunct Windows Mobile (around the time 6.0 came out), and later transitioned to Android, where I spent more than eight years. I worked on apps used by millions of people before working on PSPDFKit’s Android SDK, which is used by hundreds of different companies and almost a billion people.
Working as an Android developer required me to have proficiency in multiple platform languages: Java, Kotlin, and — to a lesser extent — C++. On top of that, I had basic proficiency in languages required for handling tooling like managing the build process and CI — for example, Groovy for Gradle build scripts, and Bash and Perl for scripting. I dedicated my full focus to following the latest developments on my platform of choice (Android) to have the confidence to consider myself as an expert.
I had good proficiency in multiple languages, yet I never considered myself a true “polyglot developer” because it didn’t fit my definition above. After all, I didn’t have any experience outside of the mobile development world, and I didn’t feel comfortable working in a different domain.
Making the Switch
Around two years ago, while I was still working as part of PSPDFKit’s Android team, I was given an opportunity to switch to the Web team. This meant I’d trade in working as a proficient Android developer to beginning in a totally new field that I knew almost nothing about. In spite of the challenges I knew I’d encounter, I was intrigued and decided to switch.
One thing I didn’t enjoy about working with the web as a platform is that most of it is basically frontend work, which isn’t my first choice for problems I enjoy working on. You might argue that there’s not much difference between frontend web and Android development. However, my work on Android struck a good balance between frontend-only tasks; business logic; and mobile platform technical challenges such as optimizing for battery life, being offline first, and interacting with hardware like the camera, and even the audio subsystem.
I wasn’t overly happy with the position, as UI work isn’t particularly interesting to me, but I also wanted to stay on the web platform side of things, because the work entailed solving problems I find interesting (for example, distributed systems, high availability, and scalability.) Additionally, I’m drawn to the fact that the web provides more freedom compared to mobile platforms mostly owned by a single company. And what intrigued me was the backend side of things, so I expressed an interest in working on our Server and Services team.
Since then, I’ve been exclusively working on PSPDFKit’s server (PSPDFKit Server and Processor) and cloud (PSPDFKit API) products. In terms of technology, we use Elixir as a programming language, but we also need to have some running knowledge of a fairly wide array of technologies that are part of our tech stack. This includes Docker for running containers, PostgreSQL for databases, Amazon Web Services for infrastructure, and an assortment of frontend technologies such as Tailwind CSS and Alpine.js for building websites for our cloud products.
Coming from a mobile development background meant I had a fair bit of “baggage” I brought with me to the position, such as having a certain expectations about performance, battery usage, building UIs, being offline first, etc. It also meant I missed gaining professional-level experience of many topics, including fundamentals like databases (yes, we use SQLite on Android, but our use cases are generally fairly simple), cloud, UI design systems other than Material Design, etc.
Learning a New Technology
Fragile toolsets — Dependency updates seemed like a huge pain, the build process was fairly obtuse, and most of the CLI tools broke with cryptic error messages.
Lesser IDE support — Non-statically typed languages lead to lower quality IDEs/text editors, resulting in problems such as code completion that isn’t completely reliable, problematic automated refactoring, etc.
As you can see, I needed to learn (and get used to) a lot to be a fully functional web developer. So now I’ll share an assortment of tips that worked for me. Not all of these are applicable to everyone, but the idea is to give you some inspiration for your own learning process.
Focus On What’s Important
Once I switched teams, I wanted to be at least somewhat productive as quickly as possible. This meant I needed to be very pragmatic about how I learned. My initial goal was to get wide coverage of the new platform and necessary tools as fast as possible. And then, only after I felt comfortable with the basics would I dig into the details.
The situation was much simpler when I made a switch to the Server team (as opposed to my switch from Android to web), because the Elixir ecosystem is still fairly new (the language is around 10 years old) and has a much smaller community of people building libraries and tools for it. In this case, I could focus on learning the Elixir language first and dive into platform and library details over time as I worked on real tasks.
New Programming Language
The Pragmatic Programmer book recommends you learn a programming language every year. Learning new languages — especially ones outside your comfort zone — is useful because:
It gives you another skill you might use in your current job or personal project. It might even prove useful in interviews for your next job.
It expands your repertoire of useful abstractions/concepts. In turn, novel approaches provided by each language might prove useful for solving problems in your own language. For example, I learned some basics of logical and functional programming during my university studies, and these proved very useful many years later when RxJava became popular in Android world — learning it while already having a good “mental model” of the functional processing pipelines allowed me to learn it almost no time. RxJava in turn helped me with functional-style coding in Elixir, so my knowledge came “full circle” here.
It might get you involved in a new community. This is especially true with more niche languages, as their communities are generally very helpful and motivated, since they want to see the language succeed. This, in turn, inspires people to join those communities to get involved and help contribute to their development.
I enjoy learning new languages. I especially like learning about new and interesting concepts these languages use. However, I struggle a lot with internalizing a syntax of a new language. This is a limitation of a way my brain works (I’m not particularly good at learning real-world languages either). I feel that my skills in this area got worse because of me working in Java for many years. By this, I mean that Java is a fairly verbose language with very minimal syntax and almost no syntactic sugar around it, and Java IDEs provide 100-percent-reliable code completion, which makes it very convenient to rely on them extensively without being forced to internalize the “vocabulary” (i.e. API names) in detail.
Because I struggle with syntax, I extensively rely on cheatsheets whenever I work in a language that I’m either learning from scratch or haven’t used for a long time. I also create snippets for “code templates,” such as templates that generate empty unit test cases. One of the most used cheatsheets is this Bash scripting cheatsheet. This fits my intended usage of cheatsheets — i.e. I’m not writing a new Bash script daily, so even if I’m fluent in it, I still rely on the cheatsheet for constructs that I forget all the time (like where should I write
; in control structures).
There are many decent tutorials to learn any language, both in the form of written articles and videos. However, I generally find these distracting. What works the best for me are books. To maintain focus, I usually read these books first without switching to a computer and trying any example code. This initial read gives me some time to not only think about the underlying concepts that are new to me in a given language, but also to get a broad idea of features provided by a language and its standard library. Once I’m done with the initial read, I like to go through the topics again and experiment with the various language features live. I especially like when the new language has a REPL shell where I can run code interactively. In the case of Elixir, I still use its code notebook (Livebook) — which is basically a REPL on steroids — to debug more complex code.
Working with an Existing Codebase
Even if you don’t switch technologies, you’ll still need to get used to a new codebase when switching projects. Since I did both at the same time, the new codebase provided me with a very hands-on language and platform learning experience. After having some initial knowledge of the underlying programming language, I picked up a lot of skills just by navigating through the codebase and learning from it.
One important technique that I use fairly often when I’m confronted with new code (be it a totally new codebase or investigating a bug in a part of code that I’m not familiar with) is to debug it live. This ranges from putting logs and using breakpoints and step debugging interesting parts of the code to executing code in REPL to change the app’s state. “Probing” into a live system is much more efficient than trying to understand the code just by reading it.
I didn’t rely solely on self-learning though. We do regular pairing sessions within the team, which we also use to get new people (such as me) up to speed with the codebase, its architecture, and problematic or otherwise interesting code paths. This is a fairly inexpensive way of onboarding new team members, and I can strongly recommend you try it in your own team.
Once I start working in the new codebase and writing new code, I always check to see how a certain concept is handled in an existing part of the codebase. And if I’m not happy with the solution, I raise the topic with the team. This allows us to maintain the existing code style and internal code design.
We have a mandatory code review policy here at PSPDFKit. This means that any code that makes it to our products needs to be reviewed by at least one additional member of the team. The main goal of reviews is improving code quality and catching issues early. However, reviewing is also useful as a tool that facilitates learning.
I always make an effort to review as much code as possible. When I was starting, I even reviewed code that had already been reviewed by others and merged. Doing reviews helps me learn:
Practical skills in the new programming language, its standard library, and any other third-party dependencies.
Insight into thinking of team members (many times more senior), including interesting ways to solve different problems.
Internalizing best practices and code style used in the company/team and an accepted “standard” way of doing things in the given language.
If you don’t participate in reviews yet, you should start as soon as possible. Don’t worry if you feel you can’t provide much value in your reviews. This feeling will most definitely disappear soon. And hey, you still have an inexpensive and effective learning tool from the start.
We at PSPDFKit treat our customer support experience seriously. We have a dedicated first-level support team that serves as the point of first contact with our customers. But some support requests require in-depth knowledge of the product and platform, which is why our engineers are also involved when handling technical customer support.
Personally, I always found support work to be a very rewarding experience. Of course, you get a feeling that you’re helping someone in their job. But you also get a lot personal value in the form of building your experience and technical skills — for example, this might be an introduction to a technology (e.g. language, framework, environment) the customer is using.
I especially saw this aspect of support when providing support for our Web SDK. Our customers use a large distribution of both frontend and backend technologies, and this forced me to pick up at least basic skills to be able to help them.
Picking the Right Tools for the Job
The nature of tools in the web ecosystem is way more fragmented than in self-contained platforms like Android. Because of this, I initially struggled with making sense of the tooling — in particular, it was a challenge to get used to the quirks of the Node.js toolset and set up my IDE/text editor to use as my daily driver. I focused a lot on this aspect, as I constantly felt like I wasn’t using the right tools and that my productivity suffered because of it.
This section contains tips that worked for me and allowed me to feel almost as productive as I did during my Android development days.
Text Editor/IDE Setup
I’m fan of IntelliJ IDEs, and as an Android developer, I’ve used Android Studio since its early versions. Subjectively, I find them superior to any other IDE I’ve used before (Eclipse, Visual Studio, Xcode), as well as any modern text editor (Atom, Visual Studio Code). They strike a good balance in providing minimal distraction while editing code, while at the same time providing rich IDE-like features such as powerful code completion, live code analysis, reliable refactoring tools, integrated test running and debugging, and more.
It’s not surprising that I picked up IntelliJ’s WebStorm IDE when I moved to the Web team. It served me well during my time there, and it helped me be relatively productive fairly quickly by abstracting some of the new workflows that I wasn’t used to as a mobile developer. For example, in Android land, you don’t need to remember CLI commands to run your tests, filter to a specific test, or debug tests. This is all a matter of a few mouse clicks or keyboard shortcuts in Android Studio. On top of that, you also get a clear UI that displays the test results per test case instead of a blob of terminal output.
After making a switch to working in Elixir, my IDE situation got much worse. Elixir is a relatively niche language, and its IDE support is still lacking. After experimenting with the Elixir support plugin for IntelliJ IDEs, I realized the best option is to not fight it and simply switch to a text editor. In my case, I already used Visual Studio Code as my text editor of choice, and it had a decent Elixir extension. This was the first time I did any proper development in the text editor, so I needed to get used to it. This meant relearning my shortcut muscle memory and getting used to using the terminal for more and more tasks that were simply not possible without an IDE.
I’ve now been using Visual Studio Code as my main development environment for about a year, and I can safely say I’ve gotten used to it. However, I’m still missing nice test outputs and solid refactoring and debugging support.
Node.js and its tools such as package managers (npm and yarn) work great on Unix-like command-line shells. Since I already worked on macOS, these tools worked nicely out of the box. If you’re using Windows, you should get a very nice experience by installing and using the Windows Subsystem for Linux, which lets you run a full GNU/Linux environment directly on Windows without managing your own virtual machines.
I was an intermediate terminal user already, so the CLI nature of these tools didn’t cause many issues for me. However, if you struggle with this, I strongly recommend strengthening your terminal skills as you would any other developer skill. The barrier of entry isn’t that high, as you don’t need to know much to get started, and the experience will give you more confidence over time.
In terms of setting up your shell/terminal for web development, I believe that the most important thing is to start using a tool version manager such as asdf. The goal of this tool is to allow you to run a set of runtime versions side by side on a single machine. So, instead of installing Node.js globally, you can configure the version on a per-project basis and easily switch between multiple versions that you might have installed at the same time. This has an obvious benefit where you can work with different projects without being forced to use the same version in each of them. Another great aspect of this is that you won’t be breaking your system-level runtime, which might be used by your system and could lead to incompatibility issues.
For additional productivity tips about setting up your terminal, refer to our blog post on the terminal setups of PSPDFKit, where we collected information about the terminal setups of multiple PSPDFKit engineers.
After spending these past two-plus years as a web/backend developer, I can now say I feel like a productive member of the team. This whole “experiment” was a great way to expand my development skills beyond what I ever considered possible and to get much deeper insight into my personal learning process. I can now think about considering myself a true polyglot developer (per my subjective definition outlined above).
This was also an exercise in humility. Being an expert and switching to an alien environment and tech stack was definitely stressful. I see benefits here though: If we didn’t ever go outside of our comfort zones, we’d never grow as professionals and (more importantly) people.
I hope this article might make you think outside of the bounds of your current environment of choice. After all, picking up new skills is of utmost importance in our field of work. Even if you don’t feel that you need a particular skill now, if something new interests you, try to follow that feeling — you never know what opportunities this particular skill might open to you in the future.