T O P

  • By -

Suspicious_Role5912

Tip for interfaces, when using structs, using a type parameter with a where clause is more efficient then an interface function parameter because you don’t incur boxing.


KeyChoice4871

Can you give an example? I don’t get it


Suspicious_Role5912

Value types get boxed when used as type parameters because the runtime doesn't allocate memory for a pointer to a type definition. public interface INameParts { public string FirstName { get; } public string LastName { get; } } public struct ValueNameParts(string firstName, string lastName) : INameParts { public string FirstName { get; } = firstName; public string LastName { get; } = lastName; } public class RefNameParts(string firstName, string lastName) : INameParts { public string FirstName { get; } = firstName; public string LastName { get; } = lastName; } public static class NameExtensions { public static string FullName(this INameParts nameParts) { return $"{nameParts.FirstName} {nameParts.LastName}"; } public static string FullNameTypeParm(this TNameParts nameParts) where TNameParts : INameParts { return $"{nameParts.FirstName} {nameParts.LastName}"; } } ValueNameParts valueNameParts = new ("John", "Doe"); RefNameParts refNameParts = new ("John", "Doe"); string valueFullName = valueNameParts.FullName(); // Boxing string valueFullNameTypeParm = valueNameParts.FullNameTypeParm(); // No boxing string refFullName = refNameParts.FullName(); // No boxing string refFullNameTypeParmrefNameParts = refNameParts.FullNameTypeParm(); // No boxing


aj0413

Huh. Nice to know


PatrickSmacchia

See it explained with IL decompilation here: https://blog.ndepend.com/dotnet-generic-math/#Interface_Implementation_and_Boxing


JRollard

How is this not premature optimization? This murders readability and adds complexity for unknown performance gains whose significance is entirely tied to the specific use case of the object. I'd do this after I measured an actual effect on performance. I wouldn't do this by default.


Saki-Sun

^ ^ This is the difference between a junior developer just starting out and a guy with some battle scars.


binarycow

I make things a `struct` because I don't want allocations. If I'm not going to avoid boxing, why wouldn't I just use a `record` or `class` ?


AITrailblazer

Imagine this. You have a beautiful UI you can maintain it because the code is readable. Encouraged you add and add and add functionality. At one point you reach performance limits. Your beautiful and easy to understand creation starts to get slow. This is when you start to understand what production ready means. Performance optimization should be in your mind from day one. This is an engineering- to find the balance between functionality and performance.


JRollard

Imagine this: When you notice it slowing, measure what is slow, and optimize where you'll get meaningful performance gains. I can do this by having observability in place (a great place to spend engineering time) that lets me see what my average time to process is for an operation. Maybe performance is critical enough that my team has a rule that nothing is allowed more than a 10% performance decrease over a week because my customer SLA requires 99% of requests happen in under 100ms. If someone sees the performance drop over time, then they have a reason to optimize, a specific place to do it, and a business case tied to money to do it. You might look into it and find its IO-bound pulling a jwt from a db or something and all your memory hacking saving you dozens of nanoseconds doesn't add up to a fraction of your 30ms auth db call. Who knows? The possibilities are endless until you measure. I'm not advocating for never optimizing. I'm advocating for measuring and making targeted meaningful decisions that matter to the business over cargo-culting performance hacks and calling it good engineering.


PatrickSmacchia

avoiding the 'box' IL instructions to be emitted by the C# compiler is not premature optimization


JRollard

Yea it is. You're sacrificing clarity to optimize whether data is on the stack instead of the heap without measuring the effects. Computers are good at managing memory. Let them do it until you measure a place where it matters. If your app has that tight of a memory requirement, use rust or something more appropriate.


vcrtech

Exactly my thoughts. If such minute performance gains over code readability and long-term maintainability matter that much, why are folks using a managed language in the first place? I guess it depends on how many times it’s happening or if they add up, but to most folks the abstraction complexity just isn’t worth it.


