HNHacker News
TopNewBestAskShowJobs

SomeCallMeTim

4,107 karma · joined February 17, 2010

I'm a consulting software architect and freelance CTO. I come in and rescue small businesses from code disasters, and occasionally am given the chance to prevent the disasters to begin with. I also used to develop video games, and have pivoted that skill to gamification consulting.

https://coderescue.com

submissionscomments
SomeCallMeTim··on Why I Hate Frameworks (2005)
I use it with TypeScript, and I find the wrapped lines to be far more readable. You get used to it.

Many people do, though I understand it's a point of religion for some to Not Wrap Lines.

Had a short contract recently with a company that had a small team of two developers. My widest reaching contribution to the team, I think, was to vote with the team lead to adopt Prettier.

Their previous approach was to _never wrap import lines_. There were literally 1000-character import lines. One of the developers was totally religiously opposed to ever wrapping them. Deltas in PRs were impossible to actually parse with huge lines like that, and if two people modified the same import line, merging the two changes was a nightmare.

But with a facade of Democracy, the team lead was able to finally adopt Prettier and its wrapping to the project. This despite the fact that I'd already let it be known that I was only staying until the end of the contract (about three months) and moving on. Whatever works.

SomeCallMeTim··on Why I Hate Frameworks (2005)
As someone who started out in the game industry in 1990, I can say that being able to choose between competently-built game engines is a HUGE bonus.

At last count I'd written six (!!) game engines. Nothing huge; mostly "casual" games as the target. One of those engines ended up having over a hundred published games written for it, though, so at least in that case I got some decent traction.

And honestly? If at any of the times I was starting a game engine, I could have just sat down and focused on _writing the game_? I would have taken that option and not looked back.

You have to make a decision, when it comes down to it: Do you want to write a game? Or do you want to build a game engine?

Because writing a complete game engine can take 2-3 years all on its own. And yes, that's counting gluing together existing libraries. I never wrote, e.g., a PNG or JPG loader from scratch. The engine with 100+ games? I started work at PlayFirst and immediately started working on the game engine. Nearly six years later when I quit to work on my own games, I was _still_ adding features to the engine.

Games were certainly released before that; the first game I released was probably only six months in. But the game engine (Playground) wasn't very mature yet, and it wasn't until at least 2-3 years in that using the engine really had a robust set of features (including cross-platform support).

And if you're looking at creating a 3d game, and don't want to start with an engine? Well, it can be done, but again, if your time budget is three years, at least half that time will be working on parts and fixing bugs that a solid engine would have handled for you. If your time horizon is shorter, then expect even more of your time to be spent reinventing the wheel.

Source: I spent 20 years in the game industry.

SomeCallMeTim··on Why I Hate Frameworks (2005)
Agree on all points...except Prettier, which is manna from the gods. Better to get used to it than to fight it.
SomeCallMeTim··on Canon sued for disabling scanner when printers run out of ink
I have a Brother inkjet all-in-one, and it works great, BUT...

Problem is that it needs to "clean" the print heads frequently. It uses up ink every time it cleans. So if you're not printing frequently, 95% of your ink will be used up by letting the printer do its thing.

I tried just leaving it unplugged for a long time once, and sure enough the print head clogged. It took a lot of printing and cleaning (and wasted ink) before it became 99% usable again.

But the Brother B&W laser we got? It Just Works.

SomeCallMeTim··on Norway to hit 100% electric vehicle sales by early next year
In Colorado at least it's not that high. $50 plus a small amount (today) that goes up over time to no more than $96 in the 2031-2032 fiscal year.

It's CERTAINLY a lot less than you'd be paying in gas tax if you used your car an average amount.

Taxes aren't punishment, anyway. Especially "road use taxes", which are, in this case, used to repair the roads you're driving on.

[1] https://afdc.energy.gov/laws/11486

SomeCallMeTim··on Analog – An analogous, indented syntax for the Rust programming language
The biggest downside to Python's popularity is the uber-fans' tendency to think it's a Good Idea to wreck other languages with significant whitespace. Like CoffeeScript.

So far I believe every such attempt has ultimately failed. Like CoffeeScript.

This seems to be a particularly execrable example of that phenomenon.

SomeCallMeTim··on Jailer: A truly relational database client
Roughly: Say you have a relational database with a dozen tables that all connect to each other using foreign keys: A user table has a user id, a message table refers to a user, a log table refers to the user and a message, a comment table refers to a message and a user, and so forth.

