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.
 
  • Locked thread
GoodCleanFun
Jan 28, 2004

GrumpyDoctor posted:

Roughly, the main window displays some information, and the dialog box contains settings for how the information should be displayed. I'll take a look at a messenger, although conceptual MVVM purity might not be worth the additional complexity.

http://blog.brentmckendrick.com/mvvm-tips-how-to-show-a-message-box-or-dialog-in-mvvm-silverlight/

I use the above implementation and instantiate the obj in the constructor of my base view model.

Adbot
ADBOT LOVES YOU

raminasi
Jan 25, 2005

a last drink with no ice

GoodCleanFun posted:

http://blog.brentmckendrick.com/mvvm-tips-how-to-show-a-message-box-or-dialog-in-mvvm-silverlight/

I use the above implementation and instantiate the obj in the constructor of my base view model.

That works fine for MessageBoxes, but if you're rolling your own dialog window you need to set its owner manually, and that's the part I couldn't figure out.

Sedro
Dec 31, 2008

GrumpyDoctor posted:

e: I'll take this opportunity to ask another WiX question: The official way to create a Start Menu shortcut causes a warning. What gives?
You have better things to do than worry about ICE warnings.

But before you ship the installer, do decide whether to install per-user or per-machine; you can't change your mind later without breaking upgrades.

Bluffoon
Jun 15, 2005
hhheeeeeeeeeeehaaaaaaaaawww

Bognar posted:

Be warned - while the code displayed on those websites is useful for learning ASP.NET MVC and Entity Framework, the style is not at all good for building a large production application (e.g. accessing your database directly from your controller, using ViewBag, using your domain models as view models or parameter objects). A new guy started at our office this week and we set him up with the MVC5 tutorials, but we're finding that we have to go back and tell him to unlearn half the things the tutorials suggest.

I'm in pretty much the exact same situation as the new guy at your office - I am starting fresh on a fairly large web application that will (hopefully) eventually be put into production. It's been a while since I've done any .NET web stuff, so I've been using the MVC5 tutorial as a refresher. My previous experience with Asp.NET MVC was with MVC2, which I took a course on in school. As our final project for that course, we had to create a MVC2 web app that used EF and the Repository pattern.