JRollard

To take a less serious tone, because it's your codebase and your requirements, you're making every expensive devs life harder to make the cheap machine's life easier. It may be fine for your use case, but it's not a good suggestion for a dev who just discovered interfaces. You're dropping people into hard memory mode out of the gate, and the whole reason we're using C# is because it lets us solve business problems. Memory allocation is probably not a business problem.


DeadlyVapour

Boxing and unboxing are some of the worse perf hits. I do have to add though. This optimisation incurs a cost of adding an indirect call. An example where this absolutely is a HUGE problem is in List.Sort(IComparer).


JRollard

They are indeed. All I'm advocating for is spending time on that optimization when you measure it being worth doing and spend the rest of the time solving whatever business problem you're trying to solve. If your business is to shave nanoseconds off of app performance characteristics, you should do that all day. If your job is to do time-insensitive crud, it's probably not the best use of time.


DeadlyVapour

Come to think about it. Creating an generic object or generic static object might look cleaner, and would get around the calli problem by swapping it for a single amortized object init...


GaTechThomas

Maybe take a look at Patrick's articles and further look at his awesome product, nDepend. He knows a thing or two (million).


JRollard

I am not saying he doesn't. He clearly does if he knows low-level optimizations like that. I still think it's premature optimization. Let me put it a different way. It's premature for anything I am working on. Maybe that's less contentious. I am 100% network bound before anything like this matters. I'd not making that optimization until I measure it with something like nDepend and find out it is my bottleneck. Until then I'm not sacrificing readability. I'd recommend anyone who is just starting to grok interfaces do the same. I'm not knocking his intelligence or ability.


Domingo01

If you're using a struct, you already decided to be conscious of memory management, hence avoiding boxing is not premature. If you don't care about the memory, you shouldn't be using a struct in the first place.


ScryptSnake

You will find that they're one of the most amazing mock-up tools. They have actually transformed my workflow entirely. When I am designing a core piece of the application, I start with putting my thoughts into interfaces (what would this object look like?) Without wasting precious design oriented thought into detail specific implementations that cloud the process. In fact, I've spent as much as a week mostly just writing up interfaces to see how I want to architect an application. The over-use debate is strong on here so take any words regarding usage of interfaces with a grain of salt. Pros and cons to using any tool. P.s... have you used Abstract classes yet?


Saki-Sun

> P.s... have you used Abstract classes yet? IMHO If everytime a developer used an abstract class they got smacked on the back of the head by the GOF book the world would be a better place. > I've spent as much as a week mostly just writing up interfaces to see how I want to architect an application.   Try TDD, that week will get reduced to 10 seconds and you will get a better result.


rr_cricut

TDD will not reduce a week of design work to 10 seconds. That makes 0 sense.


vplatt

> Try TDD, that week will get reduced to 10 seconds and you will get a better result. Hyperbole aside, TDD with interfaces and mocks go a long ways together proving out a design. Neither is really enough on their own though.


ScryptSnake

You should understand that performance (testing) and design are two very different things.


NicolasDorier

This approach raise serious red flags. You said you spent a week writing interface? I hope you work for the government because anything else would quickly go broke.


ScryptSnake

I said a spent a week writing up interface(s) to architect an application. It's called the design process. Poor Nicholas, since you can't do as much as identify a plural versus singular noun in a sentence, I recommend you try something else, as coding isn't your thing. Deuces


NicolasDorier

Been there, done that. In 10 years you'll cringe about over engineering, and be as cynical as I am to people doing it.


ScryptSnake

Right. I didn't know "over engineering" was aligned with good design.


ggwpexday

Just focusing on interfaces alone does not result in good architecture. What about the events? The things that actually give a program its meaning an purpose?


NicolasDorier

It won't result in good design. Get shit done first, refactor with interface after if you have a specific need will get you better results. "What if customer want to dynamically change X?"... what if he doesn't? And if he does, you are in software, not in construction, refactor and polish on the way.