Jailer can, say, grab a few comments from the comment table and at the same time grab any users and messages that were referenced. Then all of those records spread across all of the tables can be exported for use by, for instance, tests.

Imagine you found a bug, say, in your app logic, and you wanted to grab an image of the exact data that triggers the bug to repro that bug and use it in a test. This tool makes that easy.

SomeCallMeTim··on NDA expired, let’s spill the beans on a weird startup
My first job out of college was a practically fly-by-night video game development house that had primarily D-team members except for a couple of contractors and me.

After my first successful project for them, their biggest client started demanding that I be assigned to their next big project (or one of the external contractors). We both ended up taking jobs elsewhere, and that client quit using the developer.

And the client? They were a full-on shovel-ware developer that barely cared about game quality. They just needed a game that would run reliably enough that Nintendo would approve it. So to be fired as a developer by that company was really embarrassing...

SomeCallMeTim··on AlpineJS – Lightweight JavaScript Framework
Yup.

Regretfully we seem to be in the minority, though. I expect more of the HN readership, but apparently the instant gratification culture permeates it here as well.

SomeCallMeTim··on AlpineJS – Lightweight JavaScript Framework
I 100% agree, and I don't see why you're being downvoted.

I frankly see this approach as the Wrong Way at this point. I hate that every new framework comes out with its own take on HTML attributes.

And zero TypeScript support? Seriously?

This is a non-starter framework.

SomeCallMeTim··on DenoDB
Good question! To which I respond with another question: Why not both? ;)

Actual example code from my current project (with the actual object type anonymized by renaming it to "thing"):

    const result = await prisma.thingInstance.findMany({
        where: {
            thingTypeId: {
                in: thingTypes.map((id) => id.childThingTypeId),
            },
            thingInstanceChildren: {
                none: {
                    parentThingId: {
                        equals: args.parentThingId,
                    },
                },
            },
        },
        orderBy: {
            thingTypeId: "desc",
        },
        take: 120,
    });
Returns an array of ThingInstance objects. It can also return joined relations (giving you the "Object Relational" part of ORM), or filter on joins, or what have you.

It's because Prisma (in this case) is an ORM that fully understands the data architecture that you can layer a full automation/code generation/GraphQL server on top of it. Not all ORMs have this feature, but you mostly need to start with an ORM in order to bootstrap this functionality.

I guess you could do what you're describing by creating tons of highly specialized code given a schema without adding the ORM/query building features--but adding the layer that gives you a Data Mapper pattern ORM is a tiny amount of additional effort at that point.

I did mention elsewhere: Some people seem to think that the ActiveRecord pattern is the only "ORM" approach, but Data Mapper is another approach--and one that is usually referred to as another view strategy of an ORM. [1]

[1] https://culttt.com/2014/06/18/whats-difference-active-record...

SomeCallMeTim··on DenoDB
Awesome...maybe?

Does it support TypeScript? Because I'm not going back to dynamic types for nontrivial code. Ever.

Does it support debugging? Because having a real interactive debugger with source mapping, ideally integrated into VS Code, is another minimum bar for me to consider it a viable platform.

If yes to both, then: Awesome! I'll keep it in mind for future projects where it's appropriate.

SomeCallMeTim··on DenoDB
I'm actually using Prisma.io right now.

TypeORM has another similar solution.

Postgraphile looks cool, but ... you're writing your custom handler in PostgreSQL script. This strikes me as suboptimal for debugging and general developer productivity. Otherwise, you're right, it's a similar solution. Which actually contradicts your assertion that I'm highlighting features "packaged with the ORM I use."

Hasura...looks like a black box that you'd have very little direct control over, and if they went out of business, you'd be totally screwed. I'm very firmly against lock-in with no fallback. Been there. Don't want to do it again.

Regardless, I'm only six-months-new on the GraphQL version of this stack. Before that I was using FeathersJS with Sequelize: Similar to GraphQL only with more traditional REST endpoints and less built-in JOINing between tables. FeathersJS actually has more flexibility in querying a single table, and adding indirect JOINs was possible/generalizable across your whole API with a few lines of code, but what wasn't as clean was the security model for who could see what.

Another similar stack is LoopbackJS. I'm sure there are more.

