Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
jony neuemonic
Nov 13, 2009

Pilsner posted:

An interface on every class, just for the sake of, grossly pollutes the codebase and is terrible. It is a hack concept that stems from unittesting frameworks that require you to have an interface on a class in order to be able to mock it. Writing the code properly with as little technical fluff as possible is first priority, making it fit to some test framework or mocking is second priority.

Thinking about putting an interface on your class? Considering an inheritance hierarchy? When in doubt, leave it out, as the saying goes. It makes no sense to put an interface on a class where you know with certainty that this is going to be only one implementation of that interface.

Edit: I should note that this is talking about .NET development, where I have seen some horror examples of interface- and inheritance spewing that makes the code very hard to read and debug. In other languages it might be different.

I mean, I think (hope?) we can all agree that making an interface for every class in your application is silly. But creating an interface for classes that are going to be dependencies (repositories, services, etc.) is just idiomatic .NET as far as I can tell. Especially in web-land since ASP.NET comes with a DI container out of the box now.

Adbot
ADBOT LOVES YOU

spiritual bypass
Feb 19, 2008

Grimey Drawer
I don't understand. How could the presence of an interface make things harder? At worst, it just seems like a file hanging around that you can safely ignore.

Hughlander
May 11, 2005

rt4 posted:

I don't understand. How could the presence of an interface make things harder? At worst, it just seems like a file hanging around that you can safely ignore.

It's extra boiler plate for people with bad IDEs and extra clicks for people with good IDEs. It can encourage dependency injection in places where it's otherwise not needed.

(Note: I don't support these views, just seem them as possible arguable answers.)

jony neuemonic
Nov 13, 2009

rt4 posted:

I don't understand. How could the presence of an interface make things harder? At worst, it just seems like a file hanging around that you can safely ignore.

It's more code that you have to write and (more importantly) maintain for very little benefit if you go overboard.

spiritual bypass
Feb 19, 2008

Grimey Drawer
How does an interface require maintenance?? If an interface really takes so long to type or requires frequent adjustment down the road, that may be a problem with the software design rather than the practice of programming to interfaces.

jony neuemonic
Nov 13, 2009

All code's going to require maintenance sooner or later, and I like to have as little of it as possible when it does. Just a difference in style, I guess. :shrug:

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
My personal opinion is that since it's so easy to just split a class into interface and impl if you turns out you actually do need an alternate implementation, why would you even bother doing that work up-front? YAGNI 90% of the time.

Stinky_Pete
Aug 16, 2015

Stinkier than your average bear
Lipstick Apathy

rt4 posted:

I don't understand. How could the presence of an interface make things harder? At worst, it just seems like a file hanging around that you can safely ignore.

because it's extra baggage. change the class function headers and you have to change the interface function headers

return0
Apr 11, 2007
These are some seriously bullshit arguments up in here.

sarehu
Apr 20, 2007

(call/cc call/cc)

return0 posted:

These are some seriously bullshit arguments up in here.

There is no articulable reason for having one-class interfaces.

Source: you're unable to articulate any.

Stinky_Pete
Aug 16, 2015

Stinkier than your average bear
Lipstick Apathy
One-class interfaces are sometimes known as header files

qntm
Jun 17, 2009
"This is not a problem if you have a good software design" doesn't strike me as a great way to argue that something is not a problem.

baquerd
Jul 2, 2007

by FactsAreUseless

qntm posted:

"This is not a problem if you have a good software design" doesn't strike me as a great way to argue that something is not a problem.

An interface per class appeals to the lowest common denominator. It's generally better for people to be thinking in terms of interfaces excessively rather than avoiding them preferentially, so if you have an interface per class you cover your bases at a cost of making the code base less navigable and understandable when you use an interface only once. That is, if you can't trust your people to use interfaces smartly, at least get them thinking more about it.

Sarcophallus
Jun 12, 2011

by Lowtax

baquerd posted:

It's generally better for people to be thinking in terms of interfaces excessively rather than avoiding them preferentially

This is exactly the point that's up for debate here, seemingly. Repeating it doesn't make it true.

baquerd posted:

so if you have an interface per class you cover your bases at a cost of making the code base less navigable and understandable when you use an interface only once. That is, if you can't trust your people to use interfaces smartly, at least get them thinking more about it.

And this is exactly the behavior that should be avoided.

Someone who doesn't know how interfaces work isn't going to look at 'BeanTransformer' and 'BeanTransformerImpl' and say, "You know what, I need a bean transformer too, but I the BeanTransformerImpl doesn't do what I need it to do; I'll just make another impl of BeanTransformer!" In this world where we've established that they don't know how to use interfaces smartly, what they'll do is make another interface, 'AnotherBeanTransformer', and make their lovely impl class 'AnotherBeanTransformerImpl' and further pollute the already burning trash pile of code.

Except now you make everyone's job more difficult. You make it more difficult for the person that does know how to use interfaces, because they have to reconcile this extra interface and refactor it after the fact. You make it more difficult for literally every developer on this project to navigate to the specific code they need. You make it more obnoxious to refactor code. And for what? Interfaces have an explicit purpose. Use them for that purpose. It's not like it's hard to extract an interface out of a class after the fact when you actually need it.

baquerd
Jul 2, 2007

by FactsAreUseless

Sarcophallus posted:

Except now you make everyone's job more difficult. You make it more difficult for the person that does know how to use interfaces, because they have to reconcile this extra interface and refactor it after the fact. You make it more difficult for literally every developer on this project to navigate to the specific code they need. You make it more obnoxious to refactor code. And for what? Interfaces have an explicit purpose. Use them for that purpose. It's not like it's hard to extract an interface out of a class after the fact when you actually need it.

Yep, just playing devil's advocate.

Linear Zoetrope
Nov 28, 2011

A hero must cook
I'd actually consider a decent heuristic "one interface per piece of functionality." Depending on how you interpret the single responsibility principle, and how religiously you adhere to it, this may end up being one interface per distinct class (distinct meaning classes that don't try to give the same functionality in different ways). However, this may end up being 2-3 interfaces for some classes, or even zero if they're just POD classes or something.

