Once over the [quite low IMO] initial 'hurdle', it's easily amongst the most productive & best-supported "platforms" I've ever worked within.
That's the best summary of the .NET stack, unfortunately it requires first-hand experience to figure it out.
In the repl?
I have no experience with .net and it looks like these repls are new
Since then I am not able to take seriously the saying of .net to be "incredibly productive".
What were the actual issues and what would've made it more productive? That's much more useful for discussion here.
The backend had to receive events from a webhook and accumulate statistics on those events, then serve these statistics via REST API
Frontend was plain old React reaching the REST API.
Issues:
* The database (MS SQL Server, as recommended by Microsoft) would randomly lock up for days. Bear in mind this was a 1GB of RAM (the minimum amount that Microsoft accepts as enough to run a SQL Server instance) RDS serving around 600 MB of data.
* The introduction of the Repository Pattern (as recommended by the ASP.net documentation) introduced a lot of complexity (including incompleted/non-defined operations) that slowed down significantly the development.
* LINQ supports interleaving DB operations with not-db operations, quickly becoming a O(n^m) footguns. If you make `row => row.x > 5` a method, LINQ will happily download all the rows and run the comparison in program instead of in the DB. Bear in mind I can't construct these footguns with django ORM, or make them typecheck with any Haskell data access framework.
* The test runner UI would pretend no tests existed if the code didn't compile for any reason. Trying to debug something by running a specific failing test? If you miss a semicolon now you have to go find your test again.
* The logger would log the message and the affected class in different lines. Do you want to grep for an error? You better know the obscure grep syntax for "previous line". Want to change the logging format? Good luck finding the code that adds the newline in order to find how to influence it. If you ask the IDE to find the implementation of the logging function it will show you the interface, nothing more.
* You better not do some type of async stuff in LINQ, because the system is going to spawn a process for each entry, obliterating your production instance by creating thousands of processes, using a bunch of MB for each process.
There were more issues, I didn't make an exhaustive list of them because, you know, I don't need to make exhaustive lists of malfunctions and bad design ideas for other programming languages.
Footguns are common.
I am not sure where the .NET community coalesces (python and similar tend to hit up IRC).
I don't understand the dotnet's extension ecosystem -- how to find quality sourcing, etc. Going from an established project into dotnet SDK makes sense. But searching GitHub for useful dotnet frameworks -- stars are probably misleading here?
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.
Also, just sounds like you hate Microsoft, and are looking for (poor) excuses to continue your hatred.
Was the server running Windows? Windows doesn't perform really well in 1G of RAM, especially if you're running GUI Windows and not Windows Server Core. Then running SQL server on top of that, well that 1G RAM probably IS the performance issue. A good rule of thumb is Window takes 3G, and your programs go on top of that.
There were clearly other issues from what the OP described though, and to use LINQ you do have to have a good clear mental model of the runtime actions that it give you. It's a power tool, and can let someone experienced develop very fast, or let someone inexperienced cut their fingers off equally fast!
To provide an answer to OP, about following MS recommendations .. the reality is that not all MS advice is good advice, and also that with so many versions not all of their documentation is up to date. However it seems your team did draw the short straw! Mostly their documentation is very good for product and API level documentation, not as good for architectural documentation.
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.
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.
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.
A big thing that people often don't understand about .NET is it has the perspective of being all things to all people.
One example of this is that it gives first class support for supporting living extensible systems for long durations like decades which is often not really the case for other stacks. Hence the prevalence for approved long term supported libraries typically with first party backing from MS.
Another aspect of this all things to all people is that it has lower level closer to the metal performance features that people only used to high level stacks often mention they don't see the need for (although they don't say it like that!).
Another aspect is you can do pretty much any kind of application in it, from web to native to high performance games or latency sensitive systems (with some special techniques) to well almost anything. The ability to access low level performance while still having high level general ergonomic APIs is critical to this.
> 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.
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.
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.
It's true, EF abstracts the database away by not requiring you to write SQL but EF is only usable with some SQL databases.
So, having another abstraction layer might not be a bad idea.
Then in startup.cs or program.cs, add this to your services: optionsBuilder.UseCassandra("Contact Points=127.0.0.1;", opt => { opt.MigrationsHistoryTable(HistoryRepository.DefaultTableName, "<schema name>"); });
See more here: https://efcorecassandra.readthedocs.io/en/latest/intro/getti...
You can't. There is no such thing as switching databases "with ease" for any serious application.
Postgres, Redis and Cassandra are all very different databases and it doesn't make sense to switch between them; unless your app is small and still experimental so the changes are trivial, or so large that it's a major project with very specific needs that requires far more work than a repository would solve.
But if you really want to, Entity Framework already has multiple providers including non-relational databases like Cassandra. Anyone can write a provider and there are many 3rd-party libraries for whatever data source you want.
> "having another abstraction layer might not be a bad idea."
It's a terrible idea. It's such an exceedingly rare situation that you're wasting a lot of upfront work for something that'll never be used.
Also .NET has a fantastic data system with LINQ which is built around `IQueryable` and provides powerful query modeling that can be incrementally and dynamically changed before its pushed down to the datasource. It's what makes EF so good and why repository patterns cause so many problems by breaking this interface for no productive reason. You can also use extension methods on the `DbContext` to extract complex queries or large operations to a single method.
Now all that being said, there are times where you can have an abstraction/interface to your data sources if they're very complex or spread across multiple databases or have other processing needs. But at that point you actually need it, instead of just doing it as a "pattern".
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.
My ego is not unfounded, I have had to do this successfully in other projects, but I can only do it if both the tools, the codebase and the framework allow me to do it
Your explanations of what went wrong show clearly that you still don't have a grasp of how async/await works. So you don't understand the concept, which is now common across a number of languages including javascript (which you claim to know) and python (which you claim to know), dart, and scala.
Based on your technical knowledge of languages you claim to know, I would say you are closer to a junior developer.
If I'm a junior, 99% of the professional programmers out there are simply not programmers at all.
I feel you on the hiring bit, there's such a glut of resume padders, bullhockey purveyors, enterprise leftovers in .Net it's hard to find good people (especially in the US). If you put feelers out to any recruiting firm you'll receive a who's who of people no one will hire. There's also not much of a community to speak of compared to other platforms (what community there is is spread out across numerous platforms or centered around MS, github) so there's not really anywhere you can post your jobs and expect a positive result.
To anyone trying to hire heavy lifting .NET expertise, I am now looking for an interesting fully remote role!
I've been using .NET since V1 and Delphi before that so I have deep exposure to getting things done with this stack and would prefer to work with it compared to most others. I've also worked commercially with about 10 languages so fairly polyglot, just find C# very powerful with a focus on GTD.
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.
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. :)
* 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.
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”.
The entire premise is dubious, and even if the premise is correct, blaming it on the framework without any other evidence seems like a stretch.
On the projects I’ve worked on recently, the backend often ended up far more complex than the frontend, taking up more time to build and maintain.
This is natural. The backends were responsible for interfacing with other systems, like databases, 3rd party APIs and message queues, for example.
The frontends, on the other hand, generally interfaced with only one system: the backend.
Am I arguing that the frontend is never more complex and time consuming than the backend? Not at all.
But I don’t think you can blame the backend stack and tooling for the resultant imbalance of complexity between the two systems.
And asp.net is fantastic for webapps, especially now that Blazor has become so capable.
The upcoming MAUI framework is also encouraging and should make cross platform native UI development much nicer.
From an objective standpoint it's not a valid comparison. Blazor still has a number of fundamental deficiencies in regards to how it interfaces with the DOM event model via its messaging abstraction. You can't create a symmetrical set of tests without dropping concerns Blazor can't accomplish without custom JS, or limiting the scope of comparisons to what Blazor can do.
The best answer I have is the recent Blazor presentation from Steve Sanderson (the original author) from NDC Oslo conference on 2/21/2022: https://www.youtube.com/watch?v=Rn8psTi8FBk
It's 1 hour and will explain in far more detail exactly how good it is, from hot-reload (which is massive), importing other packages (including native Rust or C source like SQLite), unified server/wasm APIs, prerendering/hydration improvements, EF Core wasm, and even integration with existing JS react/vue components.
Blazor WASM is still unfortunately slow on load, however the recent Steve Sanderson video on Blazor in .NET 6 showed impressive client runtime performance once loaded, by doing virtualized UI access to in process Sqlite for a truly native client performance much better than the current gen SPAs and getting back to how good software used to be, literally instant scrolling over tens of thousands of records.
But Blazor server is really excellent, recommend it.
- https://www.youtube.com/watch?v=LUlbO5MjPjU - https://www.youtube.com/watch?v=HMYpAw2sl58
The main repo has links to all of the announcement posts for every preview milestone release which goes into far more detail: https://github.com/dotnet/maui
If you stopped working with .NET and C# around version 4, the language itself has transformed.
Local functions, pattern matching, records, and more!
Yes, I think it is the best ORM in terms of productivity, but it is very, very slow. This is usually not a concern for internal enterprise applications that only have a few people using them at a time though. I guess the other issue is just an issue with ORMs in general - you lose a lot of the in-built features of your sql database, which as projects progress, can ultimately result in you writing the same amount of code as if you didn't use the ORM.
You also can't switch programming languages without rewriting the entire database section. Personally, I stopped using ORMs altogether because I find that they make easy things a little easier, and hard things harder, which isn't a very good value proposition overall. They don't really save me time anymore.
That was long time ago and EF improved a lot since then.
But it can be slow if used improperly. But hand written SQL can be slow too if not carefully crafted.
Sometimes small changes in fragmentation, statistics or data composition will trigger a different queryplan which will affect your query immensely.
Good monitoring and a DBA nearby would be your best bets to overcome this. The point is that using a relational database is not a trivial thing once the database becomes large. Until then its relatively simple.
It does have a built in footgun where for some structures it defaults to invisibly lazy loading sub-collections, you can (almost certainly should) disable that and specifically tell it to populate that data in the first query using Include() or any of the other projection mechanisms. Is it possible you had that?
The benchmarks model simple, but real world scenarios. It has breakdowns by EF, Dapper (the StackOverflow "micro-ORM"), MySQL, PG, and raw ADO.NET.
It should be noted that EF and EF Core are not the same thing; EF Core is more or less a full rewrite: https://docs.microsoft.com/en-us/ef/efcore-and-ef6/
Recent benchmarks have EF Core catching up to Dapper. You can read more about Microsoft's focus on performance for EF Core here: https://devblogs.microsoft.com/dotnet/announcing-entity-fram...
The other thing is that for all ORMS, for the small amount of queries where it really matters, you should drop down to hand-written SQL anyway if the juice is worth the squeeeeze!
Node has so few "batteries included" that you spend a ridiculous amount of time searching npm.
That's especially bad because Node's ecosystem is a graveyard. There are 3-10 libraries for everything, and (if you're lucky) one will be well-tested and maintained. And even then, you're very rarely going to find something that's also: 1) maintained by more than one person, 2) used in production by well-funded developers, and 3) able to keep up with their Github bug reports.
In some cases, I have to try 2-3 libraries before picking one and often switch to another one later.
.NET, on the other hand, has a great ecosystem, batteries included, and (if needed) usually a commercial library for the really important stuff. It's just a far more stable and serious ecosystem in general.
And that is not Javascript's fault because it was never intended to be anything else that a small script language to interact with DOM in a web page and add a bit of interactivity to HTML.
For Web API maybe Go is a reasonable contender if you put up with the boiler plate and verbosity.
As for mobile apps, I didn't encounter anything as productive as Xamarin while being reasonably multiplatform.
I didn't do desktop apps since ages but I remember QT and Embarcadero's C++ builder as being quite productive.
But one platform to do it all? There isn't other. Javascript is today used everywhere but I wouldn't quite qualify it as productive or performant. And countless frameworks and libraries competing with each other kind of makes it a mess.
On the RoR comparison, while coding speed is similar, Blazor is an advancement, and then the runtime perf of .Net 6 vs RoR means having less servers, less cost, and less scaling challenges!
Techempower round 20 has ASP.NET at 309,458, compared to RoR at 8,260. That is 37 TIMES faster for .NET. Think of that as 37 times as much AWS bill for your RoR startup ..
Not that entity is bad in any way, it’s just not as productive. Which is sort of how I have it with most of the journey into TypeScript. It’s just a really great environment especially in Azure Function apps, and a massive cadeau to Microsoft for making the node in docker such a first class citizen in their Azure environment!
In many ways I feel like TypeScript is a mix of the best of Python and C# and that’s just wonderful, for me.
But writing things like Odata APIs in .Net sure has some benefits from the massive work Microsoft has done with the .net and C# environment since moving core into the main .net or however you describe it.
So now I’m not sure where I am going with this, I’m probably just very appreciative of the work Microsoft has done for us enterprise developers in non-tech enterprise in the past few years.
It's also lacking support for a lot of data types on PG.
It's crazy that EF Core has providers for everything from SQL Server to CosmosDB to Google Spanner to in memory DBs.
LINQ and expression trees are probably one of the best features of .NET.
It is good, but it's just better to learn TSQL/SQL Server if you are on a windows stack. Shouldn't use it as a crutch especially if you working on the back-end side. Entity framework was created to make data access easier for the front-end people.
They also removed the intermixing between server logic and db logic, which greatly reduces nonsense occurring
Edit: thanks :)
YARP gives you all of the building blocks you need to build a simple proxy just as easily as a highly complex one.
Push they’re buttons all the time calling them Microsoft fanboys… that will get them going. Secretly they like it.
Btw, I know this is superfluous and very shallow, but for some reason, I can’t get over the C# syntax because of how enterprisey it is. I much prefer ruby, but I guess it’s a matter of preferences and taste
This quality is attractive to managers who benefit by increased headcount, and prefer to have their "reports" or "resources" less generally capable, and more easily replaced or shuffled. Total cost is much higher, but individuals' salaries are lower, which makes managers look good.
Java and .Net are both very enterprisey platforms.
You understand that all the things done in Java and .NET’s “enterprisy” way can be done is most languages right?
This is a programmer problem not a programming language one. Today you have to write less in C# than GoLang, to do the same tasks. Does that mean GoLang is enterprisey now, just because you have to write more?
And, it is not a programmer problem. It is a management problem. None of them would exist without management demand for minimally-productive languages.
Tell me about this secret non “enterprisey” stack you are using.
Think of that as 37 times as much AWS bill for your projects in RoR.. what were you saying about the syntax ¯\_(ツ)_/¯