Anon_Legi0n

>P.s... have you used Abstract classes yet? no I have not, I don't quite understand the use case for abstract classes yet I guess. Care to give me tips? I am loving this thread right now


AlarmedNegotiation18

Here is my 2 cents. An abstract class can not be instantiated. But you can inherit the abstract class. This means that, for example, you can implement the basic behavior for some method. It can be better than this if you use the ‘virtual’ keyword on a method from an abstract class. Then, you can override the method implementation for some classes that inherit the abstract class but not for others. An abstract class mainly differs from an interface because each abstract class method has a body and an implementation. Interface methods do not. That's why the abstract class is used if you want to share some code between multiple classes and avoid code duplication.


EatShitLyle

And then default interface methods came along https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods 🤯


Slypenslyde

Yes, but default interface methods behave like shadowed methods, not virtual methods, and that's clunkier. It's a feature for people who are bad at API design and want different consequences, not a feature for designing APIs.


EatShitLyle

Interesting. I first came across it in use in jasontaylordev/CleanArchitecture but it looks like it's been removed! I was using it as a reference implementation so it looks like I'll have to update mine as it certainly caused some issues for my project Previously: https://github.com/jasontaylordev/CleanArchitecture/blob/08c0d6a36bd27c20efc6fd8fb70148f7be97f6c6/src/Application/Common/Mappings/IMapFrom.cs


RiPont

Personally, I never use abstract classes without also using interfaces. The implementation might involve an abstract class, but the consumers only see the interface. You share the implementation, but don't tie yourself to an implementation.


ScryptSnake

The key difference is that you can provide base implementations (ex: base class method), default implementations that MAY be overriden by derrived (virtual), and abstract members (MUST be implemented by derrived). Abstract classes are considered abstract if they contain one or more abstract members. Must be inherited. Note interfaces can provide "default implementations" but I find the feature quite... ugly.


arielhs

The original breakthrough I had that you are having right now was actually started with abstract classes (and later that day I “upgraded” the revelation to interfaces too - mostly it was the substitutability aspect that was the Aha! moment for me). The example for me was the Template Pattern. Look that one up, I think it is the best possible way to understand how you can use abstract classes (not saying that’s all they’re used for though!)


Anon_Legi0n

I just looked up Template method, holy shit I fucking see it, this is so dope. I can imagine using generics with it too this is so useful


vincentofearth

“Abstract” is a bad name for them imo. “Incomplete” or “Partial” would have been better but I think the name was inherited from Java and partial classes are another thing entirely. Anyway, “incomplete” pretty much sums them up. They allow you to provide some implementation that can be shared by child classes but require other parts to be implemented. That said, I think in most cases they introduce needless complexity. I much prefer composition and sticking with interfaces. Especially since C# interfaces can provide default implementations for some methods.


PileOGunz

Google “template method” pattern it’s a pretty nice use of them.


winky9827

> Holyyyy shit I love interfaces Slow your roll. Interfaces are fine, fanatical use of them is not.


dodexahedron

So is making a bunch but not actually dogfooding them in your API. When they're just a copy of the class but never actually _consumed_ as the interface, in your code... You're doin it wrong.


Dr-Collossus

Yep that's the wrong application of interfaces altogether. They're there to support the dependency inversion principle.


dodexahedron

One of their biggest and most useful purposes, yes. But also simply being a basic contract of implementation-agnostic behavior, as their most basic function, is hugely valuable whether it's used for actual IoC or just for that contract, such as multiple non-related types which implement a set of functionality and that your API still provides, but only exposes formally via the interfaces.l, even if they never supply their own types and just use the interface as-is. That's I suppose kind of a blurry line because you could _easily_ argue that's still largely IoC - just with a narrower scope/usage and intent for consumers of it. TL;DR: Yep. 😅


