When developing an application there are multiple things we should focus on to make our life easier and more pleasant. In this post I describe couple of areas I personally find important.
Have you ever entered a project just to realize you can’t compile it in one day? Or have you ever struggled with running your application locally or even in your office setup? Maybe you worked in an environment where it’s impossible to test things before going to production? That’s what I’m talking about.
When I think about a good developer experience I typically have these things in mind:
- I want to be able to work entirely offline. It’s not that I’m going to do that all the times, but I want to be able to develop the application while on a plane with little to no Internet connection
- I want to test my application on my box only. This can be via unit tests (ideally in less than a second), integration tests or manually. But I want to be able to do so
- I want to run my application locally with all services running on my box. I don’t care if I need to compile them or if I can use docker/VMs (while the latter is preferred) but I want to do it
- I want to run my service only and not need to run other dependencies on my box. This may sound contradictory to the previous statement but it does make sense – I want to keep it simple. I want to open one project and run it (and have all dependencies deployed to some preprod environments) but if I need I want to be able to run any dependency locally, debug it etc
- I want to have an IDE with full syntax support
- I want to have a good local debugger and be able to debug everything (backend code, frontend etc)
- I want to be able to attach proxy, network monitor, wireshark and others
- I want to be able to connect to the cloud resources directly from my box and be able to debug them (so have a nice remote debugger)
- I want to be able to work from any Internet connection – some VPN may be required. Ideally if it’s a split tunneling type
- I want to have a remote machine integrated with Intranet which I can connect to anytime and work from there – again, this may sound contradictory but it’s about choosing. I want to be able to babysit something while sitting at a lake and having mobile phone, don’t want to have hot laptop on my desk nor loud fan spinning 24/7
Sounds trivial but you may be surprised how many apps are built in a way which makes some or all things above impossible. Developers are forced to work on constrained remote machines, can’t run applications locally, can’t debug anything.
Another important area is how to test an application before pushing changes to a remote repository or to production. This includes the following:
- Fast tests confirming the business logic works – unit tests or whatever you name them. They should finish in matter of milliseconds ideally, couple seconds at most
- Tests actually confirming whole application works – with all dependencies in place, services up and running, authorization/authentication/tokens/security enabled, with network calls and databases, not mocks
- Comparison tests – to make sure I don’t break any existing functionality
- Performance tests, load tests, stress tests
- Penetration tests
- Tests for non-functional requirements
It’s essential to be able to run tests locally. While I’m not going to run performance tests every minute, I want to be able to do it to see how my app behaves under heavy load. However, I am going to run unit tests every other minute.
On the other hand, I don’t want to run all these things on my machine. I want to just push a feature branch to the repository and have it picked up by some testing agent which creates everything from scratch, runs all tests and confirms everything is fine. This should be done automatically.
I want to have my changes deployed automatically once they are merged to the main branch. They should be tested automatically (see previous section) with all test suites I have and then deployed to all boxes, with baking stage, time windows avoiding peaks or bank holidays, and rolled back automatically if needed. No manual actions should be needed.
There are couple things which need to be in place when the application is launched. For logging, this includes:
- Vector clock and correlation id
- Activity name
- Machine id
- Process id
- Thread/threads/fibers/async contexts id
All these things are useful, especially when working with memory dumps.
For metrics, the following pieces should be available:
- Ability to group metrics, aggregate them, calculate min/max/average/percentiles/windows
- Alarms and notifications based on metrics
- Automated rollbacks based on metrics
- Disabled deployments based on alarms
Also, dashboards showing service health should be in place as well.