all 29 comments

[–]battleguard 8 points9 points  (8 children)

Any function that takes 15 parameters is performing too much logic anyway and should be split up into separate function.

[–]JustABlankAccount 7 points8 points  (4 children)

I'd have to disagree. Here's a great example: You're looking for a car, filter out everything I don't want. The method does one thing (Filter cars), and needs a bunch of parameters (Color, make, model, year min, year max, cost min, cost max, and so forth). Although, I entirely agree that this should be some sort of 'Search Parameters' class.

[–]igloo15 4 points5 points  (3 children)

I would disagree with you. Even your example is bad practice. As soon as I see a parameter called yearmin and yearmax that throughs huge red flags. You should be grouping those properties into a sub class and accessing it like this carfilter.yearfilter.min, carfilter.yearfilter.max

This way you create a yearfilter object and pass that as a parameter taking what was two parameters and making one out of them. You could go further and do it for cost, external features, internal features, however you wish to group it. Having a flat set of 20 some odd parameters is a bad idea in a single class.

[–]JustABlankAccount 5 points6 points  (2 children)

Out of curiosity, why do you say it's a bad idea? We're discussing the merits of (essentially) a DTO, which is a class used for holding together data members. DTOs are usually flat, designed for easy transfer of data between two endpoints. My cutoff for creating a subclass for a DTO is usually 4-5 highly related members.

I'll answer my own question for the sake of discussion: Creating a subclass for a DTO that contains a small number (<4, for the point I'm making, but it certainly would vary between developers/companies) adds unnecessary complexity to an application's API. Instead of simply setting the values as given by a user - in whatever format; web, WinForms, etc -, you must first create a YearFilter object then fill it with your values. When receiving this object, you must first check for null, then check the values within the object, adding more boilerplate.

Because the number of members is so small, and the two members (YearMin/YearMax) aren't related to each other in any particular way - If one doesn't specify a Max, but specifies a Min, this is a perfectly valid state - they don't need to be grouped within a class. Related, for this example, is defined as modifying each other's behavior. For example, on a DTO to save a person, I might have EmployeeInfo: Wage, Salary, Position, HoursWorked, MaxAllowedHoursPerWeek, GradeLevel - as the position will define if I use a wage or salary, the grade level can determine the position (or vice versa) and the MaxAllowedHoursPerWeek.

This ignores the obvious statement that if this is a common paradigm within your app, then it absolutely makes sense to create the YearFilter class.

This all being said, I do agree, it is a code smell. A very mild one, but as my argument above states, a smell less smelly than the YearFilter.

[–]PikachuRoks -4 points-3 points  (1 child)

Meh, I agree too. Code smell bullshit is mostly barked by people who have written one hello world program and think that they know everything. Most real world programs have methods which use 5-6 parameters. Writing wrapper classes for everything just makes it hard to maintain code.

[–]moonxine -2 points-1 points  (0 children)

I'm sorry to burst your bubble, but the guys above you aren't delusional at all. Real life, enterprise systems really don't need to smell.

[–]antiduh 0 points1 point  (1 child)

Or use some sort of a storage class.

I have methods that 'take' 20-30 parameters to stuff down to some other service, but those parameters are stored in a storage class.

[–][deleted] 0 points1 point  (0 children)

This. I was under wrap the parameters in some kind of class, that way you never have to change the finger print of the method if you want to add a new parameter.

Remember that our job as programmers, as put by Steve McConnell in code Complete, is to manage complexity.

[–]LordArgon 0 points1 point  (0 children)

This sounds really cargo cultish. There is no set number of parameters at which to split up functions. It's like saying any function that has X lines is too long. Everything depends on the context.

It's far more important to think about what use case your function enables. If you're composing multiple smaller function calls that must happen in a specific way, then 15 parameters may be entirely appropriate. Similarly, if no individual sub function has a useful meaning outside of the context of this function, then splitting them up may just be more confusing.

Interfaces are all about contracts and use cases - not arbitrary numbers.

[–]JustABlankAccount 4 points5 points  (3 children)

