News for hackers. Stuff that matters.
Re:.NET 5.0 by balabaster on Tuesday November 10, 2020 @12:15PM (#25048329)
You'd want your config injected so that you can swap out configs for test harnesses for continuous integration and deployment. It's one of the mainstays of making your software deployable by automation.
Re:.NET 5.0 by mattmanser on Tuesday November 10, 2020 @12:32PM (#25048525)
You know a better way of doing this?

appsettings.Test.json

Voila, different settings!

I've said elsewhere, the DEFAULT should be super simple, really, really, really easy to use. No thought, no effort, just use it.

If you want to go all crazy and start injecting values into your config in your unit tests, great to have that option, you should have that option. But you're the one who should be scrabbling around writing tons of extra boilerplate code, not me.

But I just want to set a filepath, that's probably never going to change, but might one day. Or an email address to send a weekly summary email to. Or some settings on paging that the client might change their mind about once and I don't want to have to rebuild the project.

The vast majority of config settings are just cover your ass in case you need to one day change this value. They don't need to be tested.

So it not the "normal" path to need to test config values. It's not the path the vast majority of programmers need.

Re:.NET 5.0 by 0xcoffee on Tuesday November 10, 2020 @01:05PM (#25048959)
I'm going to have to disagree here. Having a settings object is much easier then appsettings.Test.json

The .json is for running the application locally. A unit test should be able to cover if a setting has value 'a, b or c', which is much easier with a regular object.

Re:.NET 5.0 by aidenn0 on Tuesday November 10, 2020 @04:00PM (#25051841)
Making software harder to read, write, and maintain in the name of making unit tests easier to read, write, and maintain is putting the cart in front of the horse.
Re:.NET 5.0 by jolux on Tuesday November 10, 2020 @10:33PM (#25055229)
Indeed it would be but making unit tests easier to read, write, and maintain should force you to make the application easier to write and maintain. I agree that readability can suffer somewhat if you’re not careful though.
Re:.NET 5.0 by aidenn0 on Thursday November 12, 2020 @02:29PM (#25073849)
Writing quality tests is often much harder than writing quality software, and I find quality unit tests to be significantly harder than e2e or integration tests, so if I can only write software for which I can also write quality unit tests, I am greatly reducing the space of quality software I can write.

Yes, one solution is to make the software more complicated in order to make the tests less complicated, but the other solution is to just use fewer unit tests. Note that I'm not advocating not testing (my motto with software is "If nobody tested it, then you can be certain it doesn't work."), but One good e2e test can often replace dozens of unit tests.

I find that E2E -> Integration -> Unit form a scale from "easy to write, hard to run" on the e2e side and "easy to run, hard to write" on the unit side.

There are exceptions; testing that you can sort N objects in M microseconds is a trivial test to write, and potentially a challenging requirement to implement, and a unit test might be completely appropriate there. However, for the general case, I find unit tests to be too often trying to make a square-peg fit a round-hole, and then saying "okay we'll shave the corners off a bit so that it's easier to fit in this hole" rather than saying "maybe we should use a square hole"

Re:.NET 5.0 by jolux on Thursday November 12, 2020 @03:28PM (#25074507)
> Writing quality tests is often much harder than writing quality software

I personally believe that tests are how you prove you understand the code you’re writing, and the changes you’re making. If they’re harder to write than the software, you probably need to further clarify the behavior being tested, but they’re going to be hard sometimes, just as some software is hard.

> if I can only write software for which I can also write quality unit tests, I am greatly reducing the space of quality software I can write.

I follow TDD, so indeed I only ever write code that I know how to write unit tests for. I haven’t found that TDD restricts the kind of software that I can write, but sometimes it does mean I’m slower to get started in a particular domain. I do find that once over the initial hump my unit tests are a constant companion that make me more comfortable and productive in developing new software.

Realistically we both agree that testing software is important, we just disagree in the details. The problems I see with end to end testing are that good patterns for building extensible and loosely coupled end to end testing suites are not as widespread in the industry as they are for unit and even integration tests.

My theory as to why is that we assume that end to end tests are going to be slow to run and “heavy” in some sense, and that as such we aren’t running them often enough to force the improvements we need in those suites.

I always find it weird when discussions about unit tests become discussions about other kinds of testing, though. I think high (though not necessarily 100%, as that’s arbitrary) and increasing unit test coverage are an empirical sign of code that is being properly maintained. They are not the last word in testing and software QA, they’re closer to being an indicator like using CI and a proper build system instead of a thousand line shell script, and having quality well-maintained documentation. As I said in another comment, I am not going to say that unit tests are the only way to write good software. They’re a powerful tool that I have found helps me and my teams a lot. That’s as far as I will go.

Re:.NET 5.0 by mattmanser on Wednesday November 11, 2020 @06:15PM (#25064173)
This is simply a dogma, if you want to follow that dogma, fine, but there's no reason to be forcing everyone else to.
Re:.NET 5.0 by jolux on Wednesday November 11, 2020 @09:30PM (#25065764)
I'm not going to force anyone else to, I am expressing an opinion. I would be pushing this position if I were on a team with you because it's not just a dogma, it reflects the best knowledge I have about how to build software well. You are free to build software as you see fit and have always been.
Re:.NET 5.0 by ljm on Wednesday November 11, 2020 @07:11AM (#25057693)
The age old TDD dilemma, that treats the test suite as first class, rather than the end user's experience.
Re:.NET 5.0 by balabaster on Wednesday November 11, 2020 @09:41AM (#25058766)
The end user being the programmer?

I find it humorous that so many programmers still can't see past the end of their nose when it comes to designing code for application testing.

An application is deliverable. That means testable and deployable with a consistent, repeatable process. Anything short of that is not an application, it's a prototype.

Yes, it takes longer to deliver up front, but it removes the long tail of maintenance. Getting a low quality product out of the door makes for a bad user experience and garners you a bad reputation.

The test suite _should_ be a first class citizen.

Re:.NET 5.0 by mattmanser on Wednesday November 11, 2020 @06:36PM (#25064324)
What utter nonsense.
Re:.NET 5.0 by sbelskie on Tuesday November 10, 2020 @12:39PM (#25048611)
I’m confused as to what you want instead of what Asp.Net core offers. Nothing is forcing you to inject configuration or to use IOptions. In most cases you don’t even need to do anything with the configuration builder because that is part of the default of how the host gets setup. You’re configuration should be automatically built from environment vars and appsettings.json.

And of course you can always just access environment variables directly if you want to.

Re:.NET 5.0 by mattmanser on Tuesday November 10, 2020 @01:27PM (#25049264)
I think they should have done what every other framework does and make it super easy to access, like this:

    Env.Config("Settings:MyEasyValue");
Or:

    Env.Config<Settings>().MySuperEasyTypedValue;

And the Dependency Injection? Sure, add some version you can DI with. But not the default.

I now know how to navigate the mess they've made, but it's not time that I feel where I gained anything in my life, it was just frustrating.

Here's one (of many) questions asking simple questions on how to access config values in .Net core:

https://stackoverflow.com/questions/46940710/getting-value-f...

280k views!

And look at the sheer length of that answer.

If you think they succeeded in making a good configuration library, we have very different definitions of success.

Re:.NET 5.0 by maybeOneDay on Tuesday November 10, 2020 @02:13PM (#25050179)
The sheer length of the answer? That's because it shows optional, more advanced ways to get config stuff.

Is this so hard?

    public class AccountController : Controller
    {
        private readonly IConfiguration _config;
    
        public AccountController(IConfiguration config)
        {
            _config = config;
        }
    
        public IActionResult ResetPassword(int userId, string code)
        {
            var vm = new ResetPasswordViewModel
            {
                PasswordRequiredLength = _config.GetValue<int>(
                    "AppIdentitySettings:Password:RequiredLength"),
                RequireUppercase = _config.GetValue<bool>(
                    "AppIdentitySettings:Password:RequireUppercase")
            };
    
            return View(vm);
        }
    }
Re:.NET 5.0 by vonseel on Wednesday November 11, 2020 @06:01AM (#25057349)
Makes perfect sense to me, even as a mostly-Python developer with very limited experience in .NET/C# or other ecosystems.
Re:.NET 5.0 by mattmanser on Wednesday November 11, 2020 @05:08AM (#25057096)
Is this supposed to be ironic? Or just unintentionally?

"What's hard about [mass of code] compared to [one liner]?"

Re:.NET 5.0 by maybeOneDay on Wednesday November 11, 2020 @06:44AM (#25057549)
The "mass" of code is an API controller, not just a way to get settings. It's an example of config use in real code. There are roughly 4 lines of code to get two variables out of the settings.json. This scales quite nicely - if we needed 8 different variables from settings then it would be 10 lines of code for 8 variables.

Sure, it could be done in one line. My point wasn't to say that this is the most terse environmental variable code possible. My point was to say that it's disingenuous to say "look at the sheer length of that answer" as a way to state that the way to get env variables is hugely bloated. It's literally one ctor param and one private variable. If you don't like that for stylistic reasons, that's fine. I understand the argument saying "there should just be a static class with a readonly prop per variable", I just don't think that this particular code is in real terms actually any worse.

Re:.NET 5.0 by nightski on Tuesday November 10, 2020 @01:34PM (#25049371)
It would be pretty trivial to implement the Env class you desire abstracting away the DI stuff.
Re:.NET 5.0 by brynjolf on Wednesday November 11, 2020 @04:10AM (#25056798)
They have that? You can call Configuration manually if you prefer that way. I feel like everyone in this thread is working overtime to justify complaining when there are multiple options to do what you want.
Re:.NET 5.0 by mattmanser on Wednesday November 11, 2020 @05:15AM (#25057130)
I was thinking about this last night, that's actually not at all true.

A 'new' C# programmer doesn't. You have to be advanced enough at C# to know you can do that (i.e. not a junior or outsider)

It's also not clear how the config works at first glance or the implications of using a POCO on the app lifecycle.

An experienced coder will have to ask themselves questions like, if I store the IOptions object, will it automatically update? If I assign the POCO in startup, will it be a single object, or does startup get called for every new request? Or maybe it will get called for every thread? Or maybe if there are no requests for 10 minutes it automatically shuts down?

Re:.NET 5.0 by fearface on Tuesday November 10, 2020 @12:24PM (#25048441)
You can do that just with different config files or env vars too. No need to complicate code for stuff that can be done easily differently as well.
Re:.NET 5.0 by eropple on Tuesday November 10, 2020 @12:28PM (#25048480)
And then you realize that it's 2020 and you don't want configuration files, you want environment variables. Or, now that you've hardstuck yourself on environment variables and built all this stuff around them to set and re-set them properly between tests (now running either in multi-process, which good luck in most environments, or are just running in serial), you're using k8s and the voluming of secrets rather than exposing them as environment variables requires refactoring any code, both operational and testing, that touches them.

"But wait," you say. "I'll just pass in the thing that provides that data"--and you just reinvented DI, albeit likely poorly.

DI is the removal of complication when it is done correctly. (I have no opinion on whether ASP.NET Core does it correctly.)

Re:.NET 5.0 by csharptwdec19 on Tuesday November 10, 2020 @12:39PM (#25048614)
> DI is the removal of complication when it is done correctly. (I have no opinion on whether ASP.NET Core does it correctly.)

I do, it was done in a really weird way and I don't care for the provided DI Abstractions nor the 'Microsoft.Extensions.Configuration' namespace.

To take the 'common' object used for configuration, the nuget package for IOptions<T> requires pulling in Microsoft's DI Abstraction..

That's the first sign of a smell. Config and DI can go hand in hand, but they should still be orthogonal.

The further you go down the DI stack, the more you can see that it's an abstraction has a lot of tradeoffs for front-line devs in the name of using the same abstraction for the underlying framework.

Re:.NET 5.0 by rhencke on Tuesday November 10, 2020 @02:58PM (#25050986)
A better take on DI wireups in .NET: https://nblumhardt.com/2010/01/the-relationship-zoo/

The gist:

    Relationship                                Adapter Type     Meaning
    A needs a B                                 None             Dependency
    A needs a B at some point in the future     Lazy<B>          Delayed instantiation
    A needs to create instances of B            Func<B>          Dynamic instantiation
    A provides parameters of types X and Y to B Func<X,Y,B>      Parameterisation
    A needs all the kinds of B                  IEnumerable<B>   Enumeration
Re:.NET 5.0 by eropple on Tuesday November 10, 2020 @12:43PM (#25048667)
For sure--that sounds real smelly. (Unless it's being used to pull in attributes that are shared between and used for wire-up, but those should then be in a separate assembly.)
Re:.NET 5.0 by to11mtm on Tuesday November 10, 2020 @07:51PM (#25054269)
> (Unless it's being used to pull in attributes that are shared between and used for wire-up, but those should then be in a separate assembly.)

Right. It's primarily interfaces, but they are tangled.

This was especially painful between Net Core 2.0 and 3.1, because moving fast and breaking things is ugly when you have tangled dependencies and everyone is trying to catch up to the breaking API changes and related nuget versioning dance.

Re:.NET 5.0 by mumblemumble on Tuesday November 10, 2020 @01:50PM (#25049600)
> DI is the removal of complication when it is done correctly.

Personally, I would rephrase that as, "DI is a pattern that is designed to mitigate certain kinds of complexity when done correctly."

That leaves room for two ways in which it can backfire. Doing it wrong, like you say, but also doing it in situations where you don't actually have one of the problems it's trying to solve. Cost/benefit ratios always get out of whack when there's no benefit to offset the cost.

Re:.NET 5.0 by eropple on Tuesday November 10, 2020 @03:03PM (#25051063)
That is a fair edit, for sure. Many systems don't need a formal DI mechanism, though should they scale to a certain human-size they'll probably invent enough of one anyway just through composition (if they don't collapse into a ball of mud).
Re:.NET 5.0 by mattmanser on Tuesday November 10, 2020 @12:33PM (#25048539)
You wouldn't be using the config at all if you're not using the config files. They're part of the default project.
Re:.NET 5.0 by ByteJockey on Tuesday November 10, 2020 @10:04PM (#25055081)
How is it that the big enterprise languages haven't gotten the ability to just mock imports yet?

There are certain benefits to DI, but this one seems more like a lack of tooling.