I had some concerns over the tutorial too (the database access in the controllers, and the ViewBag stuff, since I'd never dealt with it before), so I was planning on getting a working test version up and running with the method suggested in the tutorial, and then going back and refactoring out the database access to use some kind of data access layer (likely the repository pattern). Would that, in your opinion, result in a decent architecture for the application, or is the tutorial so screwed up that it's best to start from scratch? The application is on Azure, and uses an existing database (also on Azure), so I've been following along with the "Database first" parts of the tutorial.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

Bluffoon posted:

I had some concerns over the tutorial too (the database access in the controllers, and the ViewBag stuff, since I'd never dealt with it before), so I was planning on getting a working test version up and running with the method suggested in the tutorial, and then going back and refactoring out the database access to use some kind of data access layer (likely the repository pattern). Would that, in your opinion, result in a decent architecture for the application, or is the tutorial so screwed up that it's best to start from scratch? The application is on Azure, and uses an existing database (also on Azure), so I've been following along with the "Database first" parts of the tutorial.

The only issue with that is that you won't be able to unit test your controllers until you refactor out all the database access. The architecture sounds like it would be fine at the end of it, though.

Try to avoid using data models as View models or Action method parameters from the very beginning. That can be a bit harder to refactor after the fact.

ShaunO
Jan 29, 2006

Bognar posted:

Try to avoid using data models as View models or Action method parameters from the very beginning. That can be a bit harder to refactor after the fact.

Can you go into more detail on what you mean by avoiding Action method parameters? Or do you mean don't bind your data model to the action parameters?

epswing
Nov 4, 2003

Soiled Meat

ShaunO posted:

Can you go into more detail on what you mean by avoiding Action method parameters? Or do you mean don't bind your data model to the action parameters?

Yes that's what he meant.

Edit: Took me a while to accept it, but you're going to end up with lots of small classes with exactly the right properties to hydrate your view. Avoid the urge to reuse these view classes in other views "because they're pretty similar", because pretty soon you'll have one big ThingModel that you use to edit Things, create Things, list Things, each of which use parts of the monolithic ThingModel.

epswing fucked around with this message at 21:42 on Jan 13, 2014

Cervix-A-Lot
Sep 29, 2006
Cheeeeesy
Figured this out. Sorry.

Cervix-A-Lot fucked around with this message at 03:29 on Jan 14, 2014

Mr. Crow
May 22, 2008

Snap City mayor for life
This is irritating and probably trivial.

How do I bind to nullable value types in WPF without a converter, is it even possible?

epswing
Nov 4, 2003

Soiled Meat

Mr. Crow posted:

This is irritating and probably trivial.

How do I bind to nullable value types in WPF without a converter, is it even possible?

What problem are you experiencing? I've bound lots of TextBox elements to, for example, int?, without issue.

Mr. Crow
May 22, 2008

Snap City mayor for life

epalm posted:

What problem are you experiencing? I've bound lots of TextBox elements to, for example, int?, without issue.

Basically this

code:
<Label Content="{Binding Path=GpsElevation, ElementName=LayoutRoot}"
        ContentStringFormat="Your GPS Elevation is {0}">
    <Label.Style>
        <Style BasedOn="{StaticResource DefaultLabelStyle}" TargetType="Label">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=GpsElevation, ElementName=LayoutRoot}" Value="{x:Null}">
                    <Setter Property="ContentStringFormat" Value="No GPS Elevation" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Label.Style>
</Label>
never ends up displaying anything. Read something about an issue where Bindings with an initial value of null can get cleared out or something but I think it was in reference to an old version of .NET?

epswing
Nov 4, 2003

Soiled Meat
Ah, yeah I've ran into that before. You can't set attributes in the element, and then set them again in the style. To be more specific, you're setting ContentStringFormat twice. Don't use style/datatrigger stuff for this, just use TargetNullValue.

XML code:
<Label Content="{Binding Path=GpsElevation,
                         ElementName=LayoutRoot,
                         TargetNullValue='No GPS Elevation'}"
       ContentStringFormat="Your GPS Elevation is {0}" />
Also I think you might want to be using StringFormat in the binding:

XML code:
<Label Content="{Binding Path=GpsElevation,
                         ElementName=LayoutRoot,
                         TargetNullValue='No GPS Elevation'
                         StringFormat='Your GPS Elevation is {0}'}" />
(Untested)

Mr. Crow
May 22, 2008

Snap City mayor for life

epalm posted:

Ah, yeah I've ran into that before. You can't set attributes in the element, and then set them again in the style. To be more specific, you're setting ContentStringFormat twice. Don't use style/datatrigger stuff for this, just use TargetNullValue.

XML code:
<Label Content="{Binding Path=GpsElevation,
                         ElementName=LayoutRoot,
                         TargetNullValue='No GPS Elevation'}"
       ContentStringFormat="Your GPS Elevation is {0}" />
Also I think you might want to be using StringFormat in the binding:

XML code:
<Label Content="{Binding Path=GpsElevation,
                         ElementName=LayoutRoot,
                         TargetNullValue='No GPS Elevation'
                         StringFormat='Your GPS Elevation is {0}'}" />
(Untested)

Derp, I've run into this multiple times (some issue related to setting an attribute and trying to change it from the style via a trigger or something) and keep forgetting about it when a similar issue shows up :doh:.

The StringFormat thing also was what I wanted (though, without looking into it to much, I'm confused because people keep something about StringFormat not working on ContentControls and that you need to use ContentStringFormat :iiam:); having just ContentStringFormat would do something like "You GPS Elevation is No GPS Elevation".

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug
I saw a great presentation by Dustin Campbell from Microsoft last week. He talked about the future of C# and mentioned some cool stuff they have planned for C# 6.

I found a blog post by someone who paid attention at a similar talk and took good notes, which I didn't.

Gul Banana
Nov 28, 2003

That stuff looks pretty great. I hope that either a) it gets incorporated into VB.NET or b) it's sufficient incentive for my workplace to stop preferring VB :[

