269 karma · joined September 18, 2016
1. IaC for the network, database, container definitions, and other cloud things. I use terraform here. 2. CI/CD for the application software, which ultimately builds a container image from version control, tags it in some well-know way, and tells the container scheduler to redeploy. I tend to use CircleCI, but any CI solution will do. 3. Configuration management for my container definitions, injecting environment variables for config/secrets into the definition or runtime. I tend to use Ansible or Terraform here.
For me, the main criteria is whether the product has a large number of components with configuration that needs to reuse common structures. If I'm just deploying one or two components (e.g. your typical early-stage monolith), Terraform is fine. Bt if you have many users contributing to many components and want to provide higher-level tools, I vastly prefer using Ansible; you just have more control.
That is, I believe in Ansible as a tool for applying configuration from source control to some other system; I would no longer use it to provision cloud resources.
I can run PostgreSQL myself but there's a ton that goes into running it with redundancy, backup, encryption, etc that takes deep expertise to well. I know from experience that it's easy to get database failover wrong. I could probably cobble something together, but it would be mediocre and wouldn't handle network partitions reliably. On the other hand, RDS is used at a scale well beyond what I could afford to build out and has benefitted from much more usage. Problems that are low probability for me are regular events for RDS and have that experience built in.
Ultimately, you are paying a cloud vendor for service value and operational experience. Some services aren't as good as others in both regards, but for the ones that are good, the overhead of doing it yourself is an exponent, not a fraction.
Plus I've seen more than a few efforts at multi-cloud that resulted in a strong dependency on all clouds vs the ability to switch between them. So not only do you not get to use cloud-specific services, you don't really get any benefit in terms of decoupling.
There are obviously plenty of companies that are willing to couple themselves to a single cloud vendor (e.g. Netflix with AWS) and plenty of business continuity risks that companies don't find cost effective to pursue. Has anyone been as vocal about decoupling from CRM or ERB systems as they are with cloud?
My own view is that these kinds of infrastructure projects create as many risks as the solve and happen at least as much because engineers like to solve these kinds of problems than for any other reason.
The optionality of being cloud agnostic comes with a huge cost, both because of all the pieces you have to build+operate and because of the functionality you have to exclude from your systems.
I am sure there are scales where you either have such a large engineering budget that you can ignore these costs or where decreasing your cloud spend is the only way to scale your business. But for the average company, I can't see how spending so much on infrastructure (and future optionality) pays off, especially when you could spend on product or marketing or anything else that has a more direct impact on your success.
In my own experience:
- AWS SNS and SQS are rock solid and provide excellent foundations for distributed systems. I know I would struggle to create the same level of reliability if I wrote my own publish-subscribe primitives and I've played enough with some of the open source alternatives to know they require operational costs that I don't want to pay.
- I use EC2 some of the time (e.g. when I need GPUs), but I prefer to use containers because they offer a superior solution for reproducible installation. I tend to use ECS because I don't want to take on the complexity of K8S and it offers me enough to have reliable, load-balanced services. ECS with Fargate is a great building block for many, run-of-the-mill services (e.g. no GPU, not crazy resource usages).
- Lambda is incredibly useful as glue between systems. I use Lambda to connect S3, SES, CloudWatch, and SQS to application code. I've also gone without Lambda on the SQS side and written my framework layers to dispatch messages to application code. This has advantages (e.g. finer-grain backoff control) but isn't worth it for smaller projects.
- Secrets manager is a nice foundational component. There are alternatives out there, but it integrates so well with ECS that I rarely consider them.
- RDS is terrific. In a past life, I spent time writing database failover logic and it was way too hard to get right consistently. I love not having to think about it. Plus encryption, backup, and monitoring are all batteries included.
- VPC networking is essential. I've seen too many setups that just use the default VPC and run an EC2 instance on a public IP. The horror.
- I've recently started to appreciate the value of Step Functions. When I write distributed systems, I tend to end up with a number of discrete components that each handle one part of a problem domain. This works, but creates understandability problems. I don't love writing Step Functions using a JSON grammar that isn't easy to test locally, but I find that the visibility they offer in terms of tracing a workflow is very nice.
- CloudFront isn't the best CDN, but it is often good enough. I tend to use it for frontend application hosting (along with S3, Route53, and ACM).
- CloudWatch is hard to avoid, though I rather dislike it. CloudWatch rules are useful for implementing cron-like triggers and detecting events in AWS systems, for example knowing whether EC2 failed to provision spot capacity.
- I have mixed feeling about DynamoDB as well. It offers a nice set of primitives and is often easier to starting use for small projects than something like RDS, but I rarely operate at the scales where it's a better solution than something like RDS PostgreSQL with all the terrific libraries and frameworks that work with it.
- At some scale, you want to segregate AWS resources across different accounts, usually with SSO and some level of automated provisioning. You can't escape IAM here and Control Tower is a pretty nice solution element as well.
I'm not sure if I'm up to 20 services yet, but it's probably close enough to answer your question. There are better and worse services out there, but you can get a lot of business value by making the right trade-offs, both because you get something that would be hard to build with the same level of reliability and security and because you can spend your time writing software that speaks more directly to product needs.
As for "having a fantastic time", YMMV. I am a huge fan of Terraform and tend to enjoy developing at that level. The solutions I've built provide building blocks for development teams who mostly don't have to think about the services.
The best engineering teams are excellent at execution, but you need something more to choose the right problems.
From my experience, I've run into a few challenges with some of the claims
For 1: If engineers always operate their code, you will end up with an organization structure built around "these developers work on (and operate) this code." That might be what you want, but it's often not what I want. There are going to be some part of the code base that don't change very much and I'd rather not have a specific team perpetually taxed with operating it (instead of building new business value). Likewise, there are some engineers who are much more productive at building new things (and not just in the the crappy, "now it's your problem way"). I don't want those engineers to have a larger share of operations because they are more productive at development. Support-focused roles have value.
For 5: I have never seen a maintainable automated test suite. I'm sure they exist somewhere, just not in my experience, and I've never worked with anyone who knew how to ensure that developers create one. This means that, with purely-automated testing, your development costs can become dominated by "fixing the tests." My preference is to automate the most important things and to have have humans, with judgement, test behaviors based on test cases written in English.
I really liked the concept and we borrowed the "triple" approach in our next iterations, but we really didn't get any benefit from using RDF.
Quite possible it was our fault.
I'd assume that most anyone building a system like this at scale has to solve these problems; does everyone roll their own?
One of the ways I've seen DRY go horribly wrong involves reusable code units evolving into shared dependencies that often interdepend in complex ways. Unfortunately, the problems of such a system are observed much later than the original code duplication and fewer people have the experience to see it coming.
Useful for technical searches, where ddg is sadly, not good enough.
I've seen staged releases work quite well at multiple companies and fail miserably at some others.
That said, continuous deployment is the right choice in many/most contexts. I'd just prefer that people see it as a choice instead of assuming that it's the only way that can work.
The decision to always be backwards compatible is just that, a decision. It comes with some really nice benefits around CI/CD, but also adds overhead for certain kinds of development, especially if data models are evolving rapidly. I've been in situations where we made the explicit decision not be backwards compatible due to business context that prioritized these evolutions.
Likewise, deploying to production continuously is not always an option. I've been in situations where customer relationships (contractual or otherwise) require that changes not be made continuously. Accidental outages or regressions are simply not an acceptable risk in some business contexts.
However many developers can correctly follow the meager instructions to validate a token, the number who will properly implement a full auth system is even smaller...
I've been developing professionally for 19+ years, primarily at small-to-medium sized startups. I switched gears this year to find better life-work balance, providing part-time consulting to several companies. I'm ready to switch back to working on a single thing, preferably still part time. I prioritize good people and flexibility over most other things.
I think the first step here is to get away from the assumption that importing a module will have "interesting" side effects. This is not only a problem with Python...
I tend to create mini "dependency injection" frameworks that create a pattern for loading module code at some point well after import. This patterns tends to reduce to wrapping whatever code you have in the module in a function/closure instead of just running whenever.
Again, I like the idea of enforcing constraints with code, but I don't think it's a substitute for educating developers to avoid certain patterns and giving them infrastructure that makes the alternative easy.
Our executive management was very savvy and negotiated that the acquiring company couldn't interfere with our operations for the first year in any way that could threaten our meeting the earn out goals.
The net effect was just weird. In many ways, nothing really changed for a year. In other ways, everything kind of ground to a halt because there was no motivation to do anything and no new management to steer.
I left at the end of the year.
I don't have the experience with Kubernetes to have an informed opinion, but I've solved plenty of social problems in software organizations. Those are usually approachable without making a long-term commitment to a technology that may or may not be the right choice.
I also find that these discussions matter less in microservices because the size of each service is so small that you usually don't need more than two layers: one for business logic and one for persistence.
I very much agree that microservices create their own challenges at service interfaces, but since these boundaries are usually expressed as http operations instead of object oriented function calls, I look for different solutions, especially various forms of system-wide introspection and testing.
I've seen Slack work when there is both intention to how channels are organized and leadership nudging people to follow these intensions.