Based on this anecdote, it sounds like the team had little or no .net experience and your seniors probably don't deserve the title.
Curiously, I haven't had these problems in Python/cherrypy/django/flask, Haskell/snap/yesod, NodeJS/express/nextjs, so, maybe it's something beyond lack of .net experience.
Your experience mirrors mine, both early (circa 2005) and more recently.
Footguns are common.
I am not sure where the .NET community coalesces (python and similar tend to hit up IRC).
There's been lots of bad decisions along the way for .net, but In its current state (.net Core 6) I can't really see any of your problems happening. Although what strikes me most is your first point. Running SQL server on 1gb and complaining that it didn't work well isn't really wise. Maybe this happened on the early years of .net Core or even on FF?
I'm following what says at the official Microsoft documentation.
https://docs.microsoft.com/en-us/sql/sql-server/install/hardware-and-software-requirements-for-installing-sql-server-ver15?view=sql-server-ver15 https://docs.microsoft.com/en-us/sql/sql-server/install/hard...
Am I unwise for following the official Microsoft documentation for a Microsoft product?
Yes, I'm unwise for following it. I shouldn't have accepted the project because it required Microsoft technology. That would be wise.
The documentation you linked to clearly states that they recommend 4GB of memory and more for larger databases. While it CAN run on 1GB of memory, it is also therefore NOT recommended. You chose to go the route of the unrecommended.
Also, just sounds like you hate Microsoft, and are looking for (poor) excuses to continue your hatred.
We were using the Express edition, and I don't think a database needs 4GB of RAM for serving 600MB of data in a glorified CRUD and filter application that receives 1 update every 2 seconds, and serves a bunch of queries every 5 minutes. An unoptimized Sqlite can do that easily without the crazy memory.
That makes more sense, sorry for the confusion. I don't think your expectation is unrealistic. I haven't run into anything like what you experienced, but my exposure to express under tight memory constraints isn't something I dabble in.
Did you perhaps use dynamically generated queries, instead of stored procedures? Or do a join onto either table x or table y?
In my experience the biggest problem with C#/.NET tooling is the lack of too many open source 3rd party alternatives.
In the .Net world, if MS released a certain library, that would become the de facto choice for nearly everyone in the ecosystem. Competing with the MS options was almost impossible.
So even if the MS choice had a lot of flaws, it would remain predominant.
Which meant that as long as the MS option was good enough, you wouldn’t see too many alternatives unless they were an order of magnitude better.
And a large reason for this was the closed source nature of .NET.
In the open source world, even if the primary vendor option is great, but it has only a single minor issue, someone will invariably fork it and fix the minor issue. Which puts competitive pressure on the primary vendor to incorporate that fox, or if they’re unable to, see a lot of people migrate to the competing, slightly better offering, which is easy to do since it’s basically the same product with that 1 slightly better fix.
In practice the original vendor almost certainly incorporates the Fox, especially since it’s so easy to do as someone else has already written the code for it.
So IMO the problem with the .NET/C# ecosystem used to be it’s closed source nature, which led to very little competitive pressure for improving tools and libraries, unlike all the primarily open source alternatives you mention.
> In the .Net world, if MS released a certain library, that would become the de facto choice for nearly everyone in the ecosystem. Competing with the MS options was almost impossible.
While I get your point, I personally prefer it this way. Whatever Microsoft will put out will at least be “ok”, regularly bug fixed and supported for ever and ever.
I prefer to having an ok default and just rolling with it.
And having a default library for everything is great since you don't have to learn countless libraries doing the same thing and you can understand code written by others with ease.
But this is a tacit agreement in the .NET world. It's not only about libraries written by Microsoft. When sensible libraries such as Automapper or Newtonsoft JSON appear, everybody defaults to them.
For the benefit of others who might get the wrong idea, async/await definitely doesn’t spawn processes and in almost all cases not even extra threads.
Was this the first time using .NET for most of your devs?
> LINQ supports interleaving DB operations with not-db operations
This hasn't been the case since EF Core 3.0, it will throw an exception if something can't be translated to prevent this problem. Prior to this (EF Core 2.2), a warning would be spat out if an in-memory operation occurs. Due to this, I assume this project was a number of years ago.
> The logger would log the message and the affected class in different lines.
The default logging format is unfortunate, although it can be made a single line in .NET 5 onwards. This issue would've been easily solved by using Serilog, swapping out the built-in logging with a few lines of code. I don't know the last time I encountered a .NET dev that wasn't at least aware of Serilog as an alternative.
Keep in mind I've never done ASP.NET (only desktop development):
The old C# stuff is indeed crusty, intermixed with hot nonsense from the Balmer days.
Latest Framework version is I'd say OK, nothing to write home about, newer stuff is much better (.net 5, 6).
I do think MS SQL Server is a bit, well, bad. But don't worry, irrelevant to the C# stuff - I used to use java servlets to query mssql, while it was better performing than mysql, I wouldn't pick it again.
The anecdote about the React frontend bit is interesting, but ultimately depends on what the UI was doing. JS is certainly good to bang out some quick UI, but if it was shell for the backend, I'd say your app was either mis-designed or just naturally backend heavy.
Again, haven't used (not in web dev right now), but Blazor exists for doing C# web UI, instead of complaining that the backend was bad/hard a better comparison would be between Blazor and React.
Or you could switch architectures and do a non-component-based web UI - faster to put together a mashup of JS junk but it doesn't necessarily perform as well as doing a web client old-style - simple request response works for a lot of use-cases, its not as flashy, but it is fast.
The (Generic) Repository Patterns are some of the most anti-patterns created and goes fully agains't DRY and SOLID, it's like whole generations of developers are just on the same cargo and have never worked with a database( or datasource) having more than 1 table.
So it looks great for a blog post, for a linkedin thought leader article, but when actually used, you end up duplicating the same shit over and over and over unless you use extension methods. But then why having the damn Repo patterns with the basic methods in the first place?
These patterns are just awful and don't solve anything, abstraction of the DB? You don't need that pattern for that.
Your last point is not how threading or async works in .NET. It’s a single process that has a thread pool that runs async Tasks. The rest of the comment indicates that the team didn’t have much or any experience with .NET.
I’m sure there are issues with learning curve but the ecosystem is very capable (the corollary to being very productive) but you need to know how to properly use it.
All that sounds like poor app design.
Microsoft doesn't force you to use SQL Server. I used Postgres and Redis for a quite big microservice based app.
Repository isn't mandatory, however is nice to separate the business logic from the details of the data store or database. Using a repository shouldn't be a a problem unless you are doing it wrong. I've seen enough of poor repository pattern implementation. I would question the skills of the developers here.
LINQ was not used properly if you had mixed IEnumerable and IQueryable based queries. It's not frameworks fault here, I'm afraid.
The system is not spawning threads for async requests, it's just creating Tasks which cost very little since they aren't physical threads. Think of goroutines, not threads.
All the things you mention seem to be due to lack of experience. I am not sure how using another platform would have yield better results, skill sets remaining the same.
It's not a problem if you try a new language, platform or framework as long as you don't just churn out code assembling method calls based on name (. NET makes this very easy because of intellisense) and examples found on Stack Overflow. As long as you understand what the code does, you are fine.
So the problem is that I'm using Microsoft's recommendations (Sql Server, repository pattern, LINQ) for a Microsoft product, and the difference between an inexperienced team and an experienced team is that the experienced team knows what list of recommendations coming from Microsoft are actually the ones you should follow in order to bypass most of the footguns.
I think I'm going to go with frameworks that have the actual best reccomendations baked in, instead of the frameworks that recommend footguns.
>I think I'm going to go with frameworks that have the actual best reccomendations baked in, instead of the frameworks that recommend footguns.
For every good framework, regardless of platform and language, there is going to be a learning curve. That's because flexibility and extensibility add complexity.
Only a trivial framework with limited use cases would not allow you to make mistakes. I take it you never used C or C+=, because there's a footgun waiting for you at every keystroke. :)
It’s interesting to look at this from the perspective of an experienced .NET developer, because you’re not wrong:
* SQL Server can be incredibly fast with good access patterns, but the rest suggests you didn’t have those.
* Yeah, the repository pattern is garbage. I prefer just define the operations you need and use Dapper.
* I know some on here are wild about Entity Framework, but personally I’d rather write the SQL myself. You need a good mental model of what’s going on under the hood or what you’ve described happens.
* Honestly never used the default test runner because it seems pretty bad. NCrunch, however, is incredible and doesn’t suffer from this.
* I don’t think I’ve ever worked anywhere that used the default logging implementation and yes, that format is weird. (You can, however, step into the logging code if you want.)
* Depends on what you’re doing, but yeah 10,000,000 Task.Runs is not going to perform well. But I’m not sure the equivalent code works well anywhere except possibly BEAM.
So whilst none of these things cause me problems on a day-to-day basis, I can 100% see how inexperienced devs could drive straight into that tar pit.
> LINQ supports interleaving DB operations with not-db operations, quickly becoming a O(n^m) footguns.
This is no longer the case since EF Core 3.0. Only top level projection can contain expressions that aren’t translatable to SQL.
> You better not do some type of async stuff in LINQ, because the system is going to spawn a process for each entry…
I wonder exactly what you ran into. This is not an accurate description of how EF Core’s async support works. Not even if you replace the word “process” with the word “thread”.