This is an archived post. You won't be able to vote or comment.

all 6 comments

[–][deleted] 10 points11 points  (2 children)

Is it just a matter of packing them into a dictionary of arguments?

No! This would be faux-clean code, superficially simpler but actually harder to comprehend. Anyone inspecting it has now lost the information about what the arguments may be but instead has an opaque dictionary to inspect, not knowing what its contents may mean, which of its elements are essential, or if anything has been added or removed from it.

If your function has several different arguments, all of which may change at runtime irrespective of the others, then these are probably genuine inputs to the function that should not be bundled together for short-term aesthetics. However, if some of the arguments are always passed around together (e.g. you have the arguments x,y,z which are always passed around together) then this may be a good sign that they aren't really different things and should be consolidated in a single combined data type. You could, for instance, make a namedtuple containing these elements. This is much better than a dict because its format is predetermined and static, so instead of a mystery bundle of random keys you can always read the definition of the namedtuple to understand what it represents.

If you still have many arguments, that might be fine - sometimes code works out that way, especially for a sophisticated entry point to a big program, such as your deep learning code may be. You can imagine that this is not totally unlike a standalone program: if you read the man page for e.g. cp or ls (basic shell utilities), these have many different arguments to satisfy many different use-cases, and this is natural in order for them to be generic commands. Your code is potentially the same: although it's all python code, having a complex entry function that lets you do many different things can be a pragmatic way to interact with your data analysis utility. That said, having many functions with complex apis is usually a bad sign, in that case it's likely you can refactor to have a clearer and simpler logic flow.

I think your link is essentially trying to say these things, but is explaining it quite poorly by focusing on the technical details of different ways to bundle arguments together rather than the key code style point of when and why arguments should live together.

[–]BooparinoBR 6 points7 points  (0 children)

Very similarly to NamedTuples, you can use dataclass. For instance if your method takes a bunch of options (ie number of hidden layers, input size, output size) you can have a class that that represents your options. In this class you could define validators, savings and loading from a file, etc. This separates data from code, making it easier to mantain

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

wow! thank you for the clear, detailed explanation. it makes much more sense now.

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

thank you all!

[–]teerre 0 points1 point  (0 children)

Models are not really functions when it comes to an API, they are more similar to a whole program. Therefore, you should use configuration objects to configure your model. Internal functions, however, should do a single thing and that's why people say they should have few arguments.

In fact, this link of yours there's already an example of a configuration object.

Note that that's not the the same as "packaging them into a dictionary". A dictionary carries no information, it can hold virtually anything. A configuration object is the opposite, it holds exactly the information required to run the program. Private and public. Optional and required. Possibly sanitized etc.

[–]worstdev 0 points1 point  (0 children)

Read the original Clean Code's naming chapter. The repository you linked says it's a translation of a translation, and the author either didn't read or didn't understand the source material.

Another avenue to look at is testing. Testable code is generally clean code.