What worries me is that the major gains are in brevity, and in the past the VB team has chosen to err on the side of "we can generate the same IL, but we will make you type twice as much code to do so". The bad lambdas, for example, make operator-style linq such a pain :(

RICHUNCLEPENNYBAGS
Dec 21, 2010

Ithaqua posted:

I saw a great presentation by Dustin Campbell from Microsoft last week. He talked about the future of C# and mentioned some cool stuff they have planned for C# 6.

I found a blog post by someone who paid attention at a similar talk and took good notes, which I didn't.

This is all great. I'm glad to see them moving in a direction that is gradually reducing boilerplate you have to write.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

Ithaqua posted:

I saw a great presentation by Dustin Campbell from Microsoft last week. He talked about the future of C# and mentioned some cool stuff they have planned for C# 6.

I found a blog post by someone who paid attention at a similar talk and took good notes, which I didn't.

TFA posted:

// monadic null checking
if (points?.FirstOrDefault()?.X ?? -1 )

This is awesome. We've discussed this kind of feature at length in my office, even suggested the exact same signature (I think we called it a "coalescing access operator"). It just gets so annoying to have to write things like:

code:
public bool IsBazzed(Thing thing)
{
    if (thing == null) return false;
    if (thing.Foo == null) return false;
    if (thing.Foo.Bar == null) return false;

    return thing.Foo.Bar.IsBazzed
}
--------------

ShaunO posted:

Can you go into more detail on what you mean by avoiding Action method parameters? Or do you mean don't bind your data model to the action parameters?

Sure. You should avoid your Action method signatures having Models as parameters. Try to stick to primitive types or parameter objects created just for that method (or similar methods). Basically, never do this poo poo (from http://www.asp.net/mvc/tutorials/mvc-5/introduction/examining-the-edit-methods-and-edit-view):

code:
public ActionResult Edit([Bind(Include="ID,Title,ReleaseDate,Genre,Price")] Movie movie)
{
    if (ModelState.IsValid)
    {
        db.Entry(movie).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(movie);
}
Notice the BindAttribute that they added in to protect themselves from their own lovely practices. If they were using a type specifically for that request (or god forbid, an explicit primitive parameter for each value they might expect to receive) then they wouldn't have to worry about "over-posting". Or, if they explicitly pulled a record from the database and set the fields they wanted to change instead of just blindly setting the whole object as modified they could avoid this problem as well. Nevermind that they're accessing their database from their controller and using a private context available to the whole class rather than just scoped to the specific method. Nearly everything in these tutorials is a clusterfuck of bad practice.

This came off a bit more hostile than I was expecting - probably 'cause I've been spending more time than I should be trying to tell our new guy to unlearn nearly everything those tutorials have taught.

uXs
May 3, 2005

Mark it zero!

Bognar posted:

monadic null checking

Instant upgrade to whatever VS version that'll have this.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

Bognar posted:

This is awesome. We've discussed this kind of feature at length in my office, even suggested the exact same signature (I think we called it a "coalescing access operator"). It just gets so annoying to have to write things like:

code:
public bool IsBazzed(Thing thing)
{
    if (thing == null) return false;
    if (thing.Foo == null) return false;
    if (thing.Foo.Bar == null) return false;

    return thing.Foo.Bar.IsBazzed
}

Yup, that was the thing that made me say "holy poo poo I want this now now now"

Not mentioned in the blog post is that since the Roslyn compiler will be used for C# 6, they'll be able to easily add new code inspections/quick fixes. Basically, stuff that we've always used ReSharper for will be in VS. I think this means ReSharper's dominance in the VS plugin market is coming to an end.

RICHUNCLEPENNYBAGS
Dec 21, 2010
You know, as useful as ReSharper is sometimes I wonder about the suggestions. Some of the Linq query replacements for loops are kind of difficult to read.

I mean, not so difficult you can't look and figure out but that's a distraction.

ljw1004
Jan 18, 2005

rum

Gul Banana posted:

That stuff looks pretty great. I hope that either a) it gets incorporated into VB.NET or b) it's sufficient incentive for my workplace to stop preferring VB :[

What worries me is that the major gains are in brevity, and in the past the VB team has chosen to err on the side of "we can generate the same IL, but we will make you type twice as much code to do so". The bad lambdas, for example, make operator-style linq such a pain :(

Oh yes, it's getting incorporated into VB (I'm the VB design lead). I blogged about a few bits and pieces...
http://blogs.msdn.com/b/lucian/archive/2013/12/13/some-potential-language-ideas-for-future-versions-of-vb.aspx

Dietrich
Sep 11, 2001

RICHUNCLEPENNYBAGS posted:

You know, as useful as ReSharper is sometimes I wonder about the suggestions. Some of the Linq query replacements for loops are kind of difficult to read.

I mean, not so difficult you can't look and figure out but that's a distraction.

I personally despise the from whatever select x, y syntax for using linq, and stick with the whatever.select(w => new { w.x, w.y}); syntax, but maybe it's just me. Either way a lot of the time resharper makes good suggestions more than a majority of the time.

Munkeymon
Aug 14, 2003

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



Dietrich posted:

I personally despise the from whatever select x, y syntax for using linq, and stick with the whatever.select(w => new { w.x, w.y}); syntax, but maybe it's just me. Either way a lot of the time resharper makes good suggestions more than a majority of the time.

It's not just you. Their pidgin SQL just gives me a headache because it's not SQL but looks similar enough that it requires extra mental effort to reason about what it's doing differently. At least that's what I think is going on. At any rate, I always write LINQ in object.Linq(lambda or function call) style because I find it a lot easier to both read and write.

But, hey, maybe I'm (more) broken (than most people) :v:

wwb
Aug 17, 2004

^^^ nope.

I finally had to learn the pidgin sql for ravendb. God I hate it.

RICHUNCLEPENNYBAGS
Dec 21, 2010

Dietrich posted:

I personally despise the from whatever select x, y syntax for using linq, and stick with the whatever.select(w => new { w.x, w.y}); syntax, but maybe it's just me. Either way a lot of the time resharper makes good suggestions more than a majority of the time.

I agree. But it suggests them for foreach loops too and honestly sometimes it gets a little heady for my tastes.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

RICHUNCLEPENNYBAGS posted:

I agree. But it suggests them for foreach loops too and honestly sometimes it gets a little heady for my tastes.

The things that ReSharper can generate from a foreach loop is absolutely mind-boggling. Why yes, of course I wanted this readable and understandable foreach block to be re-written with 3 SelectManys, 2 Aggregates, and a GroupJoin.

RICHUNCLEPENNYBAGS
Dec 21, 2010

Bognar posted:

The things that ReSharper can generate from a foreach loop is absolutely mind-boggling. Why yes, of course I wanted this readable and understandable foreach block to be re-written with 3 SelectManys, 2 Aggregates, and a GroupJoin.
Right, yeah. This is what I meant.

Also, I guess I can configure this somehow, but I don't like how it suggests I eliminate named parameters everytime I use them. I'm using them because it's confusing without them! Come on.

Also, I have ReSharper set to indent everything GNU-style, which is great, but it clashes with Visual Studio sometimes which is unfortunate. I mean I would just set VS to use GNU-style if it were an option.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

RICHUNCLEPENNYBAGS posted:

Also, I guess I can configure this somehow, but I don't like how it suggests I eliminate named parameters everytime I use them. I'm using them because it's confusing without them! Come on.

Wanting/needing to use named arguments because not using them is confusing is a code smell -- your method either has too many arguments, or it could benefit from passing in an object that encapsulates the necessary arguments. Or both.

RICHUNCLEPENNYBAGS
Dec 21, 2010
What kind of project only ever calls methods defined by the project itself?

Some of Microsoft's own stuff has like a billion overloads and optional arguments.

Gul Banana
Nov 28, 2003

ljw1004 posted:

Oh yes, it's getting incorporated into VB (I'm the VB design lead). I blogged about a few bits and pieces...
http://blogs.msdn.com/b/lucian/archive/2013/12/13/some-potential-language-ideas-for-future-versions-of-vb.aspx