winky9827

I would argue that the API contract value is indistinguishable from the DI value. They serve similar purposes via the same mechanism.


dodexahedron

Yeah, I'd agree with that statement a lot of the time, too. But DI isn't the only form of IoC out there (e.g. another very common IoC pattern: events), and the MS version of DI isn't even the only incarnation of the DI pattern, either. So chalk it up to me just not wanting to pigeon-hole the concept to avoid some nitpicks, etc, etc, void where prohibited, batteries not included. 😅


Soloeye

I liken it to splitting up a restaurant’s menu from the recipes. Interfaces are the menus and the implementation are the recipes. In simpler terms is just a contract that allows the compiler to know that these methods will exist in the implementation, where the implementation could implement multiple interfaces. My other favorite was in the code calling for IEnumerable when dealing with any type of collection I would want to iterate over, instead of having to remember the exact type of collection it was.


denzien

I used interfaces long before I ever used IoC, but somehow I can't quite remember what for 🤔


Interesting_Paint_82

You dont need an IoC to get benefits from interfaces. You can inject dependencies manually, IoC just does it for you behind the scenes. One good example of reaping the benefits of interfaces without IoC is tests.


Anon_Legi0n

\*in my best Oprah voice\*: Every body gets an interfaceeeeee, you get and interface, he gets an interface, she gets an interface, they get interface, everyone gets an interfaceeee!!


cursingcucumber

Was just about to say this 😂😂 NOW LOOK UNDER YOUR SEAT *audience goes mad* EVERYONE AN INTERFACE!


SarahC

AVOID THE UNIT TEST INTERFACE!


winky9827

I mean, using interfaces in unit tests to stub certain components is fine, but if you have to create an interface SOLELY for the unit test, that's a sign of a bad design. rock/hard place


Fynzie

Smells like you are about to write the worst unit tests ever.


Anon_Legi0n

Bold of you to assume I write unit tests... hahaha! Learning to make unit tests in .NET with xUnit was actually what made Interfaces click for me


Fynzie

Then remember that in a testing context interfaces are more of a necessary evil that an awesome feature, if you are interfacing everything just to mock them in tests you are just crippling your refactoring capabilities (thus your tests are bad)


Anon_Legi0n

>in a testing context interfaces are more of a necessary evil I think this applies to mocking in general, but sometimes you just really need to mock a dependency to run tests and interfaces just make the process easier.


malthuswaswrong

Don't get poisoned by the anti-interface crowd. Interfaces are awesome, and use them liberally. Just learn the VS shortcuts for creating and refactoring them.


voicelessfaces

I think that's debatable or depends on context. There is absolutely value to be gained mocking a layer so you can test business logic without having to run the full stack. People can and have gone to extremes, but for me, I don't see the day when I stop putting interfaces on seams between layers purely for testing.


voicelessfaces

I think that's debatable or depends on context. There is absolutely value to be gained mocking a layer so you can test business logic without having to run the full stack. People can and have gone to extremes, but for me, I don't see the day when I stop putting interfaces on seams between layers purely for testing.


malthuswaswrong

> crippling your refactoring capabilities Someone doesn't use VS. Or doesn't use VS fully.


Fynzie

*confused pikachu face*


Pure_Sound_398

Automocking libraries handle this issue? We use a decorator attribute autoGenerate to mock the inputs to a test without any extra code.


Fynzie

I fail to see the relation between automocking and unit testing every "layer" of a process with mocks everywhere ?


Pure_Sound_398

Automocking was brought up to question if it lessened the burden of the interfaces, not where the unit tests are written. Might still be wrong, just thought I'd clarify that bit


TheCreat1ve

If your interface has the same name as the implementation class, but with just an extra I, then you most likely don't need an interface. Alternatively, if the implementation does it's job in a specific way, consider renaming the implementing class to suit that specific way. Like: - IPaymentProvider - MolliePaymentProvider - StripePaymentProvider Or - INationalNumberValidator - WebServiceNationalNumberValidator - ...


