2

I have a Python project where I have a few classes that model various thing I'm considering (e.g., a car class, a driver class and a street class) and then I have a single helper function that does a simple, low-level operation, that I use in some classes.

Is it considered good practice to put this function in a separate module? It seems unsatisfying to create a module that contains just one function, yet leaving it in the main file also is unsatisfying, since it clutters the code.

Please notice that I'm more of a beginner, having <1 year of experience.

2
  • 3
    In the software engineering world, we call those "helper" classes or methods, not "plumbing." There are many questions on the topic of helper classes already asked here. I recommend reading through those search results and coming up with a plan. Then if you still have a question that is not already answered here, ask that question. This question is likely a duplicate of something in the search query I linked here.
    – user22815
    Jan 13, 2018 at 7:43
  • @Snowman I edited my question accordingly
    – l7ll7
    Jan 13, 2018 at 10:27

1 Answer 1

2

The original version of this question specified "lists" as the target of the operation of helper methods. That is a very critical fact here, but I will cover two scenarios.

The first scenario is one where you have a generic operation that you perform on an object of a class you wrote. That absolutely should be part of the class. Sometimes it is difficult to fit it into an existing class: object-oriented design can be difficult at times, for sure. If you are debating putting such a utility function in a separate module because you are not sure where it fits, that may be an indication (some people call it a "code smell") that the design of your class or module is not ideal. I would like to point you to an answer I wrote for a different question that covers one aspect of refactoring code to remove temporal coupling (call method A before method B). Sometimes when a module does too much it can be difficult to reason about it and understand where methods go and how to use them together. It may help to break it up into pieces. That can make the answer to your question more clear.

The second scenario is an unfortunate one. Let us say you need a new general-purpose list operation, where "list" is a class provided by your language's core framework and said framework is not modifiable by you (typically the case, but not always). There really is no best solution here. Long story short, the software community long ago came to a consensus that the least bad option is to create classes with static methods that manipulate the core data structures. If you look at Apache Commons, for example, there are StringUtils and CollectionUtils classes where each class has utility methods for a single core Java class. Each utils class corresponds to a single core Java class, containing utility methods someone found useful when working with it but the Java interface and implementations lacked the necessary functionality.

One option you might consider is decorating an object if you need to alter its behavior. For example, let us assume you have an unsorted list of integers. However, you want to iterate the list in ascending order defined by the integers' natural ordering (i.e. the way we count up). Rather than modifying the list, you could wrap or decorate the object. Most of the methods simply pass through to the underlying list, however, methods used for iteration alter their behavior. Then when you want to iterate in a different order, you wrap the list in this new object and call whatever method your language uses to get an iterator.

There are options here, and there is not necessarily a "right" or "wrong" answer. There is no "best practice." Being relatively new to the profession, your takeaway should be that software design is an inherently complex process involving tradeoffs. You need to decide which positive and negative tradeoffs are acceptable for the program you are writing. We (here on this site) can help you identify options and maybe even pare some of them down, but ultimately, it is your call how to proceed.

3
  • Could the person who downvoted please explain why? To me, as a beginner, this answer looks sensible and provided a lot of good background info, so I'm giving a very well deserved +1! Nonetheless @Snowman, just to confirm, regarding from my two options -leaving my single helper function in my code as a separate function, vs. outsourcing it into a module- you're saying there is no general best practice, right?
    – l7ll7
    Jan 14, 2018 at 7:18
  • Could be please confirm? Then I can accept the answer.
    – l7ll7
    Jan 20, 2018 at 8:39
  • 3
    @user10324 you can accept or not, upvote, downvote, flag, whatever you feel is appropriate in isolation from any actions other users take.
    – user22815
    Jan 22, 2018 at 3:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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