Well, that's encouraging. I like, for example, the ideas about comment placement relaxation, params IEnumerable, and trivial/primary constructors. If prefixing variables with _ or something is what it takes to work around the case sensitivity, so be it..

As a VB library developer (working on frameworks, rather than applications per se), the single biggest improvements to my quality of life would be increased conciseness. Stuff like working type inference for If(x,y,z), shorter syntaxes for generics and anonymous functions, etc. Here's one way that perhaps expression-bodied functions could look, similar to expression lambdas:
code:
Public Overrides GetHashCode() => X.GetHashCode() % Y.GetHashCode()
Public Dist() => Math.Sqrt(X * X + Y * Y)
' then if you needed to narrow or specify the return type, this:
Public Dist() As Double => Math.Sqrt(X * X + Y * Y)

Munkeymon
Aug 14, 2003

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



Ithaqua posted:

it could benefit from passing in an object that encapsulates the necessary arguments

So instead of having the compiler/runtime make sure the arguments are all there for him he can check it by hand? gently caress that noise. I'd rather have a 10-argument method with everything all laid out for me in Intellisense than write code to verify that some configuration object has been fully initialized. I also use Python regularly, so the named argument standard that works pretty well for it is probably influencing my opinion a bit.

glompix
Jan 19, 2004

propane grill-pilled