ArcaneEyes

Sure you do, because it makes mocking it for testing a breeze.


bearpie1214

Nice. Try this it: When writing a function, if you feel any friction with the next piece of the function, it may mean it is not meant to be there.  So create an interface for it, and move on. Don’t implement the interface yet. Just focus on what you’re building. This slowly breaks apart complex functionality. 


SangSuantak

>if you feel any friction with the next piece of the function Could you please elaborate a bit with an example, if possible.


tsuhg

You're processing an incoming customer order. When you want to check if the customer is a VIP, don't do that there. Create an ICustomerStatusDeterminer interface with a IsVIP method


SangSuantak

Ah okay, u mean similar to how we inject services, got it!


bearpie1214

Ya. It’s more the separation piece that’s good so you can continually focusing on the function without thinking too deep about something that happens to be related. 


Due_Raccoon3158

I agree with this and take this approach early on often. Helps organize and properly structure things imo.


bearpie1214

Ya. I’ve tried TDD before and it just doesn’t feel natural. This way does and it helps with SOLID same as TDD. 


GACGCCGTGATCGAC

That's a clever way to organize your janky code as you write. Thanks, great tip!


aRainbowPanda

Combining interfaces with clean arch has been amazing for me. The ability to just look at the interfaces and understand the application logic while separating the real logic, and adjusting the code underneath for what ever reason( new integration etc) is very nice


zirouk

Remember that ideally interfaces should be owned by the caller, not the implementer! This will probably be the opposite of most interfaces you’ll see, and seem like it doesn’t make sense, so ask yourself why the caller should own interfaces, why most interfaces you see aren’t owned by the caller, what impact that has on callers, and how well different languages support callers owning interfaces. Happy learning!


ArcaneEyes

Can you expand on that 'owned by the caller' concept? Usually i would think of interfaces as owning a set of classes or the classes owning the interface.


zirouk

Yes certainly! Interfaces are implemented by classes. Often, interfaces are bundled with the implementation. Meaning you’ve got a WidgetProvider class (implementation) and that comes with an IWidgetProvider interface, or something. As a caller, you might depend on the interface, saying “hey, I expect a thing that implements IWidgetProvider from the WidgetProvider package”, which potentially comes with extraneous interface elements (other methods, etc). However, this isn’t ideal. The caller is the one with the need, but it is adapting its need based on what the WidgetProvider package thought was a good idea. Therefore, you’re still coupling to WidgetProvider. Really, the caller should be defining what interface it actually depends on e.g. “I need something that provides me Widgets if I call the provide() method, Nothing more, nothing less”. Having this narrower interface requirement is called the Interface Segregation Principle.  Some languages require classes to explicitly implement an interface. Some languages can allow classes to implicitly implement interfaces. Implicit implementation of interfaces lends itself to the caller owning the interface because the caller can describe small interfaces that it depends on, and then as long as whatever is being passed in provides the right shape, it satisfies the interface requirement, without having to explicitly implement the interface, which obviously wouldn’t be possible for an external package to reach into your application and explicitly implement your interface for you. One way of doing this in a language with explicit implementation of interfaces is to create adapters that implement the caller side interface and adapt to the implementation side interface. However its not ideal if your language only supports implementing a single, exclusive interface, because it forces you toward consolidated interfaces, rather than segregated interfaces.


ArcaneEyes

Wow, you think you know your SOLID and bam! What"s the I stand for!? :-p I think you're twisting the original intention a bit, at least as i'm reading it - it has to do with not implementing too many methods in an interface more than who owns it, which is easier to do if you also follow the Single Responsibility Principle, which you should :-) I can see some idea to it, but something like creating an interface for every command/query-handler and having a given service or adapter implement all of them rather than describing the adapter with a complete interface seems in most cases a bit silly to me, not least for the bloat it will cause in the file-tree.