More to the point, interfaces should be defined by consumers more than producers. There's not much purpose making an interface that requires methods nobody needs. Instead, your classes and functions elsewhere should be the motivating factor creating interfaces. Meaning: if I have some sort of point class that happens to provide the number of elements and a distance function, there's not necessarily purpose making a Distance and Dimensions interface. Instead, what might motivate those interfaces is if you have a KD tree that wants to work on arbitrary points, you create a Dimension and Distance interface to tell others what functionality you need to work on them, which strikes me as more the point of interfaces than telling a consumer what they need to be able to handle to work on you. That's the kind of coupling interface-focused design is meant to avoid in the first place. (Of course, in practice you probably will end up reusing interfaces in the codebase so you don't need 3 different Dimension functions because 3 different classes needed to know a vector's dimension).

E: Admittedly, this is easier in classes with more typeclassy interfaces like Rust, where you can bound a generic on compositions of interfaces rather than needing to write a separate interface that composes all the functionality you need together. At least, IIRC in Java if you need someone to implement interface A,B, and C, you have to make a tag interface that extends A, B, and C, and the implementing class has to explicitly state it's implementing the tag interface, which is a bit messy and less than ideal.

Linear Zoetrope fucked around with this message at 20:49 on Sep 24, 2016

comedyblissoption
Mar 15, 2006

an interface for everything makes sense in the context of a unit testing philosophy where you only ever test at the class level and mock out all of its dependencies in your test and your testing framework only lets you mock things with an interface

the above testing style is however a terrible idea and so an interface for everything is still a bad idea

comedyblissoption
Mar 15, 2006

only use interfaces when you actually need an interface

some reasons:
  • you need interface based polymorphism and there's not another better way to achieve what you want
  • you need to expose your behavior as a library to others
  • you need to mock something in a test and your test mocking framework only works with interfaces