Ithaqua posted:

Wanting/needing to use named arguments because not using them is confusing is a code smell -- your method either has too many arguments, or it could benefit from passing in an object that encapsulates the necessary arguments. Or both.

Then why is the feature even there? I agree with you to a degree, but in the real world named arguments can help. Sometimes I use them to give hints to a method. For instance, in HTML helpers, it's clearer to do something like:

code:
@Html.SomeWidget(m => m.SomeProp, attributes: new { @class = "wow" })
than this:

code:
@Html.SomeWidget(m => m.SomeProp, null, new { @class = "wow" })
Where that middle null is a RouteValueDictionary or something I don't give a poo poo about sometimes. I'm not going to new up an object every time I want to render a widget.

Dietrich
Sep 11, 2001

Munkeymon posted:

So instead of having the compiler/runtime make sure the arguments are all there for him he can check it by hand? gently caress that noise. I'd rather have a 10-argument method with everything all laid out for me in Intellisense than write code to verify that some configuration object has been fully initialized. I also use Python regularly, so the named argument standard that works pretty well for it is probably influencing my opinion a bit.

You're missing the point. If you're passing 10 arguments to a method, it's likely to be a pretty complicated method, and complicated methods are bad. They are hard to follow, tend to be very long, and so on.

It's good to break complicated stuff up into smaller, independently testable components.

It makes good sense to have the configuration of a process to be executed be encapsulated in a class. That way if you've got variables that depend upon each-other, you can have the validation of these dependencies handled in a validate method in that class, or something like that. Then you can unit-test it to make sure it works right, and the method that performs this process can do one thing, instead of several things.

Nevett
Aug 31, 2001

glompix posted:

Then why is the feature even there? I agree with you to a degree, but in the real world named arguments can help. Sometimes I use them to give hints to a method. For instance, in HTML helpers, it's clearer to do something like:

code:
@Html.SomeWidget(m => m.SomeProp, attributes: new { @class = "wow" })
than this:

code:
@Html.SomeWidget(m => m.SomeProp, null, new { @class = "wow" })
Where that middle null is a RouteValueDictionary or something I don't give a poo poo about sometimes. I'm not going to new up an object every time I want to render a widget.

I think the important part of Ithaua's quote is

quote:

because not using them is confusing

In your example, it's a convenience, which I'm not sure anyone would argue against.

If you've got so many arguments in methods that things are confusing, it can (not always) be an indicator of poor division of responsibilities/data encapsulation between your various classes.

Edit: ^ and what Dietrich said, better than me.

gariig
Dec 31, 2004
Beaten into submission by my fiance
Pillbug

Munkeymon posted:

So instead of having the compiler/runtime make sure the arguments are all there for him he can check it by hand? gently caress that noise. I'd rather have a 10-argument method with everything all laid out for me in Intellisense than write code to verify that some configuration object has been fully initialized. I also use Python regularly, so the named argument standard that works pretty well for it is probably influencing my opinion a bit.

You can have the configuration object enforce that everything is passed in via the constructor. Possibly marking the properties read-only to really make sure. I think Ithaqua's problem is having method calls like
code:
Frobulate(fileName, true, false, 0, 1024, buffer, output, true);
Instead of taking a FrobulateConfiguration object that stores all of that. There are definitely times when having named parameters are useful like the Razor HTML helpers post by glompix, COM objects with optional parameters, etc. I consider using named parameters to be a code smell and a sign that refactoring is required.

