[RUBY] Is it easy for the user to use when implementing general-purpose functions? Let's be aware of

When writing a program, I think that you may cut out general-purpose functions into classes and methods and implement them.

For example, consider the process of having multiple specified users participate in a specific event.

First, check the implementation when all the processing is in one method. (I wrote it in Ruby, but if you have done other programming languages, you can get a feel for it.)

def main(user_ids, event_id)
  users = User.where(id: user_ids)
  event = Event.find(event_id)

  #Excludes participating users
  target_users = users.reject {|user| user.events.ids.include?(event.id) }

  #Participation in the event
  target_users.each do |user|
    #Participation in the event=>Add record to EventUser
    EventUser.create!(user: user, event: event)
  end
end

Let's cut out the event participation process as a method from the above. This time I added a method to the Event model.

def main(user_ids, event_id)
  users = User.where(id: user_ids)
  event = Event.find(event_id)

  #Excludes participating users
  target_users = users.reject {|user| user.events.ids.include?(event.id) }

  #Participation in the event
  event.join(target_users)
end

app/models/event.rb


def join(users)
  users.each do |user|
    #Participation in the event=>Add record to EventUser
    EventUser.create!(user: user, event: event)
  end
end

Now, if you want to execute the process of joining an event from somewhere else, you can call it with ʻevent.join (users)`.

However, this implementation method has some subtleties. That is, the caller must pass only the users who can participate, excluding the users who have already joined.

In the case of this example, it will be easier for the caller to do the following.

def main(user_ids, event_id)
  users = User.where(id: user_ids)
  event = Event.find(event_id)

  #Participation in the event
  #The caller doesn't have to worry if users have already joined. OK if you pass the user who can be the target
  event.join(users)
end

app/models/event.rb


def join(users)
  #Excludes participating users
  target_users = users.reject {|user| user.events.ids.include?(event.id) }

  target_users.each do |user|
    #Participation in the event=>Add record to EventUser
    EventUser.create!(user: user, event: event)
  end
end

If implemented in this way, the caller can pass the target user without worrying about whether it has joined or not.

If you explain in order like this time, it may seem natural to implement the third one, but in reality, you often see the one implemented in the second state.

This is because there is no sense of discomfort even if the method alone is said to be "a method that allows users to participate in events." The second generalized part is reprinted below. How about looking at this method alone?

app/models/event.rb


def join(users)
  users.each do |user|
    #Participation in the event=>Add record to EventUser
    EventUser.create!(user: user, event: event)
  end
end

Also, when you first create a generic method, you may have few (or only one) callers. In that case, it doesn't take much time to check at the caller or at the callee, so it's hard to feel the hassle of having to check everything at the caller.

And once implemented like this, when implementing the process of participating in the event in the same way, the existing part will be copied. In that case, the mechanics of "Because the existing one is like this" will work, and it will be taken for granted rather than annoying.

Summary

When implementing a general-purpose function, is it easy for the user to use? Let's be aware of. If the user has to consider various restrictions or there are processes that must be executed (processes excluding participants in this example), those processes can be incorporated into general-purpose functions. Let's consider whether it is possible.

Doing so will not only make it easier for users, but will also prevent bugs such as implementation omissions.

Also, if you want to make it for general purposes, it will be used. If it is difficult to use, there is a high possibility that only the person who implemented it can use it (the person who implemented it may not be able to use it after a few months) Let's keep in mind the implementation that is easy for users to use and enjoy! !!

Recommended Posts

Is it easy for the user to use when implementing general-purpose functions? Let's be aware of
[Java] [Microsoft] Things to be aware of when including the JDBC driver for SQL Server in one jar
When the hover of Eclipse is hard to see
Things to be aware of when using devise's lockable
When importing CSV with Rails, it was really easy to use the nkf command
[Java] Things to be aware of when outputting FizzBuzz
I want to be aware of the contents of variables!
It is difficult to use the empty string or date of DBUnit, so fix it and use it.
Session was a cookie designed to be erased when the browser was closed and was a method for exchanging it: Rails Tutorial Note-What is a Rails Session?
The story of making a binding for libui, a GUI library for Ruby that is easy to install
Countermeasures for forgetting to specify the font when titleTextAttributes is specified
Be aware that the default for Spring boot redirect is http
[For beginners] Ruby is said to be ruby, but what about it?
An example of a small work when you want to divide the definition value according to the environment but do not want to be aware of it
Let's write a code that is easy to maintain (Part 2) Name
Write code that is easy to maintain (Part 1)
Write code that is easy to maintain (Part 4)
Write code that is easy to maintain (Part 3)
Write code that is difficult to test
Function is very easy to use
Think of test code that is easy to understand through Comparator testing
Code that is difficult to debug and parse
How to write code that thinks object-oriented Ruby
Use stream to verify that SimpleDateFormat is thread unsafe
Java 14 new features that could be used to write code
[Java] Code that is hard to notice but terribly slow
Is it easy for the user to use when implementing general-purpose functions? Let's be aware of
How to write good code
Easy to use array.map (&: method)
How to identify the path that is easy to make a mistake
Function is very easy to use
[RSpec] When you want to use the instance variable of the controller in the test [assigns is not recommended]
To be aware of easy-to-read code
Incident (rails) that is logged out when user editing of the application
Get the type of an array element to determine if it is an array
I want you to use Enum # name () for the Key of SharedPreference
Is it possible to put the library (aar) in the Android library (aar) and use it?
In the topic of "total concentration", "How to use Docker" is summarized for the virtual Mameko who sleeps in me.
Since the du command used when the capacity is full is difficult to use, I tried wrapping it with ruby
[Java] When checking URL format with Bean Validation, it may be better not to use @URL of Hibernate Validator.
[swift] How to control the behavior when the back button of NavigationBar is pressed
Summarize the life cycle of Java objects to be aware of in Android development
[Ruby] Meaning of &. How to avoid the error when the receiver (object) is nil
[Java] Is it unnecessary to check "identity" in the implementation of the equals () method?
Is it mainstream not to write the closing tag of <P> tag in Javadoc?
[Java] When putting a character string in the case of a switch statement, it is necessary to make it a constant expression
[Swift] If the support of the application is iOS 11 or later, it was not necessary to use Int and Int64 properly