So it's really, really not that of a niche case. I've used a similar approach again and again for pretty much every backend project that needed a CRUD API. Every one of those projects I touched probably had 1/100th the amount of raw code required compared to the traditional wasteful approach.

SomeCallMeTim··on DenoDB
OK, that's awesome.

But type safety is only part of the equation.

Automatic CRUD or GraphQL code generation and/or other abstraction such that you never need to write basic CRUD code ever again? That should be a minimal software engineering best practice at this point, and yet we have tons of people insisting on writing every single query, either as a SQL query directly or using a query builder.

It's on the order of professional negligence to ever write complex code to handle the same situation over and over. CRUD is exactly that. Huge swaths of CRUD code are blatant DRY violations, and using an ORM or another kind of query builder that can interface with CRUD/GraphQL automation should be the minimal best practice we're all using.

SomeCallMeTim··on DenoDB
I've been doing this as my $DAYJOB for the last five years.

Your examples/predicted catastrophes are straw men that I've never seen in reality myself--though I've heard reports of Rails/ActiveRecord having issues similar to what you describe. Maybe that's the real problem you're worried about? RoR sucks. We can agree on that.

In the code I've been working with, though? An ORM can have annoying limitations, but doesn't suffer from weird magic. So in that case, write custom SQL to solve the exact issue the ORM doesn't support. Problem solved!

I'm confused by "use a query builder instead of an ORM," though. The ORMs I'm using are effectively query builders with knowledge of your object relationships. See for example Sequelize, TypeORM, or Prisma.io. Lighter query builders like knex.js don't seem to have enough information on the schema to give you type safety or auto-generated code (like FeathersJS or GraphQL resolver builders).

TypeORM and Prisma.io even allow you to use the Data Mapper pattern instead of the annoying ActiveRecord pattern. I suspect you're confusing the ActiveRecord pattern with "ORM". No "magical ORM layers" required.

Don't confuse Rails/ActiveRecord garbage for a modern ORM.

SomeCallMeTim··on DenoDB
Pgtyped looks really cool. So does Zapatos.

But my current gig has an absolute non-negotiable business requirement to support multiple database backends. Specifically SQL Server and MySQL in addition to PostgreSQL.

Additionally: Not seeing any way to take the schema info from either of the above and have it crank out a full GraphQL server code base. Check out my linked comment if you want more details, but I'm seriously talking 20-40k lines of code that I didn't need to write because the resolvers were auto-generated by the stack I'm using.

At least a first pass of Google searching isn't coming up with anything similar with pgtyped or Zapatos. And no, you're not going to convince me that 40k lines of code that shouldn't be necessary to write by hand are somehow superior to 1/100 the code that just includes the queries that don't map as well onto the ORM or the GraphQL generated code.

SomeCallMeTim··on DenoDB
Writing, what, a couple dozen (at most) SQL statements that are custom designed for a single application? Not really a big deal. Sure, write your SQLite queries by hand. Fine. Whatever; I wouldn't even say it's inefficient if it's that few.

Writing ~20 SQL queries for each of 20 different data structures (including various JOINs and search options) to create a CRUD API? And maintaining them each individually? And needing to make changes to the query every time the clients need to make a slightly different search request?

When I can literally write the 20 different schemas in one file, type a build command, and get a fully featured GraphQL API with full JOIN and custom boolean logic search capability in a few seconds?

I'm saving myself probably 40,000 lines of code, counting all of the data wrangling and test cases that I'd need to create to provide the minimal functionality that I would need--and the GraphQL code wouldn't need to be modified to change the search or order-by options of a particular query. And lines of code you don't write are lines of code you don't need to maintain. It's a huge win. Not even close.

And that said, the above is based on a real project I'm currently involved with, and that project does have six custom GraphQL queries that I wrote by hand--most of which also leveraging the ORM to some degree.

In exactly three cases, I wrote raw SQL queries that the ORM didn't support directly.

So I'm going to say no, the black boxes don't need to work 100% of the time. For me they're working 99% of the time, and I write the last 1% by hand, which is just fine. If I had run across a terrible query in that one corner case, I'd probably not try to dig inside the black box; instead I'd create a custom query that does exactly what I want and expose it for that bit of functionality. Done. [1]