invalid reasons:
  • my oop cargo cult believes you should put an interface on everything because of nebulous principles

unfortunately in industry you will find people who probably believe you should slap an interface on everything because *reasons* and judge you negatively if you don't share this belief among many other OOP kool-aid beliefs

comedyblissoption
Mar 15, 2006

the industry absolutely adores useless boilerplate that can be autogenerated by an IDE

here is the standard industry practice using dependency injection and interfaces in C# to call a module in your own code from some other module in your own code where there's only ever one implementation of the interface:

code:
/* pretend there's some dependency injection framework reflection-based wiring bullshit here */

public interface IFoo
{
    void DoSomething();
}

public class Foo : IFoo
{
    public void DoSomething()
    {
    }
}

public interface IBar
{
    void DoAnotherThing();
}

public class Bar : IBar
{
    private readonly IFoo _foo;

    public Bar(IFoo foo)
    {
        _foo = foo;
    }

    public void DoAnotherThing()
    {
        _foo.DoSomething();
    }
}
here is the same drat code without boilerplate that will get you shunned by other practitioners in the industry:
code:
public static class Foo
{
    public static void DoSomething()
    {
    }
}

public static class Bar
{
    public static void DoAnotherThing()
    {
        Foo.DoSomething();
    }
}
be skeptical of "best practices" in OOP land

Eggnogium
Jun 1, 2010

Never give an inch! Hnnnghhhhhh!
The only codebase I've worked in that was riddled with interfaces and heavily unit tested was also constantly full of integration bugs.

That said, it would be really handy if the BCL had interfaces for HTTP requests, event logs, other out-of-proc APIs because they are super handy for writing functional tests.

comedyblissoption
Mar 15, 2006

automated in-memory tests should instantiate as much of the system or subsystem you are testing and only mock the boundaries (e.g. file and network operations)

unit tests should be the exception to the rule if you are narrowing the scope of the test to some complicated calculation or something

testing everything at the class level and mocking all its dependencies will result in useless and brittle tests that don't test the important interactions between classes and also unnecessarily make it difficult to refactor or change the code

sarehu
Apr 20, 2007

(call/cc call/cc)

comedyblissoption posted:

automated in-memory tests should instantiate as much of the system or subsystem you are testing and only mock the boundaries (e.g. file and network operations)

unit tests should be the exception to the rule if you are narrowing the scope of the test to some complicated calculation or something

testing everything at the class level and mocking all its dependencies will result in useless and brittle tests that don't test the important interactions between classes and also unnecessarily make it difficult to refactor or change the code

Having trouble finding your shift key? How did you noty die as a baby, considering that you were likely too stupid to find a tit to suck on?

(USER WAS PUT ON PROBATION FOR THIS POST)

Pilsner
Nov 23, 2002

sarehu posted:

Having trouble finding your shift key? How did you noty die as a baby, considering that you were likely too stupid to find a tit to suck on?
Jeez, a bit harsh for a programming debate thread, eh buddy? I agree with him.

I work in a company where our development is heavily centered around a database that is live 24/7 and gets new data every millisecond, whether it's from customers, employees, batch jobs, imports from external companies or services receiving data. We might have a "Case" object with Customers, Agencies, Employees, CustomerRelations, Activities, and 5-10 other domain entities below it that are tied to the database, and each entity can have between 20 and 100+ data fields. We change our data structure every release, removing or adding fields as necessary to implement new features. It is simply not worth my time mocking and simulating the database, so I always use the database straight up for unittesting (no mocking) as that will give me the best and most realistic results.

Other people lucky enough to work on projects that are more static in their data or perhaps not tied to a database as all, will find that creating and maintaining a suite of unittests with mocking or whatever is more worth their time.

However, don't forget the number one mantra: Unittests are only as worthwhile as the guy who wrote them. You could write 50 unittests for your class, but that doesn't guarantee that it will be bug free, and especially not that it will be free from semantic errors, which are the most important ones.

