Live data from Hacker News

Good system design

seangoedecke.com

391–400 of 400 posts

Re: Good system design

#391

> I’m often alone on this. Engineers look at complex systems with many interesting parts and think “wow, a lot of system design is happening here!” In fact, a complex system usually reflects an absence of good design. For any job-hunters, it's important you forget this during interviews. In the past I've made the mistake of trying to convey this in system design interviews. Some hypothetical startup app > Interviewer…

I’ve been in software for 20 years and it’s the first time I hear “back pressure”. Am I too old already?

Yes

(but worry yea not, just like someone said of another term: "Dependency Injection" is a 25-dollar term for a 5-cent concept, something is similar for this term. )

Re: Good system design

#392

Earlier quoted context omitted.

Really! I've written about this in my comments here... Here's a brief summary: - typical thread-per-client programming is terribly wasteful because it needs large stacks that must be able to grow (within reason), and this leads programmers to smear client state all over the stack, which then means that the memory and _cache_ footprint of per-client state is huge even though the state is highly compressible, and this…

Good summary of the theory, but the weird thing is that every time I’ve rewritten code to use async the total throughout went down by about 10%… which is what I estimate is the overheads introduced by the compiler-generated async state machinery. I’m yet to see a convincing set of A/B comparisons from a modern language. My experiences don’t line up with the conventional wisdom!

That could be because you're still smearing state on the stack? With async functions one can do that, and so you still have stacks/fibers/threads, and so you've not gained much.

With a CPS approach you really don't have multiple stacks.

Oh, and relatedly the functional core, imperative shell (FCIS) concept comes in here. The imperative shell is the async I/O event loop / executor. Everything else is functional state transitions that possibly request I/O, and if you represent I/O requests as return values to be executed by the executor, then you can have those state transitions be functional. The functional state transition can use as much stack as it wants, but when it's done the stack is gone -- no stack use between state transitions.

Now naturally you don't want state transitions to have unbounded CPU time, but for some applications it might have to be the case that you have to allow it, in which case you have problems (gaaah, thread cancellation is such a pain!).

The point of FCIS is to make it so it's trivial to test the state transitions because there is nothing to mock except one input, one state of the world, and check the output against what's expected. The "imperative shell" can also be tested with a very simple "application" and setup to show that it works w/o having to test the whole enchilada with complex mockup setups.

Re: Good system design

#393

Earlier quoted context omitted.

It is a granluarity tradeoff. With SQL you need to explicitly test all queries where the shape granularity is down to field level. When you map data onto an object model (in the dto sense, not oop sense) you have bigger building blocks. This gives a simpler application that is more reliable. Obviously you need to pick a performant orm - and it seems a lot of people in these threads have been traumatized. Personally,…

> 50 ms p99 You realize that’s abysmally bad performance for any reasonable OLTP query, right? Sub-msec (as measured by the DB, not including RTT etc.) is very achievable, even at scale. 2-3 msec for complex queries.

The is the response time for the server, not the database - which is appears that everyone but you understood clearly from the context.

Re: Good system design

#394

Earlier quoted context omitted.

I disagree. I generally understand the problem a "split-up" database brings to the table. This is how people designed things in the last many decades. What I propose is to leave this design behind. The split up design fits modern use cases much better. People want all kind of data. They want to change what data they want rather often. "One" database for all of this doesn't really work -- you can't change the schema s…

> In the split-up design, since you're not sharing the database, you can do whatever you want. > we can't add a new field, we can't change this field Ok, let's do an example. Assumption: A-ERP system with approximately 30 modules in use (e.g. sales order mgmt, inventory, purchasing, etc) B-For split DB, the DB is split by module and data flows exist for all shared data. So there are X different copies of the item mas…

It's interesting to see what people consider difficult to do.

In my opinion the "Split DB" case you outlined is still much easier to do.

It's never the lines of code or number of steps that need to be done make it complicated or difficult.

It's always the strange, weird, unexpected things. I change "this" and "that" breaks, but nobody knows why.

The biggest benefit of my approach is that it can be split-up between people. One team handles this part, the other some other part. You can only break your part of the database, not everything for everyone else.

Re: Good system design

#395

Earlier quoted context omitted.

Views are great. Stored procedures are cursed.

>Stored procedures are cursed. Elaborate?

Stored procedures make sense if you are trying to make your backend less chatty with the database. The downsides are that they aren't version controlled. PLSQL and its variants can be inscrutable and difficult to debug. I guess you just have to decide what tradeoffs you are willing to make in your application. For me stored procedures take too much discipline for any potential upside. Sure you might have a wizard on your team that has it all in their head. But once they are gone it becomes a tar pit.

