In 2015, I joined a startup called Landdox. I was the first employee. In fact, I joined Landdox before it officially became a company. Since then, the application has grown from an idea designed in Sketch by the founder to a fruitful large application with a customer base.
It has been an intense nearly 2 years and I wanted to share a few things I’ve learned. Some that have hit me over the nose and others that pleasantly surprised me as well.
As a side note, we’re currently hiring.
My role and the company
Before I get into the learnings, let me just review my role at the company as well as what we do. I’m a Senior Engineer. Fancy title aside, I’m responsible for the back-end, the front-end, the DevOps, hiring, and well, a slew of other things. I like to call myself the “CTO-in-training” (I don’t and I’m not, but it seems fitting to the narrative. Edit: I feel like I have to emphasize this. I’m not the CTO and I’m not up for the role either. I’d remove the line but there are already some comments on this). I’m that “wearing many hats” developer that was able to build the first prototype of the app that “beta” customers were able to test out. A few months into the work, we were able to hire another developer so my role slowly evolved to include code reviews, developer experience, mentoring, and other similar tasks.
Today, I tend to handle what I have the most experience with: new feature development for complicated features, debugging stubborn bugs, and DevOps. That’s not to say that I get to handle all of it (my co-worker Julien gets to play around with maps all day, something I know nearly nothing about, and he also dives into new feature development and debugging stubborn bugs). I hope that gives you an insight into what I do.
As far as the company, we’re a Land Document Management system. To put it shortly (and avoid NDA crap), imagine a Dropbox-like app that also helps you track the land you actually own and the contracts you’ve signed that give you rights to the land as an energy company.
Top X Things I’ve Learned
I thought I’d write a nice narrative but in the end, a list seems more appropriate
Tracers over Prototypes
A year or two ago, I started reading a book called the Pragmatic Programmer. It introduced me to a concept called a “tracer”. A “Tracer” is an MVP-like idea for just one feature. Basically, instead of writing a prototype, I write a small permanent program instead. Prototyping is great but often doesn’t work in a fast-paced environment where no one has time to build features or architecture that will disappear once the work is done. Prototyping is meant to figure out the strong and weak points of an idea. A tracer is built the stay.
The initial architecture for Landdox was written in January and February of last year. It was meant to be a prototype that we’d quickly show off and build it properly later. The “build it properly later” never happened. Not only due to time constraints but because the prototype was “good enough”. There is still a good chunk of code from back then that has never been rewritten. It taught me a valuable lesson: you can’t always depend on being able to build a pure prototype that can be thrown away. Sometimes, you’ll get stuck with what you build. And when there is even the slightest hint that this might happen, build a tracer instead.
Everything is legacy a week later
Going from IIFE to Browserify meant touching EVERY SINGLE JS FILE in the system and removing the IIFE. It also meant implementing require. Which meant we had to get packages from NPM rather than Bower. Oh joy.
When we switched to ES2015, it meant that we could finally use imports and lots of other features but at 10K lines of code, it was unthinkable trying to go back and update everything. So we’re still updating code to this day. That’s almost a year later.
Technology moves quickly and there are great reasons to move forward with it, the problem is that the codebase is a little slower. When we started using
Object.assign, it meant that we could either remove certain parts of lodash (namely
.extend) or remove
angular.copy. The latter was more important for packages that slowly migrated their way to be universally used across back-end and front-end.
Updating things as you go also means that parts of the application that get less love tend to be written with an older style (perhaps one that doesn’t adhere to the latest estlint updates), with older ideas in mind, and using older technology (like
indexOf rather than
contains or a for loop rather than reduce).
The only way to deal with this is to accept that this will always be true and truly, update only when touching a file. Whenever I go in to fix a bug or to develop a new feature, I try to fix the eslint issues in any file I touch, update methods, and rewrite what’s necessary (unless it’s a BIG hassle).
Slow and steady on big projects; move fast and break things on smaller projects
By now, even if I switched to React, I’d still be lagging behind. VueJS is making rounds, Elm is the best thing on the market, and Angular 2 is rearing its head with all of its amazing functionality. On top of that, data management flow is just out of control. Redux is still the “big thing” but the “hot” libraries on the block are MobX, RxJS, and many others. It’s impossible to keep up. Which is why I don’t and why it’s a bad idea to try on a larger project.
But wait, there’s more! You see, when these libraries come out, it’s not just a matter of switching but it’s a matter of figuring out best practices. And best practices usually naturally come out a year or several after the framework/library makes its rounds. We’re only now settling down on how React applications should be built. Last year, developers finally came out with the defacto way of building Angular 1.X applications (and with the release of 1.5, it was solidified). VueJS 2.0.0 just came out and so did Angular 2.0.0 but “best practices” aren’t nowhere near understood.
That’s why I suggest this: use the tried and true way for your main/core project. Your core should be solid, you should have a solid understanding of it, and you should know not only its benefits but its detractors as well. Well-established frameworks bring all of this and, hopefully, a community of knowledgeable developers to help out. You don’t want any surprise, and you definitely don’t want to be a year into developer just to realize that this framework doesn’t work for your usecase and can’t be adapter. Or you don’t know how to adapt it.
For smaller projects like microservices, isolated applications, even parts of the UI that most users don’t see, experiment. We have a couple of microservices that we’re playing around with that are getting this treatment. I’ve heard of bigger companies also implementing new UI frameworks this way by either rewriting a back-end dashboard, or a small part of the app, using the library. Elm is apparently perfect for this and people start with rewriting smaller components in Elm and hooking it up to their existing infrastructure.
TypeScript has support for incremental upgrades as well and so does Flow (if you want typechecking without a compiler). Be free and experiment on these projects but leave the core alone.
Project Management Is Key
I’ve never been into project management, mostly because of my bad experiences with it. PM had always been synonymous with “micromanaging” for me. I’ve had to keep track of my time to the minute before and having to justify every single one of those minutes. I’ve also run into endless to-do lists, unclear communication, or using PM as more of a “formality” or a “messaging” tool with the management. I’ve been starkly against it.
Well, I changed my mind this year. We kept most of our backlog in Trello and that worked out okay. Due to ever-changing priorities, the order in that list never really mattered but having a separate “in process” list and a “done” list kept communications somewhat opened between the development and the management (we’re talking about 3 people here). But even at our small scale, we always ran into communication issues, namely:
- Why has something been “in process” for a month?
- What are you REALLY working on next?
- If it’s done, is it on staging? Or is it in production? Or did you just “finish” it but never pushed it to be tested?
- It says “document” bug, what does that mean?
The issues started to pile when we worked with contractors and started to build up a huge backlog, a huge bug list, and individual “to do” lists between all of the developers. There was also the issue of having Trello cards that were just way too big. Imagine an entire feature encompassed in a single card.
Not only was it confusing to management but it was confusing to us developers. I was never sure what I was working on, I could never really gauge my own progress on a feature.
But then one day, we hired a guy to contract for us and he introduced us to Pivotal Tracker, agile development, and project management that blew ambiguity out of the water. We ended up gaining all kinds of interesting benefits from it but here’s a quick list:
- developer subtasks (such as “implement back-end API fetching” and “implement back-end API processing”) became their own stories rather than being lumped with “implement feature” so we knew exactly where to go next.
- management could see overall large feature progress via “epics”. This meant that we could visibly see progress without having Uber-tasks.
- checking off items one by one helped us keep up a momentum. It was easier to work harder and faster when you felt like there was progress.
- PT’s “velocity” tracker gave us a good goal each week as to how much work needed to be done. I’m somewhere at 15-20 points a week. That means I need to do 3-4 points a day. That’s an achievable goal.
- Seeing the ratio of points vs “stories completed” gave us a good idea as to how much time we spent developing new features vs. how much time we spent bug-fixing (and we spent a lot of time bug fixing).
If you’re using PM at work and it’s not working out for you, I’d look into why that is. We basically had no idea what to do to fix our issues until someone came along and said “Here’s how I do it and it might be a better solution to your problems”.
Code style keeps the codebase happy
Over the course of the year, our ESLint ruleset grew from a handful of rules to a pretty sizeable rulesheet. And I’ve no regrets. I’ve never been a stickler for code style until I had to dive into other people’s complicated code and that’s when I realized that some of the extra spaces, newlines, and consistent indentation made a world of a difference.
With codestyle, it’s important to keep the following in mind:
- ease of adherence. How easy is it to follow the rules? Is it presenting an obstacle to the developer or is it helping?
- legibility. Probably the #1 reason to adhere to a codestyle you’re happy with is legibility. It’s a subjective term but getting the entire team to mostly agree on one style helps a lot. Will you use semi-colons? How about use of whitespace? Four or two indentations?
- architecture for the sake of codestyle is bad codestyle. Codestyle shouldn’t compromise code architecture. Small modules are great and all but having hundreds of module may not be right for your project. Sticking to 2 argument functions (or less) shouldn’t force a developer to create an “options” object or the use of heavily nested functions.
- it’s okay to bend the rules. Sometimes, it’s just necessary.
- codebase trends can become codestyle rules.
- it’s easier to contribute to a standardized codebase. A codebase that follows clear rules makes it also much easier to contribute to. Automated codestyle checker makes this even easier.
Developer experience increases productivity
We often discuss the UX of the website or product, using testing to keep things chugging along, and so on. But over the past few years, there has been a new buzzword making its rounds: developer experience. It’s an idea that having a comfortable workflow increases productivity and developer happiness. The easier it is to work and to keep moving things forward, the more you’ll be motivated to do so.
One of the first things I did when setting up Landdox was implement Gulp for file watching and file building. Not having to deal with manual compilation or remembering to recompile when saving a file has been immensely helpful. Using Browserify to compile modules together was another positive step. Implementing ES2015 made the codebase fun to use.
It’s hard justifying time for developer experience, you’ve got a product to push out after all, but certain DX features (can I…can I coin that term?) help accelerate product development. When we added automated deployments to our workflow, we saved hours and hours of troubleshooting deployment software, trying to carve out “deployment” time and communicating this with whomever tests the changes. In fact, we deploy to staging constantly throughout the day. Production gets more deployments as well because all it takes is merging in a branch into development or master.
Adding to that comprehensive notification system (for error alerts and deployment alerts), we found ourselves never checking the progress of a deployment or even installing deployment software on our machines.
But wait…is there more?
Of course, there is. And I have tons more to talk about but I think the post has gone on long enough.