As to the ORM used by Duplicati? Crappy ORMs exist. That doesn't mean all ORMs are bad. I can see the exact queries (minus parameters) scroll by in my log that the ORM I'm using is writing out. My own custom SQL queries tend to be more lines of code in practice, and none of the queries that it has generated so far have been slow.

[1] Figuring out why a 100 line SQL statement is slow is generally not that hard: You put "EXPLAIN ANALYZE" in front of it, and it will point out where the time is going. That's a PostgreSQL feature, so you'd need to have a Postgres backend in order to use it. Good thing we're talking about using an ORM that could easily switch between SQLite and PostgreSQL! Optimize the schema and indices on PostgreSQL and then switch to SQLite for embedded work.

SomeCallMeTim··on DenoDB
Because "getting to know your data storage technology better" isn't the business goal. On the surface, that's a great goal to have, but taking an approach that requires you to do 100x as much work so you can learn SQL better isn't software engineering. It's over-billing.

I throw together 200 lines of schema in Prisma.io and it creates 20,000 lines of GraphQL handling code plus more ORM-specific code that allows me to create type-safe access to the database.

And "the database" right now is PostgreSQL, but one of the business requirements is that "the database" could also be SQL Server or MySQL.

Having learned the salient details of the ORM in ... hmm ... about three days? ... I feel that the advantages of getting a full GraphQL API that can be wired up to an arbitrary backend database for 99% of the queries vastly outweigh the fact that most of my database queries are entirely inside a "black box."

In six months I've encountered exactly one problem where the black box made my life more difficult. I think I wasted about an hour, maybe 90 minutes, on tracking down why it didn't work as expected. Given that "writing custom SQL" for all of the queries that I've created would have required 10s of thousands of lines of additional code plus system tests to verify that the queries were all working as expected? That's a profoundly huge win.

I'd still be writing SQL queries months from now if I had taken the approach you're suggesting. Maybe it's advice that's good for consulting firms that charge by the hour and love to find ways to make their developers work more hours, but in my book it's not even ethical to recommend.

SomeCallMeTim··on DenoDB
Yeah, and we already have TypeORM in Node, which is an excellent ORM (despite some clear haters here in the comments).

This is why Deno is a dead-end. We have tons of excellent solutions in the Node-verse, and they need to build everything up from scratch (or create ports that are "unstable and shouldn't be used in production" [1]).

And it's not just the ORM that's interesting. It's the tooling that will connect, say, TypeORM or Prisma.io to GraphQL, so that you can throw up an API in a few lines of code, that means you're writing something like 1/100 the number of lines of code for equivalent or even superior functionality.

[1] https://github.com/denolib/typeorm

SomeCallMeTim··on DenoDB
Wow.

See this other comment I wrote:

https://news.ycombinator.com/item?id=27551288

TypeORM in particular is well designed and quite awesome. A huge benefit of TypeORM is that you get full static type support in all of your queries, including in the returned results.

SQL results are effectively one-off dynamic type result piles that you need to validate by hand, and are insanely inefficient to code.

SomeCallMeTim··on DenoDB
I am super happy and comfortable reading and writing SQL. Give me the slightest excuse and I'll write up a wicked complex query that does exactly what we need to solve a particular problem.