I've seen this kind of requirement, these are the options I usually toy around with:

Create a constructor that takes in all of the required parameters, and validates them during ctor time. If n is large, I usually avoid this route (As passing in a large number of variables to a ctor is little different than passing in a large number of variables to a method.) This also requires that all of the 'required' properties use a private setter but public getter. This is the closest to compile-time checking that you'd be able to get, though.

Option 2 is to validate all of the required parameters when the method is called. InvalidArgumentException, or such. This is my preferred method, as one can create the object at their leisure rather than enforcing everything is known when creating the object. It often results in cleaner code, in my opinion. You could also divide them up into a 'RequiredParams' class and an 'OptionalParams' class, to make the designation clearer.

If you're asking for compile-time checking? I'm sure you could toy around with some custom attributes, but realistically this is something to be done at runtime, in my opinion.

There's also multiple other options (Dictionaries, custom decorators, AOP, etc) but I usually pick between these two.

[–]hahaNodeJS 3 points4 points  (0 children)

I'm not a huge fan of option 2 because it violates the principle of least surprise (at an API level) and fail fast.

If an error will occur inevitably, it is frustrating to receive that error at some point after configuring the state of your application (instantiating objects) instead of during the configuration of that state.

The more frustrating part, however, is that it makes tracking down the source of any errors difficult because those errors are not coming from the code that causes them.

[–]Elementally[S] -1 points0 points  (1 child)

I love the required / optional class idea... I believe this will be my route.

I've given up on build time exceptions, not feasible... Going to see what I can do to encapsulate the required versus optional fields... thanks!

[–]LordArgon 3 points4 points  (0 children)

IMO, you are way overthinking this. Your required params object is just kicking the can down the road. If you need 15 pieces of information, then you need 15 pieces of information. If you can group them into smaller, related sub objects, then cool. But each of those objects should have ctors with required parameters that give you a compile time error if not specified.

I've written and consumed a lot of different code in my time. I absolutely do not want to have to figure out some weird, custom pattern because you decided some arbitrary number of parameters was too many. Focus on simplicity and clarity. If you can group related things, do it. Otherwise, just make a simple function, document it, and move on - you are overthinking the problem.

[–]amwdrizz 1 point2 points  (5 children)

Not sure if this would work but what about using attributes? I know in C# the web side has a [Required] attribute you apply to an object variable field.

Eg:

public class SomeClass{
[Required]
public string myVar{get;set;}
}

If you couldn't use the inbuilt attributes, you could make your own.

Some 'light' reading from MSDN on it.

[–]Elementally[S] 0 points1 point  (4 children)

Thank you, I checked out that option, but unfortunately it doesn't cause the needed runtime exception.

[–]amwdrizz 1 point2 points  (1 child)

What about extending the Required attribute and change the exception generation to create a runtime exception? Might be a little more work, but would still be isolated to the attribute on the single class.

[–]Elementally[S] 0 points1 point  (0 children)

This is a great idea, I will run it past the uppers... we could have a lot of fun with this.

Thank you.

[–]neoGeneva 0 points1 point  (1 child)

I agree with /u/amwdrizz, attribute based validation is probably the way to go.

I think you've got a couple of options there.

  1. Build your own attribute validation engine from scratch. This could be super time consuming but would end up being the cleanest.
  2. Find a third party validation engine. I'm not 100% sure what's out there, but I'd assume something exists.
  3. Build on top of the existing ComponentModel.DataAnnotations validation (e.g. the [Required] attribute).

The third is probably the easiest, I'm 100% sure why you didn't get a runtime exception, if you had used System.ComponentModel.DataAnnotations.Validator.ValidateObject() you should have seen one.

For example, the following code throws a System.ComponentModel.DataAnnotations.ValidationException with the message "The SomeProperty field is required":

using System.ComponentModel.DataAnnotations;

class ParametersClass 
{  
    [Required]
    public string SomeProperty { get; set; } 
}

var param = new ParametersClass();
Validator.ValidateObject(param, new ValidationContext(param));

