4 ms·
I spent a lot of time as a Java developer and have recently moved into a spot where I'm being asked to work with C#. A few things rub me the wrong way, and I'm
by great_cormorant 4y ago
I spent a lot of time as a Java developer and have recently moved into a spot where I'm being asked to work with C#. A few things rub me the wrong way, and I'm wondering if it's just ignorance and / or me being stuck in my old ways.
- Unit testing with mocking is kludgy compared to Java and Kotlin (Moq vs Mockito). There's no mocking of concrete implementations for technical reasons, perhaps unless you shell out money for a paid product. This leads to folks putting interfaces everywhere so that code is testable.
- Along the lines of the above, everything feels a lot more corporatized or tied to Microsoft. The open source ecosystem and tooling around C# isn't to the same level of the JVM langs.
- The project structure feels odd. Solutions hide a lot of files from you, whereas JVM langs generally show what's actually there.
When it comes to actually writing implementations, I don't mind it, and it's far ahead of, say, Java 8. ASP.net might even be ahead of Spring in a few ways. But with Java 20 and Kotlin around, I don't feel compelled to move to it as a new default.
- bearzdev 4y agoThere are other libraries than Moq. Nsubstitute, FakeItEasy, etc. With Moq and most mocking libraries, you generally just need to make a method virtual for mocking concrete classes. Most mocking libraries use Castle Project's Dynamic Proxy, so they should be able to inject things without the need of interfaces. Interfaces for everything comes from the .net community's obsession with patterns, abstraction, clean architecture, and DDD. You can use vscode with file based projects. With Rider/Visual Studio you can show hidden folder so long as they are in a folder or subfolder of a project. Otherwise, you'll need to add a solution folder and items to the solution folder.
- great_cormorant 4y agoRight, marking methods as virtual is the other route I saw. Are most C# codebases opting to do that rather than add interfaces? It feels weird to edit signatures like that for testability, but maybe it's just what I'm used to - I'm putting all of my objects in constructors already for testability's sake, and I'm no stranger to making a factory or two. VSCode has been my way forward for file-based editing so far. It's not so bad - just feels like I'm doing things that I ought not to be when I'm searching for DLLs or a random "scripts" folder in the root folder of our repo in Rider. In IntelliJ IDEA, all of the folders are just sitting there, ready for quick edits. I think C# overcommitted on interface-driven design. It's good in some instances, but the more I work in code the more I think that the majority of it is needless and oftentimes harmful to maintaining a healthy code base. Thanks for the pointers! Nsubstitute looks cleaner than Moq at first glance.
- bearzdev 4y agoThat is a good question. I'm not sure. I've seen a lot interface usage for testing web apps or backend services at companies when I was doing consulting work. I personally use stubs for higher reuse, favor integration/functional tests over units, and InternalsVisibleToAttribute to allow the use of internal classes / methods from test assemblies. Its been a long while since I reached for a mocking library. I probably use structs, statics, and extension methods more than the typical dotnet dev. And for DI, I have no qualms just using concrete classes or base classes. I also built my own extensions to xunit to enable DI in test methods, since I do more integration tests. Extension methods for interfaces can be very powerful along with the newer default interface feature. So using that where it makes sense, I get. In dotnet itself, interfaces are only heavily used for key extension points, so you see them more enforcing specific idioms like IComparable<T>, IReadOnlyList<T> or adapter/extensions for System.Data.x, Microsoft.Extensions.x, and Asp.net core MVC. For the adapter types of things there is generally a base class that implements key interfaces and you can create stubs or mocks from those. For the files... for stuff in the root folder like .editorconfig, gitignore, etc. I generally create a virtual Solution folder and add those files to it. For folders with larger amounts of files, I sometimes create an empty project or use specialized project for it like node or powershell project which can be installed as VS extensions, especially if its for a project where the team lives in Visual Studio. That said, I do most of my coding in JetBrains rider or vscode these days and keep a terminal open. When I'm on a windows box, I have nano and neovim installed, so I can just quickly edit scripts that way or just do code /path/to/file as needed.
- diarrhea 4y agoReally liking your approaches and wish our code base followed them more as well. Mocking leads to “interfaces everywhere”, I agree. The latter also results from the attitude of putting interfaces all over, even if there’s just a single concrete implementation that makes sense at any point in time, like a file hashing routine (which of course should just be a function but that’s not a thing in C#). Dependency inversion gone overboard? My biggest qualm with mocking is setting up a detailed test, where every method called is specified, alongside their order etc. You’re reimplementing the entire method essentially. Those tests I despise.
- stevefan1999 4y ago> There is no mocking of concrete implementations That's an obvious anti-pattern in the first place, especially when you know the optimizer could inline hot code and optimize the function out. > Everything feels a lot more corporartized or tied to Microsoft Remember J2EE and the confusing javax stuff? They're the same and fortunately both are waning out. > The open source ecosystem and tooling around C# isn't to the same level of the JVM Isn't that because of the open source community's refusal, rejection and resistance against Microsoft? Not only open sourcing is a first mover takes all, but specific to Microsoft they have been known to be hostile to open source in the past, most prominently one of the former CEOs of Microsoft blatantly called Linux cancer and what do we have today (https://www.theregister.com/2001/06/02/ballmer_linux_is_a_cancer/ https://www.theregister.com/2001/06/02/ballmer_linux_is_a_ca...) Also, it is very well known Microsoft tried to spread FUD in the past in order to kill Netscape Navigator and tried to kill Java until it is almost being antitrusted to the extent of Baby Bells (https://en.wikipedia.org/wiki/Breakup_of_the_Bell_System?wprov=sfla1 https://en.wikipedia.org/wiki/Breakup_of_the_Bell_System?wpr...). Still Microsoft is not friendly nor hostile towards open source given that they let Mono lived, despite using Microsoft's trademarks and patents (you heard me right, dotnet has several patents and ECMA standards before!) It's not like we dotnet people don't know the past shady shit of Microsoft, but I do believe in a convicted criminal could learn from the past, correct itself, move on from the past and be a better person off the record in the long run. It's like a big bully tried to beat off a skinny nerd but now the nerd is as big as the bully now, and all of a sudden the bully found its conscience and begged for apology. It is natural for the nerd to not accept it in the first place. Except when both are nerds and the analogy may sound kinda odd. But I also do understand not all people thinks like that especially for the open source community who is wary of Microsoft may attempt to commit a FUD to the open source community and they do have their memory and thus reactions, I don't have any means to control it. In fact most ordinary people would still choose to reject a convicted criminal in their community instead of accepting even if they have stopped the behavior, because it is a social stigma that indicates this person is of high risk And contrary to Java world, the Oracle situation is getting more and more heated due to its predatory licensing agreement and people are flocking to other Java distributions. This could tear the Java ecosystem apart because it is the .NET Standard situation again and I'm pretty sure histories repeat. By the way, fragmentation is what ultimately killed MIPS and I think RISCV is on the watch. Alas, time as always will tell, just like it's either hit or miss. We should look for a longer vision and see how it shaped out in the futures. > The project structure feels odd No it isn't. It's the multiprojects structure of Gradle, although I'm not sure if you ever heard of it in the first place given your reaction. In JS ecosystem this is aka monorepo but this means .NET Ecosystem actually have monorepos for almost the last two decades!
- paulddraper 4y ago> There's no mocking of concrete implementations That was always halfway between oxymoron and forbidden magic.
- jeremyjh 4y agoIs hot loading the default in JVM-ville circa 2023 ? God I hope so, I remember downloading these third-party builds and 180 characters of args or something to get that going + whatever voodoo was needed to make your janky framework respect that, make your IDE use it etc.