0

In the book Clean Code, Robert C. Martin says that we should avoid polyadic functions (functions that contain four or more arguments).

One of the solutions presented by him is the use of objects as parameters.

In some cases it is easy to identify arguments that can become or be grouped into an object. However, in other cases, this is not a simple task.

For example: Parameters being passed to a method in a DAO (Data Access Object) class, which will be used in an SQL script. They will only be used in that single location throughout the code. There is no other point in the code that will make use of these parameters.

I am currently considering these objects as a DTO (Data Transfer Object), but I have a feeling that this would not be the best classification for these objects.

I have this feeling, because in languages ​​like C# and Java, where basically each file is a class. Having a file with a DTO class, which will be passed as a method parameter, in a single location in the code, that sounds weird to me.

Is it correct to classify these objects as DTO? Or is there another more suitable nomenclature?

Is there any other solution for these cases of functions with parameters that will only be used in that function (to avoid having to keep creating files/classes that only serve to be passed as parameters)? Perhaps the use of dictionaries (key and value), would be feasible (Even if you lose all the autocomplete help from IDEs)?

5
  • "to avoid having to keep creating files/classes that only serve to be passed as parameters" - it's a matter of style, but there's really no need to avoid such classes. These classes are in essence part of the interface of the class that takes them as a parameter, and also a chance for you to explicitly name a concept. Also, if you're writing tests, you'll reuse them in a different setting in your test suite. BTW, C# doesn't require you to have a single class per file. Perfectly acceptable to group closely related classes together, and you can also create nested classes. – Filip Milovanović Feb 9 at 16:53
  • More generally, another thing to consider when you have a long parameter list is why your class/method needs all those parameters - maybe it's doing too much; maybe there's an elegant way to split it into two or three more focused objects that are easier to understand/manage, and can work together to achieve the same result. – Filip Milovanović Feb 9 at 16:56
  • IMO those objects are NOT DTO. They're parameter objects (personally I end the class names with "Param" but that's just me). In some cases you may find yourself passing both a DTO (the data) and a parameter object to a single method call (eg, making API call to Ebay and you need to pass both the product DTO and the request parameters) – slebetman Feb 19 at 7:10
  • I might at some point write a "real" answer if I get the time, but I have two points: You phrase this question as how to pass all this information to the function cleanly, but I think you should look at if it is the function itself that needs all this data because it is doing too much? But without a more concrete example, it's difficult to tell. Secondly, the type of object you are referring to, I would call a "Request Object". There are good uses for a such, but I normally only use them at the outer boundaries of the system. That didn't seem to be the case in your scenario. – Pete Feb 19 at 7:55
  • @Pete Showing the concrete example is complicated. Because what led me to write this question, is a function of a project that I'm working on. The function is receiving 12 parameters for printing a report. As it is a report, the function is very tied to the company's business rule, it would be necessary to have knowledge of the database tables to understand it. So I cannot expose this information. Talking to my supervisor, he told me to create a DTO, I did it the way he asked, but it kept hammering in my head. – Felipe Godinho Feb 20 at 22:34
0

In my opinion such rules should be treated as a recommendation and not a inflexible rule. If parameters have a good reason to be grouped they should be put into a class regardless of how many there are. I would not think grouping parameters just to avoid the 4-parameter limit is sufficient justification.

Examples

// Wrap parameter to make the unit unambiguous
Foo(Angle.FromDegree(45)); 

// This would not improve readability in my opinion
Bar( new BarParameters(1, 2, 3), new BarParameters2(4, 5, 6)); 

Another example could be the DrawRectangle methods. One overload just takes a pen and a rectangle: DrawRectangle(Pen, Rectangle). But there is also an overload that takes individual parameters DrawRectangle(Pen, Int32, Int32, Int32, Int32). I find that this works just fine, the pattern of x, y, width, height is sufficiently common that it should be fairly quickly recognized even by junior developers.

If you should call parameter objects for 'DTO' or not should depend your naming conventions. There is as far as I know no generally accepted naming convention for 'DTO', so the most important thing would be to be consistent in your own projects. I personally only use 'DTO'-label for types that need serializing, but that is just my own convention.

3

It's not a weird thing to have a class that is used only in one place to reduce a long parameter list, anymore than it's a bad thing to have a method that's called only once to cut down a lengthy caller method.

In both cases the point is to make the code more readable and self-explanatory than it would be if humans had to read through long argument lists or scroll through long method listings. Never judge your code base by thinking "But this is unnecessary, the computer could process it just as well as it is!" The point of good software engineering is to transform code into a form where it's equally well processable by computer, but better by human.

4
  • But would it be correct to classify these classes as DTO? – Felipe Godinho Feb 9 at 18:04
  • @FelipeGodinho: Does it transfer data? Is it an object? – Flater Feb 18 at 17:13
  • @Flater In a way, yes. Because it all depends on what is meant by "transferring data". If it means trafficking data over the network or something, then no. If it means just passing data from one place to another, then yes. – Felipe Godinho Feb 20 at 22:46
  • @FelipeGodinho: Right. So if it's an object that exists to transfer data (as the carrier), then it's a DTO. – Flater Feb 20 at 23:22
0

Well, replacing group of parameters with one specific object, which will be used only once just to reduce the number of parameters is not the best approach either. The point of having not more than 3-4 is not only about having better readable code, but more about having cleaner architecture. You can pass objects to your method, but objects should be meaningful and possibly could be reused somewhere else.

For example:

findUsers(name, email, phone) can be replaced with findUsers(contactDetails), contactDetails can be reused anywhere, even in the User class.

The point is to break down big things in smaller ones, so smaller pieces can be reused everywhere and they are less coupled with each other. Maybe your group of params can be replaced with 2 meaningful objects, which make sense and can be reused. Polyadic function is a flag which tells you that something is not perferct in your architecture, something is too big and doing too much. There is no universal solutions, pretty much depends on your particular case, so it's better to discuss having some real code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.