Sure it compiles. But often it crashes without rhyme or reason and for some reason, customers hate it.
First thing I did was to get it from .net 4.8 to .net 7 and enable all available errors checkers and style linters.
The other howled, but their builds stopped because they could no longer check-in crap. That helped. But fixing this is more work than what this would have needed if they had done it right the first time.
Funny examples: reinvanted rabbitmw badly using raw TCP and XML. Better hope your network is good, If the messages arrive at the same time, they are merged and the app crashes. So there are lots of time.sleep(50) calls to avoid that. Why is that app slow?
The iot devices can only address 254 states. The UI for that allows ulong devices. It's never checked, but if the vast fails, the app just crashes.
This might not have been a great idea, I'm fairly surprised nobody stopped you before you went through with it.
4.8 is the "final" version of .NET Framework. It's pretty much the longest "Long Term Support" offer Microsoft will ever give for a platform, realistically they'll be supporting it into 2030 and beyond. I'd not start any new projects in it, but upgrading away from it probably wouldn't be the first thing I'd do on a new project.
From .NET5, the framework moved to fundamentally different approach. It's effectively a different framework with the same NET branding on it. Most organisations who decided to move from 4.X to 6.X went through a near total rewrite because the paradigm shift is so massive, lots of organisations decided to stick with the pre-5 versions. The architecture and technology choices probably make a lot more sense in the pre-5 version of .NET, and it's unsurprising that your colleagues are frustrated with this decision, irrespective of the quality of their code.
On top of the move between .NET paradigms, you've moved away from a long-term-support version. NET7 is an 18month short-term-support interim release between two Long Term Support 36month versions .NET6 and .NET8. By moving to 7, you've trapped the company into an early & rapid upgrade path to .NET8 as soon as it comes out in Nov 2023, rather than giving the full 12 month buffer you'd have got if you moved to .NET6, which is in Long Term Support until Nov 2024. You moved the application off of a rock-solid framework with near infinite long-term-support, onto a framework that'll be deprecated before in four months, and out of support entirely in ten.
If I were you, I'd probably not be bringing this decision up in any performance reviews or interviews at new companies.
We moved from 4.8 to 7 because a) the better compiler warnings helped to reduce the amount of shit people where able to check-in AND highlight problems in the existing codebase (beyond "well, it looks like written by the lowest bidder offshore guy drunken on Friday night") and provide management with metrics they could understand (two warnings per LOC is part of your problem). B) it deepened our hiring pool, because it's easier to find people willing to work with current technologies than legacy. C) it allowed us to pull in various modern libraries (BLe especially) which made whole swathes of swamp code irrelevant. D) allowed us to establish a sane Ci/CD Pipeline more easily which we needed to reject bad stuff. F) we ship this product every few months, so not being on lts is not really a problem.
But this crowd believed it obviously. The chief perpetrators already left when I got there, so I could not ask directly. Zero tests, zero documentation and a coding style like somebody tried to write pure C in c#.
In actuality, writing software that is some quality is so hard that one needs all help one can get. One absolutely needs type checking and is just not professional without. One absolutely needs automated tests and is just not professional without. One absolutely needs manual/exploratory testing and is just not professional without.
If culture is that tests are necessary, then these people hide and write their tests (or actually learn that test-writing makes sense).
I am in an organization currently that values testing overall, but being in a regulated industry its almost a little over-done, the result of that is, that for prototypes, tools, etc. the rules are weakened, leading to this weird situation where "of course we write tests, but this was just our prototype, that runs in production, for 3 years" seems to work in some departments...
Just because something works, doesn't mean we can't improve it, and just because we can deliver value with one tool, doesn't mean that we couldn't be delivering more value with other tools.
Granted, this has the potential of the opposite problem, convincing detractors that static analysis didn’t find much, but that can be avoided by keeping a list of the bugs that were resolved ahead of time.
For people who know nothing but JavaScript and dynamic typing, it could be.
Just because something is 'legacy' doesn't mean it's crap. It cauld be well thought out and easily maintained.
I've been dealing with a straightforward legacy api in JS. Trying to port it to typescript, the hard part is typing classes with dynamic propertied based on a schema. Has worked great in production for years. Well tested. I have to rewrite it to make it workin typescript apparently. going from about 10 line files to 50+ just for typings. Im sure i'm doing something wrong, but i've asked and it seems my code is wrong? despite having worked great for me all this time.... Yes i'm salty
That said, some people see TypeScript as "Javascript, but with types in the definitions", but it's more than that. Sure, the core of it is that you're adding types to your code, but with things like KeyOf<>, Partial<>, Pick<> and other such utilities the TypeScript system is a lot more powerful than that of many statically typed languages.
Typing dynamic JS with TS can be tough because complex dynamic typing requires a lot of assumptions that often are half-truths from a programming language point of view. "When x.foo is a Number then x.bar.baz is a String with at most two characters" can be expressed in Typescript but it's very verbose and requires some digging through the Typescript docs to get right.
Describing types does add more lines of code, but that's not necessarily a bad thing. What you're doing is taking the implicit assumptions based on your dynamically typed program and expressing them in a way that can be verified. Assuming you don't invent completely new types in every single function, the initial typing workload is high but it becomes a lot easier over time, especially if you use your Partial/Pick/keyofs well.
What I found to be helpful is that the ?. operator has been added to Javascript quite some time ago (legacy JS doesn't normally use it) which means you can define properties that don't exist in the beginning but are set down the line to be of type `foo: string | undefined` rather than invent implementations of interfaces for every modification step of the program, using it through `bar.foo?.baz` rather than `bar.foo.baz`, and maintain the exact same assertions your program had before.
Alternatively, using `!` when you're absolutely 100% sure some parameter has been filled in (`bar.foo!.baz!`) can help convince the transpiler of assumptions that can't easily be expressed in code.
Thousands of files all become filled with very obvious bugs once you enable a basic type checker, which then helps brand Typescript as "too much effort" by those who normally write Javascript because now they need to deal with their buggy code. Luckily you can just explicitly cast all of your types without checking and hope that nobody notices!
When you ask people to get their typing right, someone will use buzzwords like "rapid prototyping" and remind you that features are more important than fixing the existing product as long as nobody complains about the bugs, and that's that. Also, Typescript is hard, apparently.
Untyped legacy code sucks. It's one of the reasons I detest working with languages like Javascript, Python, and PHP. At least Python and PHP have types these days, making Javascript objectively inferior.