How do you keep on top of your game as a full-stack programmer? Should you learn the theory or the practice? What skills do you really need as a full-stacker? Should you go deep into one subject area, or stay across as many as possible?
In this article, Tiny's software architect, Dylan Just, provides his perspective, emphasizing a balanced approach to learning.
Theory and practice
As a software architect and die-hard full-stacker, keeping up with different skills is a challenge I'm all too familiar with. There's a lot to learn, so it's important to build up your ability to learn, and to always be open to new knowledge. I find that theory is a great scaffold for new knowledge, and the balance of theory and practice is crucial. Theory guides practice, and practice refines theory.
I don't know much React, Vue, or Angular, but I do know the fundamental concepts of Functional Reactive Programming upon which they're based. With this theory backing, I can read about these frameworks and map them back to the theoretical concepts. I have a background and starting point from which to graft knowledge as I learn them.
An understanding of type theory and language theory lets me learn languages quickly. I can scan a manual or website and identify aspects such as: is it statically-typed; does it have generics; does it have custom operators; does it have type inference; does it have higher-kinded types? Given this information, I can form a pattern in my mind of what the language is capable of, how I might program in it, and how other users of the language may program in it.
For example, if a language has type inference that isn't total (like in TypeScript), I know I have to be liberal with spreading type annotations throughout the codebase, or I'll hit edge cases that it can't infer. If I know a language is dynamically-typed, I'll keep my functions small and add more tests than I would in a statically-typed language. If the language has higher-kinded types, I know I can use Monads for composing sequences of operations that may fail, but if it doesn't, I might be more inclined to use async..await or to throw exceptions.
Similarly with sysadmin. My background is in physical networks, then with VMware. But I know the concepts and trade-offs of virtualization, containerization and serverless architectures, so I can work in AWS or Azure fine.
People say there is a lot to learn, but that's only partially true. There are a lot of frameworks/libraries/technologies, but far fewer designs/patterns/architectures/concepts. Fundamentally-new ideas don't actually come along that frequently. Learn the concepts and the theories, and map them to concrete technologies.
I'm not suggesting that you ignore practice, though. You do need to actually wield these technologies - you have to get your hands dirty to truly learn the intricacies, and validate assumptions you have made in your mental model. You need the battle scars. You need to actually try things and evaluate technologies critically. Did this technology do what it said on the tin? Is it a good implementation of this concept? Knowing what I do now, would I have chosen it next time? Does my experience with this technology validate or invalidate the theory behind it?
12 essential skills for full-stack developers
For me, the crucial skills for a full-stack programmer are:
- Ability to learn - because you can't know everything at the outset of a project.
- General problem-solving - to analyze requirements and creatively design solutions for them.
- Critical thinking - critically evaluate techniques, technologies and solutions, and be able to reflect on experiences.
- Functional programming - a very powerful approach to programming that has immense benefits for correctness and maintainability.
- Functional reactive programming - the language of events, streams, and behaviors that inspires many modern UI frameworks.
- Type systems - the logic of programming, and a core distinguishing feature of any language.
- Property-based testing - a superpower for crushing edge cases.
- Databases - know the ACID and CAP properties and the relevant trade-offs for your system.
- Virtualization and containerization - these are ubiquitous and most programmers need a working knowledge of them.
- Fault-tolerant design - how does your system gracefully handle bugs and crashes?
- Computer networking basics - the glue of any connected app, and not just the domain of the back-end.
- The art of making trade-offs - no technology is perfect, but what really matters for your system?
Notice I didn't mention a single framework or programming language in that list. These are all general concepts that apply to many different specific technologies.
Learning and specialization
I find it's also useful to reject the fear of learning or the feeling of it being overwhelming. Embrace it. Relish in that feeling of being a complete newbie, as it's an opportunity to learn. Never say "I can't do that" or "I can't learn that". Throw out your "too hard basket" and dive in. Read, learn, ask questions and do.
Don't label yourself an "AWS guy" or a "Java programmer" or a "front-end dev". You are a person: unique, intelligent, capable of learning anything you put your mind to. Pigeon-holing yourself with a specific set of skills closes your mind. Focus and specialization is fine, but I've never met a programmer that couldn't learn another language.
I suspect the rise of full-stack is partly an acknowledgment that many engineers see value in learning the full context of where software fits in, and find that their skills are general enough that they apply to many different problems. Companies are wanting to hire engineers that are flexible, and can use their general problem-solving skills to solve the task at hand, rather than throwing their hands up if the right solution calls for something that's not their specialty.
There has been some backlash to the full-stack movement, though. Some developers feel like it puts unrealistic expectations on developers - that they're expected to be experts at everything. Some feel that it encourages shallow knowledge, and that it discourages specialization and true mastery. This article (https://blog.hackerrank.com/full-stack-developer/) has a good summary of the history and debate over the term "full-stack developer".
Specialization is a valid and useful strategy for an engineering career. In a team, you need that one battle-hardened engineer that knows every tiny last detail about CSS or Docker or C# or Linux and you just need them to go hard. Specialization is a viable and useful career strategy. Just be aware that it comes with risks. I used to be a Cold Fusion developer, and specializing in that would have been a dead-end for me. If you want to specialize, you need to be sure you specialize in an area that will support your career going forward, or be able to switch to another specialty far enough in advance.
Regardless of your mix of depth and breadth, there are always new things to learn. Getting better at learning is essential. For that, I think you need to know your learning style - how do you best acquire knowledge? You also need to be critical and reflective in your learning. What did I really learn? How does this fit into the context of what I already learned? When you're writing code, find time to reflect - how well did this design turn out in practice? Can I learn something from this experience for next time?
Personally, rather than treating depth vs breadth as a trade-off, I treat it as a challenge. I find that attitude keeps my mind open and ready to absorb knowledge.
If you'd like to read more from Tiny, including development tips, plus information about how to enhance the UX of your apps with the TinyMCE rich text editor, sign up below to receive our developer newsletter, check out more of our blog, or follow us on Twitter.