Microsoft having lots of overloads being bad I think it depends on what you are building. For framework-ish code like the BCL you are probably going to have lots of it. Look at all the StreamReader/Writer function calls to see all the crazy stuff you might want to do to a stream. For your own code I think splitting out calls is better. Example
code:
Frobulate(fileName, true, false, 0, 1024, buffer, output, true);//a file
Frobulate(URL, output, true);//a URL
Although somewhat obvious the first Frobulates a file and the other is a URL a better way is
code:
FrobulateFile(fileName, true, false, 0, 1024, buffer, output, true);//a file
FrobulateURL(URL, output, true);//a URL

Munkeymon
Aug 14, 2003

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



Dietrich posted:

You're missing the point. If you're passing 10 arguments to a method, it's likely to be a pretty complicated method, and complicated methods are bad. They are hard to follow, tend to be very long, and so on.

Yes, I'm well aware of this argument, but passing around an object that I have to write code to validate is making the code more complicated in general because I have to write more code to validate it before I use it and my users can't just look at the method signature via Intellisense to see what they need to pass in. Instead, they have to waste time looking up some configuration object.

quote:

It's good to break complicated stuff up into smaller, independently testable components.

Agreed, but you also don't expose helper methods, so breaking up a big, complicated public method into a series of smaller, less complex but probably private* helpers isn't going to make anything more testable.

*because if your class was going to expose this functionality it'd already be in a different, public method or you've copy-pasted code and I want to break your fingers

quote:

It makes good sense to have the configuration of a process to be executed be encapsulated in a class. That way if you've got variables that depend upon each-other, you can have the validation of these dependencies handled in a validate method in that class, or something like that. Then you can unit-test it to make sure it works right, and the method that performs this process can do one thing, instead of several things.

You can do all of those things with less code to maintain by using method arguments. Look at Bognar's post about not passing models around.

Dietrich
Sep 11, 2001

Munkeymon posted:

Yes, I'm well aware of this argument, but passing around an object that I have to write code to validate is making the code more complicated in general because I have to write more code to validate it before I use it and my users can't just look at the method signature via Intellisense to see what they need to pass in. Instead, they have to waste time looking up some configuration object.

Validating code is among the simplest code in the world, and frankly you should be doing it anyway even if you didn't have a configuration object. What if someone passes a null in, but you don't check it, and you're halfway though some set of changes when your code errors out hitting the null reference? If you're skipping argument validation because you expect the compiler to tell you if someone missed an argument, you're really half-assing it. You need to further ensure that the arguments passed to you are valid arguments.

There are libraries such as Conditions that make this as easy as
C# code:
Condition.Requires(url)
  .IsNotNullOrEmpty()
  .StartsWith("http://")
  .EndsWith(".html");

quote:

Agreed, but you also don't expose helper methods, so breaking up a big, complicated public method into a series of smaller, less complex but probably private* helpers isn't going to make anything more testable.

*because if your class was going to expose this functionality it'd already be in a different, public method or you've copy-pasted code and I want to break your fingers

This is all pretty hard to discuss without a concrete problem to use as a reference, but breaking down a complicated method into lots of private methods that get chained together is only a small step in the right direction.

Classes should have one purpose, as should methods within classes. A single method should not, for example, construct a web-client, use that webclient to download the HTML at a URL, use a regex pattern to parse the HTML, construct a enumerable of complex objects from the results, and then return them. In order to unit-test that method, you'd have to set up the entire ecosystem.

It be better to have a method that constructs a web-client, a method that parses HTML and returns a set of matches, and a method that takes a set of matches and constructs an enumerable of complex objects. Then you can unit-test each of these methods in isolation. Then you can make a set of static HTML files for the possible kinds of results, and pass each to the parsing method, and validate that the results are what you expect.

There are numerous strategies to unit test functionality without making it public, by the way, if that is your concern.

quote:

You can do all of those things with less code to maintain by using method arguments.
Unit testable code is cheaper to maintain than non-unit testable code. Code-golf may be a fun distraction, but it is not the proper way to develop applications that won't become less maintainable over time.

