Why Golang instead of Rust to develop the Krater desktop app
blog.moonguard.dev
blog.moonguard.dev
Is there an institutional issue with SQL knowledge or is it exceedingly complex database?
As someone who finds ORMs more trouble than they're worth I really struggle with that point, particularly if it's SQLite.
And while Go's testing framework is really nice, I've never had much issue doing unit testing in Rust. I'm assuming the problem was more with the testing + the tauri framework than Rust itself.
I guess it's a good example of how powerful Rust is. The "magic" that sqlx does at compile time gets really difficult if not impossible to do without macros.
Of course you could create a separate parser/builder, and codegen works as well, but definitely not as convenient and flexible.
caveat: I'm an ex-DBA so I'm comfortable with building complex tables, relationships and queries. Less familiar folks might struggle building the tables, relationships, and doing joins, ctes etc.
There are derives involved, of course, so that probably counts as macros.
this now 400+ headcount company would not exist if query builders did not exist
If working in-house or building something bespoke, an ORM provides negative value. The only possible upside I can think of is that it offers an opportunity to capture databases access events or... no, that's it. In exchange for this dubious capability, ORMs end up sacrificing the full generality of SQL for simple CRUD statements. On top of that, if ORM migrations are in play then database maintenance becomes bifurcated because, like on the CRUD side, ORMs can only provide crippled imitations of DML.
Avoid.
It's the power of an ACID RDBMS with the level of integration of DAOs written in whatever language you want.
There's nothing stopping anyone from writing their own DAO layer with bespoke SQL statements and allowing intellisense to index the API over the top of that.
That sounds like a homebrew ORM. It could end up being better than any out-of-the-box solution. Or you could make a spaghetti code mess. But I’d rather spend my time elsewhere.
In my opinion the bespoke app code is the center of everything. The database is on the periphery and should conform to my needs as a software engineer building a user facing product. I need to live in reality, though, and understand the database accessed through an ORM is a leaky abstraction. But for many common use cases (find by ID, update a field for a row, etc) I can forget that it’s Postgres under the hood.
I know SQL well enough, understand how to craft a decent schema, how to keep the database happy as tables grow in size. But the main job is writing web app code, not operating as a DBA.
I operate on the principle that the center of the app can be determined by finding where most of the bullshit is. For an app where you’ve got some tables and indexes, the database is too idyllic to be the center of bullshit. Your app code probably has 1000x more bugs and spaghetti to it.
I'm always amazed at how much I can do in a single SQL query and how much extra code is required to accomplish the same when using an ORM. But then I once wrote a SQL compiler and runtime system so I'm quite adept at SQL.
The only thing I think (some) ORMs do really well is migration management. But you can also devise your own patterns for this easily enough that it's not worth it.
This is pretty much the life cycle of the “ORMs suck” crowd. The hangups are similar to “XML sucks” — conflating a poor ORM framework or XML-based format with the concept of ORMs or XML in general.
ORMs are a very useful abstraction, and even if you think you aren’t using an ORM, you probably are — just a bespoke one.
An ORMs super power is in easily composable queries. Something no easily don’t with SQL strings because of name conflicts and other issues. ORMs provide incredible benefits when it comes to sub queries and IN statements for instance.
ORMs are not a replacement for SQL strings or knowing SQL. Knowing SQL is sometimes a prerequisite for using some advanced features of an ORM to begin with.
Maybe it comes from people using crappy libs or perhaps some people just like something to feel superior about, but I’ll keep using my humble ORM. So many incredible benefits of ORMs and zero restrictions on just using raw SQL with them anyways.
It's the modelling of SQL as an AST that gives you that composability, and this does not require an ORM; see for instance arel (even though this was later absorbed into Rails' ActiveRecord ORM as an implementation detail...). [0]
orms are often opinionated and tables that are setup with an ORM may not be compatible with other ORMS. This is the only real downside. If you have a large legacy application that needs to be migrated to a new framework that uses different conventions for index names, table names, ect, then you are in for a bad time.
Django's orm is probably one of the best out there. Django also has orm manager classes you can extend with abstractions around orm functions or raw queries.
For complex queries, like with CTE's, complex joins, recrusive queries, index optimizations, there is no way around custom queries but any good ORM has an api around these raw queries that can hopefully also map to objects in your applications.
My personal experience is that the more they try to abstract away raw queries, the least useful they are. YMMV
It's not good, but it's not bad enough to justify ORM complexity. Then again I've worked in places where no one knew what an index was so maybe they make sense in such environments.
Working directly with SQL does feel a bit like peppering your modern codebase with COBOL.
On the other hand, I've worked at companies where they built their own barely functional ORM. It was total garbage. The original developer did not understand prepared statements, so you can imagine how well that worked out. We'd regularly hit SQL errors in production because a quoted string came through.
C# (LINQ) or F# (Query Expressions) come to mind. Sadly not much else.
Golang and Rust both offer type safety, but Golang is statically typed and uses a garbage collector to manage memory (as mentioned earlier).
Why would they word it that way? Is Rust any less statically typed than Go?
Golang (and java) by nature has a bad type system that's fundamentally incompatible with popular data structures used in the web.
Json a very popular web data structure cannot be represented properly as a type in golang.
The standard way of dealing with a dynamic json data structure in golang is to resort to interfaces and type assertions or assuming it's some struct. There is a similar problem in java. This isn't some "wrong" thing in go as you wrongly state. It's standard practice. You are suppose to use interfaces for this purpose in go. It's standard and by design. If you haven't then you haven't worked on something sufficiently big enough such that the input parameters include json of an unknown structure. Basically you only worked in web apps where inputs aren't complex like trees which is a valid structure that can be represented in json.
Rust gets around this by something called sum types allowing you to stay type safe without ever resorting to breaking out of the type system when dealing with any json type. Typed python also has sum types which let's you easily get around this problem.
I want to add that "ownership" isn't new. When working with systems languages without a GC, ownership was always there, you just kept track of it mentally, rust may be the first to make you aware of it by enforcing it at the compiler level, essentially making you aware that you are doing something stupid.
Adopting rust's ownership model was truly "zero cost" coming from a C/C++ background as we were already doing it.
Skill issue for sure, I would love to spend more time learning and practicing, but that's not always great when you need to get stuff done.
In Go it is really easy to just build the things I need, fast enough, safe enough. I expect it's somewhat the reverse of Rust, very productive and easy until it's not, but it will take you quite far! It's maybe more like Python, but with decent types, and a lot faster.
I think both are pretty awesome for different purposes, I would also expect that once you get to a decent level of Rust experience it probably gets a lot more productive, but it takes a while to get there.
I had not heard of https://wails.io before for Golang GUIs, only https://fyne.io which renders its own controls without a browser engine (also: mobile).
I admit that STW GC pauses sicken me, so I avoid them on principle.
* I was surprised how naturally and easily porting the Go code to Rust was. I have been writing Go and I have been happy with it (to my surprise actually). And I have a stereotype in my head that Rust is more cumbersome. But in some cases, the Rust code was much more ergonomic than the Go code.
* Rust appears to be a quagmire of TIMTOWTDI (There Is More Than One Way To Do It). Just looking at the Rust docs for the standard library is a bit stress inducing. In some way Rust reminds me of the old Perl hacker culture which many love but I did not. When I first read the zen of Python stuff, and the idea that there should be one obvious way to do things I knew where my own heart lay.
* Rust is like the Dark Souls of programming. In the linked video there is a moment where the creator is audibly relieved. He did some mutable borrowing stuff across threads and he was deep in a rabbit hole of making the compiler happy. Finally he got it all to compile but he admits he wondered if he was going to find a dead-end. But there is something addictive about that kind of stress - I know it myself. You feel like you accomplished something when you come out the other side. It is some kind of dopamine inducing validation of your ability as a programmer. I think this is a very negative trait in the context of tools used to complete work.
* After implementing large blocks of functionality and getting the code to compile, it "just worked" as Rust programmers like to brag about.
My impression is still that Rust is over engineered. I have a lot of reasons to feel that way, but a recent one is a video from the CopenhagenRustCommunity where Jon Gjengset did a presentation on using `impl` traits in place of generics. It really feels to me that the ergonomics that I praised in my first point are a deal with the devil. I get the impression that maintaining this facade of "easy" is creating some demons under the covers. And things like `impl` trait and some of the decisions around it are layering on top to try to hide those demons. I don't want to call out this feature too hard since I'm just a tourist here and real Rust guys will probably have more useful opinions on it. But whenever I dig deep into Rust you end up with things like "Pin" or whatever and the guys behind it are almost apologetic. They recognize these are weird annoying things but in some sense earlier decisions are forcing them to do the best they can.
All that being said, I'm probably going to finally give Rust a decent try. I've been writing a small personal project in C and I think porting it to Rust is worth the time.
1. https://www.youtube.com/watch?v=BbIEuNscn_E&ab_channel=Tsodi...
2. https://www.youtube.com/watch?v=CWiz_RtA1Hw&t=2234s&ab_chann...
> You feel like you accomplished something when you come out the other side. It is some kind of dopamine inducing validation of your ability as a programmer. I think this is a very negative trait in the context of tools used to complete work.
It is an interesting point. I have regularly claimed that you need to be heroic to program applications with weakly or dynamically-typed languages, because regularly, everything is going to come crashing down on you, and you will need large doses of heroism to debug through stuff that a strongly, statically typed language would have caught earlier.
Reading what you write makes sense, though, because it is true that you sometimes need to sacrifice live chicken to the compiler gods. So it could very well be that you are trading late heroism for earlier heroism.
> My impression is still that Rust is over engineered. [...]
Having worked on a few compilers and SpiderMonkey, I believe that I can tell you that most, if not all, languages are over engineered. Rust likes making choices explicit, while Go, Python or JavaScript try harder (with various levels of success) to hide this over engineering into the runtime.
That being said, yes, the Rust team has made a few choices they're not happy with and is trying to harmonize back the language.
Traits are mostly well-trodden ground, being rather like typeclasses in Haskell. The ability to use them for both generic bounds and dynamic dispatch is lovely, but a source of confusion if you’re new to the language.
In my experience lifetime management is the biggest hurdle when you’re getting started. I’ll admit that five years into learning rust, with half of that working with it professionally, I still sometimes get lifetime errors that I don’t understand. However, I have gotten much better at them over time (name your lifetimes well! it’s a lot more helpful for understanding for a lifetime to be named ‘frobnicator than ‘a, IMO).
Anyway, only thing for it is to give it a shot! The feeling of easy performance wins and strong type safety is hard to give up once you’re used to it.
I'd like to remind people that errors you don't understand are bugs and I'd encourage you all to file a ticket when encountering any: https://github.com/rust-lang/rust/issues/new?assignees=&labe...
As he mentioned the current situation with return position impl trait + 'a was surprising even to some of the core rustc developers so it's not like they intended for it to be like that.
If you were a plumber, would you rent your pipe fitting tools forever just to have the manufacturer frequently changing the way they work to justify the subscription model? The software development industry has gone crazy.
I'll never in my life pay $30 / year for something like this, but I wouldn't hesitate to buy a perpetual license for $150 upfront if it were useful to me.
I have Java projects that are 10+ years old and I can check out the repo, install IntelliJ IDEA v7 (perpetual), install all my other tooling that had perpetual licenses, and have everything "just work". It's so frustrating to try that in modern times where there's no hope in hell a project that's been idle for 5 years is serviceable without a bunch of tweaking due to the rolling release, subscription software everyone's been suckered into using.
The software industry is going backwards IMO.
/rant
I felt the same way for a long time, but then I realized that I was paying so much to upgrade my “perpetual license” software to the new version every year or 2 that it might as well have been subscription software
I do prefer subscription software that lets me use old versions that were available when my subscription was still active, though. JetBrains is a good example of this.
On the other hand, I now have several old 32-bit x86 Mac programs that I can’t run because the OS moved on. The Windows situation is much better and I have some extremely old engineering tools that still work just fine.
JetBrains is an example of a subscription designed to damage your development process if you cancel. Rolling back to a year old IDE isn't reasonable. You should get the current version and all previous versions. Once a version is 5 years old they should release patches that strip out licensing / activation.
> I realized that I was paying so much to upgrade my “perpetual license” software to the new version every year or 2
I have no problem with a subscription in terms of the cost. It's cancellation causing the loss of access to tools that I depend on that's the issue for me. JetBrains is the only subscription I pay for because if a project idles for a year then I'm at least into the territory where I can go back and work on it with the original tooling even if I've cancelled my subscription.
I don't particularly like JetBrains' model, but it's half tolerable. They charge $289, $231, $173 for the 1st, 2nd, 3rd year on personal licenses for all products. IMO, make the 1st year $347 and then $173 after that and give a perpetual license for the current version. Updating every 3rd year and being 2 years out of date by the time you update would only save $100 per year over a 9 year cycle and isn't worth the hassle for anyone that actually uses the software regularly. However, having access to the current version of everything if I suddenly need to cancel tomorrow has a lot of value for me.
I think it depends on the app. If it's something that I use frequently I want a subscription. Otherwise, not. The reason for that, is that I look at subscriptions as something I have to be convinced to continuously pay every month. That gives me a lot of power to just disconnect at a later time, and this means that those apps tend to listen to user feedback more often than other apps.
I don't agree. I'm fine with the economic idea of a subscription in terms of creating recurring revenue for developers and think a loyalty discount is a good way to convince people to keep paying, especially for tools that are used moderately to frequently. I want the latest and greatest version of the software I depend on and I don't mind paying for it, but I want to be able to stop paying at any moment and have the only downside be a loss of loyalty discount.
On the workflow / risk side, cancelling a subscription is, by design, intended to be punitive. As soon as you stop paying, the vendor revokes access to your tooling and you're workflow is disrupted. The intent is for it to damage your businesses and processes enough that cancelling becomes extremely painful.
Even the Jetbrains model that everyone seems to love is a total sham because cancelling is designed to damage your development process by forcing you to roll back to a year old version of the software.
It's really unfortunate that things have moved this way, but I'm with you that a desktop client is the thing that feels most alien in this model.
Does Java have a killer framework for this? Something that builds super fast, creates a small executable that doesn't gobble memory like crazy?
That's what devs in this space care about, not the language (as I think this post indicates).
Whilst I don't contest about the executable size does really golang gc is more efficient than Java's?
Given the latter has a much more mature platform I would assume their gc would be the best at maximizing memory efficiency, even beating golang.
As for executable size, JVM byte code is much more dense than executables.
Want to do Web, target the browser.
Want to do native, target OS SDKs.