Re: Good system design

#396

Earlier quoted context omitted.

>Stored procedures are cursed. Elaborate?

Stored procedures make sense if you are trying to make your backend less chatty with the database. The downsides are that they aren't version controlled. PLSQL and its variants can be inscrutable and difficult to debug. I guess you just have to decide what tradeoffs you are willing to make in your application. For me stored procedures take too much discipline for any potential upside. Sure you might have a wizard on…

Thanks!

Re: Good system design

#397

> I’m often alone on this. Engineers look at complex systems with many interesting parts and think “wow, a lot of system design is happening here!” In fact, a complex system usually reflects an absence of good design. For any job-hunters, it's important you forget this during interviews. In the past I've made the mistake of trying to convey this in system design interviews. Some hypothetical startup app > Interviewer…

lol that's sad and real. modern software engineering has a lot of bloatware, costing security, etc.

Re: Good system design

#399
post #120
post #94

Earlier quoted context omitted.

It’s not old school, it’s actually solid design. I have worked too with people that think the frontend or even services should guide the design/architecture of the whole thing. Seems tempting and it has the initial impression that it works, but long terms it’s just bad design. Having Data structures (and mainly this means database structures) stable is key to long term maintenance.

> Seems tempting and it has the initial impression that it works, but long terms it’s just bad design. This appears as an opinion rather than an argument. Could you explain what you find bad about the design? In any case, I believe a DB per backend service isn't a decision driven by the frontend - rather, it's driven by data migration and data access requirements.

It's an opinion based on countless of references and books out there. I cannot cite them, but it's like "code should be designed to depend on abstract interfaces instead of a concrete implementation", "everything is a byte stream", "adding more people to a late project makes it later", "Bad programmers worry about the code. Good programmers worry about data structures and their relationships", "Show me your flowchart and conceal your tables, and I shall continue to be mystified. Show me your tables, and I won't usually need your flowchart; it'll be obvious.", etc... they are usually true.

Re: Good system design

#400

Earlier quoted context omitted.

I’m generally pro SQL-as-interface, but this is just wrong. Not only are there all sorts of bizarre constraints imposed by databases on migration behavior that application code can’t express (for example, how can I implement a transaction-plus-double-write pattern to migrate to use a new table because the locks taken to add an index to the old table require unacceptably long downtime? There are probably some SQL engi…

As the sibling comment mentioned, this is a solved problem. MySQL and MariaDB take a very brief lock on the table at the very end of index creation that you will not notice, I promise. Postgres does the same if you use the CONCURRENTLY option for index builds. If for some reason you do need to migrate data to a new table, triggers. If somehow these still don’t solve your problem, ProxySQL or the equivalent (you are r…

> this is a solved problem

It really isn't. The addition of an index was an example, and a relatively straightforward/simple one, of general schema migration pain. And even index additions aren't a solved problem: CONCURRENTLY (postgres only) and other affordances don't work in every case, as their documentation abundantly illustrates--what about overlapping indices, foreign key "inherited"/implicit indexes, UNIQUE constraints, and so on? Even in postgres with a DDL expert on hand, things get hairy fast.

In MySQL/maria, that "very brief lock" at the end of index creation can turn out to be anything but, if the table is high-write-volume, since InnoDB locks aren't FIFO--at least, not in the way people expect them to be.

And again, that's a simple case for which mitigations exist! More complex schema migrations hit immense amounts of trouble at even medium sizes of data and query volumes.

Online-schema-change tools that use triggers/cutovers are extremely limited: not only do they take locks to set up and manage their triggers/replication systems internally (meaning that they can cause severe disruption, or fail to migrate, in the face of continuous $thousands/sec of writes to a table), but their underlying mechanism is also often one of duplicating a table entirely, bulk-copying data from old to new, using triggers to stream changes during the migration, and then cut over. That mechanism is flawed for large tables (2x the data might not fit), flawed for high write volumes (2x the update operations is an unacceptable latency cost in plenty of circumstances), and just plain risky (that final cutover/drop/rename to point things at the new table is and probably will always be extremely lock-ful).

To be clear,the availability of advanced database facilities like CREATE INDEX ... CONCURRENTLY, triggers, and online-schema-change tools are all good things! My point is that this is very, very far from a solved or painless problem space--one that starts to become quite painful at even moderate scale.

Post reply on HN