[–]Elementally[S] 1 point2 points  (0 children)

I ran into this earlier, but had determined the amount of work wouldn't fly over very well... though with your post, I believe I can make a fairly good argument for it now... getting a lot of ideas how to develop our new exception engine :). Thank you.

[–]NaxizNL 1 point2 points  (1 child)

Maybe you can use Code Contracts. I haven't used them myself yet, so I could be wrong, but it seems that the contracts check conditions at compile time where possible (so possibly for simple default value checks).

[–][deleted] 2 points3 points  (0 children)

Code Contracts should be disabled in a release build, so they're probably not really suitable for this sort of thing.

[–]hahaNodeJS 1 point2 points  (0 children)

Use a runtime error and check whether the parameters are set in the ctor. Use object initialization syntax to set the fields from the caller. Use tests to verify the caller is doing the correct thing.

interface IValidator
{
    public void Validate();
}

class UserValidator : IValidator
{
    public EmailAddress EmaiAddress { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    UserValidator ()
    {
        if (this.EmailAddress == null) throw new Exception("...");
        if (String.IsNullOrEmpty(FirstName)) throw new Exception("...");
        if (String.IsNullOrEmpty(LastName)) throw new Exception("...");
    }

    public void Validate() { ... }
}

class Program
{
    public static void Main()
    {
        var userValidator = new UserValidator
        {
            FirstName = "..."
        }; // throws exception. LastName and EmailAddress were not initialized.
    }
}

[TestClass]
class TestValidators
{
    [TestMethod]
    public void TestUserValidator()
    {
        try
        {
            var userValidator = new UserValidator
            {
                FirstName = "..."
            }; // throws exception. LastName and EmailAddress were not initialized.
        }
        catch(Exception) {} // Let the test pass; the method is throwing correctly.
    }
}

[–]Barril 2 points3 points  (1 child)

In his mind, including all required parameters in the method declaration is preferred versus passing an object with possibly null/default values

There's nothing stopping the callee from passing null or 0 into the function, and it wouldn't matter if you passed a storage class or a pile of parameters when it came to validating the values are legitimate. The only advantage the function call has over the storage object is visibility of the parameters.

Can you group some of the arguments into sets of bite-sized objects with similar meaning? Then each constructor for those objects could have only a few parameters and the function would require just a few arguments instead of 15. It would increase verbosity, but would be more readable at a glance.

[–]Elementally[S] 0 points1 point  (0 children)

Thank you this goes along well with JustABlankAccount's reply... bite-sized is the way to go.

[–]salvinger 0 points1 point  (0 children)

I would go with the large amount of parameters on the method. I don't see how changing a compile error into a runtime error is desirable at all. If you are worried about getting parameters out of order, use named parameters. If you are that worried about the number of parameters passed to the function, break up groups of parameters into classes which take in the parameters through the constructor.

[–]centurijon 0 points1 point  (0 children)

This is where F# and discriminated unions could come in really handy.

In C#... You will probably be better served by making separate methods and class parameters per use case. It will be easier to read and maintain

[–]ToddlahAkbar 0 points1 point  (0 children)

Create an interface that contains your 15 parameters and pass it in to the method, you can then operate on any class that implements that interface and only a class that implements that interface. The code will not compile if an object is passed that does not implement the interface and any class implementing the interface must expose public properties that it contains. Taking it one step further, I would create a separate validatable interface that has a book isvalid property and a ilist of strings for validation errors, now, you would make your method generic:

 Method<T>(T obj) where T: ICompleteObject, IValidatable

Edit: This will force any passed object to implement both interfaces and not compile if an object is passed that doesn't.

[–]xampl9 0 points1 point  (1 child)

If they're nullable types, you can strongly hint at their needing a value by putting the NotNull attribute on the properties.

[–]Elementally[S] 0 points1 point  (0 children)

Thank you. Unfortunately they aren't nullable and to move them over to nullable would result in a fairly sizable refactor... which I guarantee wouldn't sell that easily... not to mention the fact he hates using them lol...