comedyblissoption posted:

invalid reasons:
  • my oop cargo cult believes you should put an interface on everything because of nebulous principles
:lol:

return0
Apr 11, 2007

comedyblissoption posted:

the industry absolutely adores useless boilerplate that can be autogenerated by an IDE

here is the standard industry practice using dependency injection and interfaces in C# to call a module in your own code from some other module in your own code where there's only ever one implementation of the interface:

code:
/* pretend there's some dependency injection framework reflection-based wiring bullshit here */

public interface IFoo
{
    void DoSomething();
}

public class Foo : IFoo
{
    public void DoSomething()
    {
    }
}

public interface IBar
{
    void DoAnotherThing();
}

public class Bar : IBar
{
    private readonly IFoo _foo;

    public Bar(IFoo foo)
    {
        _foo = foo;
    }

    public void DoAnotherThing()
    {
        _foo.DoSomething();
    }
}
here is the same drat code without boilerplate that will get you shunned by other practitioners in the industry:
code:
public static class Foo
{
    public static void DoSomething()
    {
    }
}

public static class Bar
{
    public static void DoAnotherThing()
    {
        Foo.DoSomething();
    }
}
be skeptical of "best practices" in OOP land


Hmm yeah that second one sure is better in a very narrow set of circumstances that the majority of people won't find themselves in, while the first one is far more flexible and general, hmm makes you think.

Gildiss
Aug 24, 2010

Grimey Drawer
Yup, super glad I don't work in or with anyone that uses OOP.

everythingWasBees
Jan 9, 2013




Posted this in the Game Jobs thread, but the more eyes the better.

everythingWasBees posted:

So a few game companies are gonna be at a upcoming job fair this Wednesday, and I'm hoping to land a summer internship. There's a good relationship between both the school and game development club and the local companies, with lots of alumni from both at various positions, and employees sometimes working as lecturers. I've never written a resume before, and was hoping I could get some feedback. Because I know it'll come up, I specified C++98 as I haven't touched C++11, and there's apparently no good way to write C# in LaTeX. I have taken, or am taking, Computer Graphics, Animation Programming,and Artificial Intelligence, as well as the standard classes (Physics, Calc classes, data structures, assembly, etc,) although I haven't heard a worthwhile argument in including those on a resume.

https://www.overleaf.com/read/ztxhmhhmqgrr
Let me know if there are any problems with the link.

everythingWasBees fucked around with this message at 18:57 on Sep 25, 2016

Hughlander
May 11, 2005

everythingWasBees posted:

Posted this in the Game Jobs thread, but the more eyes the better.

This site can’t be reached

The webpage at https://www.overleaf.com/docs/6335846hvtprp/pdf.pdf might be temporarily down or it may have moved permanently to a new web address.

return0
Apr 11, 2007

Gildiss posted:

Yup, super glad I don't work in or with anyone that uses OOP.

I don't get the antipathy for IoC/DI, in certain contexts it works really well. In a previous place I worked on a .net mvc app, we used one of the standard idiomatic containers and adding new types and wiring was braindead simple. There was literally no time spent doing any drudge work on changing constructor args, lifetime scoping of entities (e.g., instance per request vs shared singleton) was done in one place, the dependency graph was nice/simple/acyclical (impossible to gently caress up because resolution is automatic, via constructor injection only). This meant people were more inclined to factor and split out types because there was zero weight/resistance to doing so in terms of boring code shuffling.

In other contexts it's not idiomatic so why do it? Part of what I work on now is a C++ SDK for a cross platform library for high performance simulation. We don't use DI there, and don't use interfaces internally, but we have them at the boundaries of the library for some things.

A big reason the comparison featuring this code is such bullshit:

code:
public static class Foo
{
    public static void DoSomething()
    {
    }
}

