18 ms·
Many of these practices are popularized by Google/Facebook/Amazon but don't make sense for a company with 100 or even 1,000 people. I try to focus on whether a
by SatvikBeri 10y ago
Many of these practices are popularized by Google/Facebook/Amazon but don't make sense for a company with 100 or even 1,000 people. I try to focus on whether a practice will solve a concrete problem we're facing.
Switching from Hadoop to Spark was clearly a good idea for our team, even though it required learning a new stack, but there isn't a strong reason to switch to Flink or start using Haskell.
Agile makes sense when your main risk is fine-grained details of user requirements, but not when you have other substantial risks, such as making sure a statistical algorithm is accurate enough.
Microservices probably reduces the asymptotic cost of scaling but add a huge constant factor.
Relational databases are the right choice 95% of the time, non-relational stores require a really specific use case.
TDD is good for fast feedback in some domains, but for others, manually investigating the output or putting your logic into types is better. E.g. a lot of my time comes from scaling jobs that work on 10gb of data but crash on 1tb, TDD is not that helpful here.
Continuous integration mostly makes sense when you're making a lot of small changes and can reliably expect a test suite to catch issues.
In short, ask the question "when is practice X useful?" instead of "is practice X a good idea?"
- OJFord 10y ago> Microservices probably reduces the asymptotic cost of scaling but add a huge constant factor. If this were Medium, I'd highlight the hell out of that. That's so true, and so nicely, succinctly put - it ought to be the reply to end every argument about whether microservices are good or bad.
- FatalBaboon 10y agoI believe, for small shops, the real benefit of microservices is the logic split that forces good design and reduces cognitive load. You reap the scaling benefits way later, if ever.
- serge2k 10y ago> forces good design and reduces cognitive load Except splitting into microservices is an unnecessarily complex design choice. That's almost always worse, and the cognitive load comes in when you now need to figure out how to get this stuff right. The scaling benefits also require that you get it right, small flaws in your system become massive issues.
- rhizome 10y ago"Is your bicycle too slow? Get a helicopter!"
- kornish 10y agoDefinitely agree – the polyglot aspect can also be useful for companies where different parts of their problem fit different tools. However, exercising proper software discipline and using languages with good/existent module systems, like OCaml or Go, can lead to the same modular results without the fixed overhead. If you don't have a full-time ops person or team, you almost always have no business running microservices.
- nostrademons 10y agoYou can get that benefit by dividing your system up into libraries with defined, documented, tested APIs. There's no need to introduce all the complexity and failure modes of distributed systems just to force good design. When you need to scale, then you can easily throw your libraries behind an RPC framework and call it microservices, but there's no need to pay that cost until you actually face that problem.
- tunesmith 10y agoOne caveat is that if you need to fix a bug in your library in an API-compatible way, you can't reach into all the codebases that are using your library. You can deploy a new version of the microservice, though.
- kornish 10y agoI mean, you _can_ if you organize your code such that you can. For example, Google's monorepo lets maintainers of a library find all internal usages and fix them. This is one of the benefits Dan Luu notes in http://danluu.com/monorepo/ http://danluu.com/monorepo/.
- nostrademons 10y agoI think he means that you can't force all teams that use your library to recompile and pickup the updated code, while if you deploy it as a service, you recompile and redeploy and everyone talking to your service gets the most up-to-date version. This is a real problem - I recall that Sanjay Ghemawat et al was working on it when I left Google, though I dunno if the solution they came up with is public yet. It's unlikely to seriously affect you unless you're Google-scale, though, by which time you've probably divided everything up into services and aren't taking advice from the Internet anyway. For companies that are a few teams working on a single product, it's easy enough to send a company-wide e-mail saying "Rebuild & redeploy anything that depends upon library X", and if you're doing continuous deployment or deploy only as a single artifact, the problem never affects you anyway.
- the_gastropod 10y agoNothing about splitting your app into microservices _forces_ a good design. I've never seen microservices with well-defined seams. Every time, knowledge "leaked" between the apps, and any non-trivial change to the app required updating multiple repos, deployment synchronization, etc. Microservices are a tremendous burden that the vast majority of companies will not benefit from.
- FatalBaboon 10y agoI did not mean microservice as in "just make it many apps!". I meant as do not share databases and expose everything as APIs. It helps cognitive load because such apps can be reasoned about without reading code elsewhere.
- AstralStorm 10y agoAPI is not enough, full contract has to be shared.
- ajmurmann 10y agoIf you separate components wrong in the same code base is an easy fix. If you get them wrong between services you have s much larger problem. I'm not sure why you'd be more likely to get that right with services than within the same code base.
- endgame 10y agoI think this is actually a failure in mainstream programming languages, which make it far too easy to reach across what's meant to be a defined subsystem boundary and meddle where you shouldn't.
- AstralStorm 10y agoThey also have to weak tools to automate enforcing contracts. Generally the only available tool is "assert".
- manigandham 10y ago"Logic" is vague and there a several layers you can implement this before even thinking about microservices. It can be as simple as a simple class, or maybe a larger class as a single-file service, or an entire namespace with a several classes, or a separate library easily referenced. All the "logic" split benefits without the ridiculous hassle of microservices.
- brwr 10y agoAt the last company I was at, our search microservice was fast (average response was well under 100ms) and it didn't crash once while I was there. At a larger company, this may not be an accomplishment. At a startup, this is the bees knees. Meanwhile, the rest of our codebase (a monolith) crashed every few days for one reason or another. We had an on-call rotation not because that's what you're supposed to do, but because we actually needed it. Now I'm not saying that microservices make sense for everyone. In general, I agree that they are used incorrectly. Microservices are hot and software developers, generally speaking, like to use hot technologies. Yes, moving to a microservice was costly. We had to re-write a lot of code, we had to set up our own servers, and we had to get permission from the guardians that be to do all of this. But, for our use case, and I assume there are other use cases too, the benefits of detaching ourselves from the company's monolithic codebase far outweighed the costs for doing so. TL;DR No argument is the end to every conversation. Few things are so black and white.
- cs02rm0 10y agoI tend to start with a monolithic service. Sooner or later you get a feel for which bits are becoming at least API stable and could run independently. That's when I split them out. Do it too soon and you end up choosing the wrong boundaries and tying yourself up in knots, do it too late and your monolith can become a mess that's difficult to detach the pieces of.
- brwr 10y agoTrue. There's another thread in here somewhere talking about premature generalization. I think that's what you're getting at with "Do it too soon and you end up choosing the wrong boundaries".
- api 10y agoI tend to try to write monolithic services in such a way that they could be broken up into microservices if that were ever desired. I don't go too far with this, just avoid things like shared static state and other anti-patterns.
- gshulegaard 10y ago> ask the question "when is practice X useful?" instead of "is practice X a good idea?" This too!
- braveo 10y agoIt applies to TDD as well, unfortunately a lot of TDD proponents don't really acknowledge that.
- kosinus 10y agoOne thing that bothers me is the 'relational databases are good enough' statement, that is repeated in other contexts as well. But especially here, where we're talking about reducing complexity, it feels off to me. PostgreSQL and MySQL seem to me like incredibly complex packages. SQL, the language, is not easy to master either; most programmers I meet know mostly basics. On top of that, there's a long ongoing history of security malpractice. When talking about reducing complexity, CouchDB and Redis are far easier alternatives, in my humble opinion, though they go slightly against 'use the tools developers know'.
- crdoconnor 10y agoPostgres and MySQL aren't overly complicated for simple use cases. A lot of other technologies drop complications like foreign keys which you won't miss when you start developing software but it gives guarantees you will miss sorely when you start seeing inconsistent data 6 months in.
- AstralStorm 10y agoThe expensive and complicated thing about these is deployment and maintenance. But then, you could instead pick sqlite and switch to big one when needed. Sometimes it is good to get a pickup truck ahead of time, but often a smaller less versatile car will suffice. But not quite a motorbike.
- devty 10y agoRelational databases are not simple systems as you say, but they do seem to me simpler to use - especially in the 95% case where a single, large enough machine hosting postgresql/mysql is entirely sufficient. Key-value stores are "easy", but what I think isn't easy is to reduce your business domain to a simple key-value model without sacrificing promises and gaurantees offered by a good relational database system.
- pg314 10y agoThe implementation of PostgreSQL is complex, no doubt about that. But if you need strong data consistency and durability guarantees, it provides a rock-solid foundation. SQL might take some getting used, but it is also not rocket science. It shouldn't take more than a week's study to master the basics. There is of course a lot of awful SQL code out there, exactly because most programmers don't even know the basics. You can do incredibly powerful things in it that would take 10x the code in an OO/procedural language. In my opinion dumping an ORM on top is also not the best way to leverage the strengths of an RDBM. It is slightly ironic that you bring up security malpractice in the context of PostgreSQL, when in the next sentence you advocate Redis as a far easier alternative. As was recently in the news the Redis defaults were for a long time insecure (google for Fairware ransomware).
- deleted 10y ago[deleted]
- krptos 10y ago"putting your logic into types is better" Can you elaborate on that one? Sounds interesting to me.
- imh 10y agoSuppose you have some business logic that subtracts the cost of a transaction from an account balance and returns a new account balance. These things are probably integers, but in many languages you don't have to specify that. You write this function, then later your coworker comes across it and passes it a double. You might end up with weird small discrepancies in account balances (or mysterious errors that only happen sometimes) that could be totally prevented at the time your colleague wrote the code via static analysis, if you use put some logic (costs and balances are integers) into the types. This can be more sophisticated, like "this function requires a sorted list" so lets make a sorted list type, or packaging things up into biz logic types (a cost type that contains an integer instead of just using integers), but you can catch a wide variety of errors with static analysis if you make your code and logic amenable.
- SatvikBeri 10y agoRecently our team built a data pipeline: a few large inputs, a few large outputs, a lot of processing in between, a lot of parallelization & working w/large datasets needed. Essentially you could view the entire process as writing one very complex function. We approached this first outlining the procedure and specifying the types involved, then outlining functions from each type to the next. You could essentially think of our types as tables, so our outline was f1: t1: -> t2, f2: t2 -> t3,...,fn: tn -> t_output (although not quite that linear.) This let us split up work on the different functions across a team of 6 people. Specifying the input and output types was basically enough to make sure the functions were correct most of the time, and baking the interfaces into types enforced by the compiler made it easy to refactor & coordinate on changes when necessary. Feedback when we made an error was generally immediately available, because IntelliJ would highlight the function that produced an output value of the wrong type, or the compiler would catch it. In contrast, if we had relied primarily on unit tests to check the functions, that would have made coordination more difficult, refactoring harder, and would have required us to either generate or acquire test data to feed through each function. But this architecture let us successfully build out most of the logic even while we had no access to real data & a different team was working on data ingestion.
- stcredzero 10y agoIn short, ask the question "when is practice X useful?" instead of "is practice X a good idea?" Shorter version: Cost/benefit.
- deleted 10y ago[deleted]
- algesten 10y ago> Relational databases are the right choice 95% of the time, non-relational stores require a really specific use case. Relational databases are great, but I spent large parts of my life as a developer writing layers converting to/from SQL and later ORMs. There's a huge gain in just not translating data. I know Postgres (and others) deal with JSON, but I can't escape the feeling it's a bit shoe horned in there – basic SQL statements have strange new operators like ->> -> #>>. Relational databases are great for, well, relational data with strong consistency requirements. The popularity of the original MyISAM tables without integrity checks baffled me at the time. Why spend time marshalling data in/out of table form when you don't gain the benefits of a RDBM? Not doing data translation saves _a lot_ of time. Plain key-value stores are amazing, document stores like Elasticsearch are great, ultimately the choice comes down to requirements and time saving is often a very heavy argument, especially for small companies/startups.
- simonpantzare 10y agoThings such as joins, transactions, and means of enforcing data integrity are useful when solving a whole slew of problems. Not to mention the tooling and community you benefit from when you use a common RDBMS. I never found data translation/serialization to be a big pain (just rely on a framework/lib that does it for you). It's a bigger pain to hand-roll joins that would be a one-liner in SQL or deal with issues that arise from having your data (unnecessarily) reside in many systems.
- EdHominem 10y agoI hear this data-integrity thing a lot but I don't run into these problems myself. I think it might be a functional-programming thing. It's much easier and safer to declare your constraints rather than trying to enforce them. If you aren't in a functional language I can see why you'd want to reach out to one but SQL in a separate process is just one of the options. > Things such as joins, transactions, and means of enforcing data integrity are useful If the domain needs transactions I'm already speccing them regardless of general usefulness. Yes all that stuff is useful, but all abstractions have a cost which isn't free just because it's hidden in the DB. For a problem that didn't need transactions, but for which they were useful, why would you automatically want to couple the solution with your storage layer? If you're looking for the ability to express business logic clearly without cluttering it with error handling, for instance, software transaction memory would probably be a better level to work at.
- eikenberry 10y agoTDD is not about the tests, it is about teaching yourself to code better. About forcing yourself to break up your code into small components with well defined interfaces. Something we all want to do but which is hard in practice without a tool to guide you. TDD is that tool.
- SatvikBeri 10y agoIn our case, we did that using functional programming & type-driven design (which ironically is also a TDD.)
- devbug 10y agoThis this this! Most often I see TDD used as a couch for a really bad type system.
- AstralStorm 10y agoTypes are just formalised limited contracts. Emphasis on limited. They are not enough.
- eikenberry 10y agoT(est)DD does tend to make your code look more like you used a functional-oriented language. A lot less mutability, heavier use of first-class functions, etc. Though I tend to prefer languages that are at least somewhat functional (eg. python, go).
- AstralStorm 10y agoIt doesn't even help people enough apply SOLID principles. Pure functions help but the principles of generalisation are deeper than this. Tests verify contracts offline. This will miss real issues.
- peruvian 10y ago> Though I tend to prefer languages that are at least somewhat functional (eg. python, go). Can't think of any less functional languages than these.
- madcocomo 10y ago> TDD is good for fast feedback in some domains,...... It hears like, "IDE is good for fast feedback in some domains. " If someone saying that IDE is only suitable for GUI application but not the software he is writing, he probably means that "look at me, I am the old school tough guy." It's about the people dislike the tool but nothing about the domain.
- deleted 10y ago[deleted]
- voycey 10y agoQuite possibly the first time I have agreed with everything in a post on HN! Just because a new paradigm exists doesn't mean it will solve all of your problems and will likely introduce several more!
- disordinary 10y agoHaving loosely coupled microservices has benefits for maintenance as well as scaleability. If you are quickly iterating on a product and have it up in a rough state then you can easily work on seperate parts without having to worry about effecting the whole.
- spronkey 10y agoIt can go both ways. If you mess up modification of the microservice such that it breaks other services that relied upon it, you quickly get into ceremony that a small team might struggle with. A monolith might have had the problem solved faster.
- disordinary 10y agoYou're right of course, but it can also go the other way. If you break something then it seldom brings the service down, and often the breakage is very visible and can be seen by queues backing up. You can restore the broken service without having to redeploy the system as a whole. Like most things in life there is no right answer, with tools like Terraform you can build a very complicated microservices system with not much effort, but only if someone on your team is experienced enough. If you're in a small team it's probably not worth the effort of learning the techniques and putting them in practice. We hate premature optimisation after all.