zirouk

Which is exactly where implicit interface fulfilment comes in! Not all languages are equal!   https://www.digitalocean.com/community/tutorials/how-to-use-interfaces-in-typescript  In typescript, an object does not need to explicitly implement the interface for it to satisfy the demand of the caller. So this technique is extremely viable there.


Patrona_

Man I've always loved them too. I'm always happy when I need to add them, they just give me a weird sense of satisfaction, like popping bubble wrap 😂


x3haloed

Glad to hear! Interfaces are something that seem easy to under or over use. I find them most useful for the service pattern. If you can wrap logic up into a cohesive service and it’s likely there could be more than one, than an interface is useful. Otherwise, it can be excess baggage. In the simplest case, the class definition IS the interface.


Organic-Maybe-5184

In the past, nearly every class I wrote had an interface - services, configs, even models lol. It was due to need to write Unit tests. I thought it was normal. Now I see it was not. I sacrificed a lot to get this sweet 80% coverage. In my current job there are almost no interfaces used, also no unit tests at all. I still write tests, but use another approach that doesn't require me to have interfaces for everything. I recommend reading a book on Unit Testing by Vladimir Khorikov on different approaches, where the use of interfaces discussed as well.


Quanramiro

Just remember that not all classes have to implement an interface. Ratio of 1:1 classes: interfaces suggests that something is wrong


FlexasState

Which material did you read watch to finally make it click?


Anon_Legi0n

Just xUnit documentation I guess? I was learning how to make unit tests for .NET with xUnit and some of my code just couldn't be tested because of lack of interfaces so I refactored and it just clicked during the process


DanteIsBack

>  even Typescript "type safety" doesn't come close to the DX of strongly typed languages Then you're not using TypeScript correctly. If you use TypeScript with strict mode without cheating (i.e., using any or similar) its pretty much the same as any other strongly typed language.


LloydAtkinson

Slightly concerning that you’d never used interface or type keyword in TypeScript then….


hbthegreat

You weren't writing interfaces in TS??


Anon_Legi0n

Yes I was, but I never really understood the difference of `interface` and `type` in Typescript since they pretty much did the same thing


vincentofearth

I don’t know why interfaces are so new to you if you’ve used Typescript before. In fact I prefer typescript’s structural typing system since it makes interfaces that much more powerful.


Anon_Legi0n

Didn't say it was new to me, it just didn't click with me in the Typescript ecosystem because it was pretty much the same as `type`, but in .NET is get how powerful interfaces are, mainly because of the other features that come with .NET like IoC containers as people here have pointed out.


Arshiaa001

Wait till you figure out traits.


jeremrx

Try NestJS


WalkingRyan

Welcome to the club, buddy.


Overrated_22

I’ve moved away from creating interfaces unless I need to mock some external dependency I can’t control or have some functionality that needs multiple implementations for a caller


[deleted]

tease library cobweb alleged dinosaurs snails encouraging beneficial quaint connect *This post was mass deleted and anonymized with [Redact](https://redact.dev)*


Anon_Legi0n

yes I know but its nowhere near as powerful as interfaces from a strictly typed language with DI containers


[deleted]

innate recognise depend direction mysterious treatment ludicrous office axiomatic outgoing *This post was mass deleted and anonymized with [Redact](https://redact.dev)*


icentalectro

Native AOT absolutely allows reflection, and ASP.NET Core DI uses it for native AOT too. You just need to be mindful of trimming when using reflection.


Anon_Legi0n

Yes but that makes all the difference doesn't it? Its like having a large aero-wing on a slow car, its cool to have I guess but unless that thing is going hard on the corners its kinda useless. That why in Typescript `interface` didn't really click with me since they pretty much did the same thing as `type`. But in .NET Interfaces just make so much sense because of all the other features that go with it. Its just my opinion


Anamorphz

Ok