public static class Bar
{
    public static void DoAnotherThing()
    {
        Foo.DoSomething();
    }
}
... is because it's not the same as the class/interface based version. What if Foo and Bar need state and we need to make more than instance? What if Foo.DoSomething() depends on the environment and needs to be stubbed or mocked, or what if it hits a live service (like a payment gateway). Who knows if this applies, because it's a deliberately contrived example to show less keystrokes.

It's like arguing that free functions are better than classes, it's just stupid argument to make for the general case. The static class way also sucks because it is surprising that Bar depends on Foo when examining the class constructors, which are the idiomatic mechanism to express dependencies.

comedyblissoption
Mar 15, 2006

I agree in practice the boilerplate is not that big a deal. You just learn to live with saying foo 6 times every time you need to declare it as a dependency because the IDE helps autogenerate it for you, but it is still absurd and has no reasonable justification. The language could also require you to put "Java/C# is great and awesome!" at the top of every source file and your IDE could autogenerate it for you, but "it's not a big deal" would not be a valid argument in support of such a requirement.

return0 posted:

What if Foo and Bar need state and we need to make more than instance?
The vast majority of your code should be passing state on the stack. In the scenarios where you need state encapsulated by an object, then you can encapsulate it in an object that can be instantiated (either using new or a static factory function). Ideally these state objects would mostly be isolated and not require dependencies to instantiate. Any methods should be self-contained to logic that works on the object itself. If they do need to call out to an external dependency, injecting it as a constructor argument does not really buy you anything except boilerplate. The only really justifiable reason is if you need interface based polymorphism or that the object instance with state depends on being created with another object instance with state. When you have that justifiable reason, then pass it as a constructor argument.

return0 posted:

What if Foo.DoSomething() depends on the environment and needs to be stubbed or mocked, or what if it hits a live service (like a payment gateway).
function calls that hit outside system boundaries (e.g. a network call) can be wrapped in a static wrapper so you can mock it for tests

return0 posted:

The static class way also sucks because it is surprising that Bar depends on Foo when examining the class constructors, which are the idiomatic mechanism to express dependencies.
Code analysis could easily reveal the static classes invoked from another class at a glance and show this in a dependency graph.

return0 posted:

It's like arguing that free functions are better than classes, it's just stupid argument to make for the general case.
The answer to this argument depends on your viewpoint on whether or not encapsulating state should be the general case or not.

comedyblissoption
Mar 15, 2006

return0 posted:

In other contexts it's not idiomatic so why do it? Part of what I work on now is a C++ SDK for a cross platform library for high performance simulation. We don't use DI there, and don't use interfaces internally, but we have them at the boundaries of the library for some things.
Did you lose anything at all whatsoever by not using boilerplate DI? To be fair, C++ has its own boilerplate b/c it's still using the header include mechanisms, but it would be even more mindnumbingly boilerplatish with the java/C# DI pattern.

Tres Burritos
Sep 3, 2009

This belongs in the coding horrors thread.

return0
Apr 11, 2007
I think the position I'm taking is more germane to this thread (general advice for new programmers interviewing) than the alternatives, but point taken. I'll stop the poo poo derail.

comedyblissoption
Mar 15, 2006

I agree your advice is completely idiomatic and the general standard accepted "best practice" in the C#/java world. I follow it on my team projects at my job. Newbies will not go wrong to following it. It would actually be detrimental to follow my advice as a newbie with other industry programmers since they will argue that you're wrong and view you as problematic.

I am just pointing out the idiom is flawed and without justification.

return0
Apr 11, 2007
I agree. It requires a bit of a nuanced view to figure out when it's best to roll with the idioms, and when it's worth deviating. This applies both technically and politically - don't pick a pointless hill to die on. And definitely don't die on it in an interview when you're just starting out (unless you're super talented, then do whatever).

everythingWasBees
Jan 9, 2013




Hughlander posted:

This site can’t be reached

The webpage at https://www.overleaf.com/docs/6335846hvtprp/pdf.pdf might be temporarily down or it may have moved permanently to a new web address.