I simply also feel that having 100% type safety in your results (which you really can't do with SQL queries) is a huge bonus. Add in database portability for most of your operations (including between, say, PostgreSQL and MongoDB), and you end up with a huge software engineering win over writing custom SQL for every query.

And frankly? That's only the tip of the iceberg in the advantages of relying on an ORM.

The next step is to use something like FeathersJS or GraphQL that will prevent you from ever needing to create a basic CRUD API by hand.

Once your ORM knows the shape of the data, you can simply tell FeathersJS to serve that API, complete with POST/GET (one)/GET (find/search)/PATCH/UPDATE/DELETE, and poof, you're done except for any custom behavior or security that you want to add using hooks. Or similarly, you hook your ORM into your GraphQL adapter, and you get a great graph querying API with very little effort.

And in both cases it can be very type safe. The best query to maintain is the one that you never need to write by hand. The GraphQL code generator I'm currently using took 200 lines of clean schema definition and turned that into 20,000 lines of code that I never need to maintain or even think about.

ORMs are tools. If you ignore the power tools you have available, you're going to end up as obsolete as someone who insists on still building houses or cabinets using only hand tools. Yes, of course it can be done. But it takes 100-1000x longer, and the results are often not as good.

SomeCallMeTim··on Babel is used by millions, so why are we running out of money?
> Since we're taking Silicon Valley metrics seriously

Umm... Colorado?

We're more than a thousand miles as the crow flies or 20 hours of driving away from Silicon Valley.

More to the point: If the rest of the team is in US time zones, coordinating with an Eastern European developer is much harder. It means someone has to stay up really late or get up really early, and typically you still don't get much overlap.

Granted if such a brilliant developer who needed very little input from the rest of the team were to apply, they'd do well to hire them. But as the other comment mentions, how do you find such a developer on demand?

SomeCallMeTim··on Babel is used by millions, so why are we running out of money?
Understood. Thanks for the specifics.
SomeCallMeTim··on Babel is used by millions, so why are we running out of money?
I don't live in Silicon Valley. I live in Colorado, in a Denver/Boulder suburb. Not one of the most expensive places to live, though prices have been skyrocketing during the pandemic.

I see jobs all around me every week that go to the $150k-160k range. If I decided to take a Google or Amazon job I could easily break $200k, maybe more (including stock grants).

Developers in the US get paid more because demand has actually pushed our wages up to closer to what they're actually worth to an employer.

I've read estimates that a strong software engineer can add $500k-$1M of value per year to a company. You want a strong software engineer in charge of Babel, right?

SomeCallMeTim··on The real reason to end the death penalty
I was on a jury for a trial where they had crap on the kid accused of conspiracy to create meth.

He drove an old high school friend, who he hadn't seen for years, to a park. He drove into a parking lot on the way and turned around "as if trying to avoid tails." He returned to the car and the undercover cop put the key back in his hand after putting ingredients in the car.

AND...he was being accused of conspiracy (which raises the seriousness of the crime to a felony!) to create meth because...there were drug ingredients in the car and the keys were in his hand. He'd spent his time at the park napping on the grass with his hat over his head. Or, as the cops testified, "probably acting as a lookout."

We of course said "not guilty." No one even wanted to argue. No idea why they thought they had a case.

But the kid in this case was white. I could totally see a black kid deciding that accepting a "lesser plea" would have been preferable to taking a chance on a 95%+ white jury (was in a predominantly white area; I don't think there was a single black juror, though I wasn't keeping count).

SomeCallMeTim··on The real reason to end the death penalty
There is zero evidence that the death penalty is useful for deterrence.

Zero points for using a distraction from the argument at hand which is whether the death penalty is justified.

SomeCallMeTim··on Ask HN: What tech job would let me get away with the least real work possible?
I managed four concurrent "half-time" gigs once.

Probably my most lucrative month ever.

SomeCallMeTim··on Ask HN: What tech job would let me get away with the least real work possible?
> If staff are functionally lying to their company about their output, something has gone wrong.

Problem is that productivity gains are extreme across most industries over the past fifty years, and except at the FAANG end of the income spectrum where people are making $300k+/year, those gains have been 100% absorbed by employers and not passed on to workers.

As such, employers are the ones to have broken the social contract. Yes, they're pushed to do this because they can, and there are no penalties to dissuade them from this behavior (specifically because employee organizations/unions have fallen out of favor, though that may seem to be reversing recently).

So it feels justified to provide a service to an employer for a fixed fee (a salary or weekly contract wage) in exchange for satisfactory work output, and to not work the hours the employer may assume you're working. It's a profoundly asymmetric relationship, and letting an employer believe you're working more hours for that work output--as long as they're happy with your work output!--is balanced by the fact that they're not paying you what you're worth to them.

The latter is clearly true if they're continuing to be happy with your work output and you're working half as many hours as they may believe you to be working. And yet they absolutely wouldn't double your salary if you doubled your work output.

SomeCallMeTim··on Redefining what a map can be with new information and AI
I'd be curious to know if that maps onto the lowest energy use in an electric car.

Because I've been wanting that feature for long-distance EV trips for a while now.

SomeCallMeTim··on It Can Happen to You
Agreed. My first instinct was the same: *scanf is never the right tool for pretty much any job.

I learned this 20+ years ago. As far as I'm concerned it should have been considered deprecated along with gets; it was considered dangerous in the early 90s and probably before. Not sure why people are still using it in the 2000s+.

← PreviousPage 7 of 34Next →