quote:

Look at Bognar's post about not passing models around.

I'm not talking about passing entity framework models in as method arguments. The way I develop things, EF/NH models never leave the data namespace.

ManoliIsFat
Oct 4, 2002

Dietrich posted:

There are libraries such as Conditions that make this as easy as
C# code:
Condition.Requires(url)
  .IsNotNullOrEmpty()
  .StartsWith("http://")
  .EndsWith(".html");
Cool, thanks for this. I hate having huge blocks of "if this param is null or out of range, throw an exception" at the top of my functions.

quote:

There are numerous strategies to unit test functionality without making it public, by the way, if that is your concern.
Oooh I'm quite interested to hear about this.

Munkeymon
Aug 14, 2003

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



Dietrich posted:

Validating code is among the simplest code in the world, and frankly you should be doing it anyway even if you didn't have a configuration object. What if someone passes a null in, but you don't check it, and you're halfway though some set of changes when your code errors out hitting the null reference? If you're skipping argument validation because you expect the compiler to tell you if someone missed an argument, you're really half-assing it. You need to further ensure that the arguments passed to you are valid arguments.

There are libraries such as Conditions that make this as easy as
C# code:
Condition.Requires(url)
  .IsNotNullOrEmpty()
  .StartsWith("http://")
  .EndsWith(".html");

That's fair and thanks for telling me about Conditions, but the whole point of a method signature is to say 'I need this list of stuff to work' and it doesn't actually help readability or usability to say 'go look somewhere else to figure out what you need to give me'.

quote:

Unit testable code is cheaper to maintain than non-unit testable code. Code-golf may be a fun distraction, but it is not the proper way to develop applications that won't become less maintainable over time.

I'm not talking about golf or skipping testing. I'm saying you don't need this pointless arguments object laying around in order to unit test a method and it doesn't make testing easier, anyway.

quote:

I'm not talking about passing entity framework models in as method arguments. The way I develop things, EF/NH models never leave the data namespace.

Oh, heh, I skimmed it and didn't realize it was an EF object - I just thought he meant a generic model.


This is really a separate argument:

quote:

This is all pretty hard to discuss without a concrete problem to use as a reference, but breaking down a complicated method into lots of private methods that get chained together is only a small step in the right direction.

Classes should have one purpose, as should methods within classes. A single method should not, for example, construct a web-client, use that webclient to download the HTML at a URL, use a regex pattern to parse the HTML, construct a enumerable of complex objects from the results, and then return them. In order to unit-test that method, you'd have to set up the entire ecosystem.

It be better to have a method that constructs a web-client, a method that parses HTML and returns a set of matches, and a method that takes a set of matches and constructs an enumerable of complex objects. Then you can unit-test each of these methods in isolation. Then you can make a set of static HTML files for the possible kinds of results, and pass each to the parsing method, and validate that the results are what you expect.

There are numerous strategies to unit test functionality without making it public, by the way, if that is your concern.

I agree that you should split out the part that sets up the file request and then calls the overload that takes a stream, but, realistically, you should use a library to do the parsing.

On general principal, I'll avoid moving code to it's own method unless it's re-used, but I will avoid folding methods back into single call sites. That's because I think that taking that code out of its intended context can obscure its meaning and encourage architecture astronaut thinking: well it only has to handle arrays because that's what the only call site will pass it, but what if someone wants to hand it their bespoke, artisanal data structure some day?!

Adbot
ADBOT LOVES YOU

Dietrich
Sep 11, 2001

ManoliIsFat posted:

Oooh I'm quite interested to hear about this.

Off the top of my head:

1) Make your unit tests part of your library, instead of a different assembly. (The simplest approach and honestly just fine when size of assembly and initial load performance are not huge concerns)

2) Instead of having a test assembly that references your assembly-under-test, have a test assembly that uses file links to include the code of your assembly-under-test.
Acts like option 1, but with the added benefit that you have no unit-test code compiled in your final version. Downside- you've got to manually maintain the test project to make sure that it has all the code files from the tested project, or it probably won't compile.

3) Use internal instead of private, and add
C# code:
[assembly: InternalsVisibleTo("name of testing assembly here")]
to your assembly.cs of your library.

  • Locked thread