https://www.overleaf.com/read/ztxhmhhmqgrr

This should work.

putin is a cunt
Apr 5, 2007

BOY DO I SURE ENJOY TRASH. THERE'S NOTHING MORE I LOVE THAN TO SIT DOWN IN FRONT OF THE BIG SCREEN AND EAT A BIIIIG STEAMY BOWL OF SHIT. WARNER BROS CAN COME OVER TO MY HOUSE AND ASSFUCK MY MOM WHILE I WATCH AND I WOULD CERTIFY IT FRESH, NO QUESTION
I can only offer the stock-standard completely-unhelpful response that everyone inevitably sees whenever a question of "best practice" comes up: Sometimes you'll want lots and lots of interfaces, sometimes you won't. One of the projects I spend the majority of my time working with is incredibly complex with bits and pieces that need to be swapped in or out. We have an expectation that this pattern is likely to continue, and new stuff that we implement is likely to eventually need alternative implementations that can be swapped in and out using DI. This means we tend to code to interfaces habitually on the code library layer.

BUT when we use that code library in an MVC project for example, we'll try to avoid using too many interfaces, particularly when we write the adapter layer between the MVC controllers and the code library/API layer, because generally speaking that code is specific to that particular project and we'll never need another implementation.

So we have one project where we do follow the "interface just about every class" pattern and others that consume that project where we don't. There's no strictly correct way to approach it, it's entirely contextual. I know that sounds obvious but the way some people are framing their arguments makes it appear that it's not as obvious as I thought at least.

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



return0 posted:

There was literally no time spent doing any drudge work on changing constructor args, lifetime scoping of entities (e.g., instance per request vs shared singleton) was done in one place, the dependency graph was nice/simple/acyclical (impossible to gently caress up because resolution is automatic, via constructor injection only).

I'm pretty sure this was a function of your coworkers' competence rather than your choice to use DI.

Tres Burritos
Sep 3, 2009


Don't list your GPA unless you think it's poo poo hot, even then most normal people don't care.

I'd suggest you put the stuff you want to highlight at the top and put the detail there. Your projects section sounds much more interesting than your professional section, you should flip their sizes and go into way more detail about what you accomplished / did in the projects.
Also I can't tell what kind of job you're trying to get. You are tailoring your resume to the places that you're applying to right?

That's just my $0.02, someone else should probably chime in.

return0
Apr 11, 2007

Munkeymon posted:

I'm pretty sure this was a function of your coworkers' competence rather than your choice to use DI.

I've worked in places with... challenging co-workers, and the use of a container was an excellent forcing function to prevent them from concocting all manner of N-phase initialisation : N > 1 devices. That isn't an issue where I am now, but it's still something to keep in mind.

You never know when you're going to absorb a number of less skilled developers. If it doesn't hurt the good-developer path (and it can, so you need to be careful) and it protects against some of the worst machinations of the less good developers, it's worth considering.

Adbot
ADBOT LOVES YOU

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



return0 posted:

I've worked in places with... challenging co-workers, and the use of a container was an excellent forcing function to prevent them from concocting all manner of N-phase initialisation : N > 1 devices. That isn't an issue where I am now, but it's still something to keep in mind.

You never know when you're going to absorb a number of less skilled developers. If it doesn't hurt the good-developer path (and it can, so you need to be careful) and it protects against some of the worst machinations of the less good developers, it's worth considering.

I mean, I managed to create a DI graph cycle one time a couple of jobs ago and only found it because I wrote out a graph that went ~6 hops out of the class the crash actually happened in. It was a big, messy graph that I could not hope to keep in my head, partly because I largely was not responsible for making it. I almost gave up and started looking for a different cause after four hops because it was getting silly. I also wasn't the only one to do it and whatever DI mess we were using made this class of error only show up occasionally or after multiple re-builds, so I guess what I'm trying to get at is that DI isn't magical fix-all fairy dust as I think the bit I quoted kind of implied.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply