Question

I am so obsessively OC at dividing a class or instance method and move it in its own class, and many times a simple "hello world" method will be divided into many classes.

like for example,

class MainProgram
  def hello_world
    puts "hello world"
  end
end

will be divided to

class SayHello
  def initialize
    @hello = "hello"
  end

  def hello
    @hello
  end
end

class SayWorld
  def initialize
    @world = "world"
  end

  def world
    @world
  end
end

class SayHelloWorld
  def initialize
    @hello = SayHello.new.hello
    @world = SayWorld.new.world
    @hello_world = "#{@hello} #{@world}"
  end

  def hello_world
    @hello_world
  end
end

class MainProgram
  def hello_world
    @hello_world = SayHelloWorld.new.hello_world
    @hello_world
  end
end

And sometimes it feels unnecessary. Is doing it this way any good at all?

When do I stop refactoring my code? Is there such thing as a refactored code?

Was it helpful?

Solution

"Refactoring mode" should only be enabled when you see code duplication for code that is complex enough (or contains business logic) that it might cause problems later down the line for doing maintenance/updates; such that it would create the scenario where you might forget to update all code locations that are otherwise meant to be identical in function, resulting in inconsistent behaviour of functionality depending on code-path.

One common rule is that once you see 3 duplications of non-trivial code, you should refactor it.

Refactoring enables re-usability, but its not exactly the same as making reusable software components (which I think is your motivation).

What you are doing is over-engineering your software and are basically reducing your programming language's otherwise powerful and succinct syntax into a much simpler, more brittle and less expressive one. This is because you are creating too many abstraction layers and encapsulating basic expressions into classes.

One useful question you should ask yourself is "What benefit do I get from turning this series of expression into a class?" e.g. "Do I need to track state?", "Do multiple instances make sense?", and "Do I gain or lose expressiveness? flexibility? convenience?".

Another way of looking at it is that refactoring is often motivated by DRY (Dont Repeat Yourself), keeping in mind that DRY is not exactly the same as wanting to create reusable software components. However, there is also YAGNI (You Aint Gonna Need It): unless you need a certain functionality in the immediate future, you probably dont need to implement it now, just stick to the most basic version that works (at least to start off with).

Dont speculate way off into the future thinking "I want to leave all options open for later on; what if I decide to do A, what if I decide to do B, yes, yes, I'm gonna turn this simple thing into a class that lets you also do f, g and h, just in case later on I decide I need it...!".

So a lot of this is related to getting your software requirements and scope at a fairly stable level of finalisation before you start writing the relevant code. Knowing where the road stops helps you to estimate how much fuel you need, how to pace yourself properly, and apply resources proportionately to where they are needed most.

Also, If you are new to programming and learning a language, you will be more likely to feel the need to shoehorn every language feature in your program even if you dont need it. As you start writing more complex, real world programs (well beyond hello world), you will get a feel for when to use what.

Becoming aware of software antipatterns is one of the best ways to speed up this process. You are currently doing a form of "Cargo Cult Programming"

OTHER TIPS

It all depends on what remains invariant, and what changes. If you need to print the same string "Hello World" all the time, you do not need all the complications. If you think you want to change the string once in a while but not as often as every time you run it, then you might want to keep the string as a constant, and refer to that constant. If you want the output to vary according to the user input in the form "Hello world", "Hello Mars", "Hello Moon", etc., then you can have the "Hello" part hard wired and have a routine for user input for the varying part. etc.

Intuitively, everybody knows how to write a "Hello world" program:

puts "Hello world!"

So why bother OOP-ing around? The answer is, for the future. If you just want to say hello world now and never do it again in your programming career, as is the normal case, then just write the oneliner. The question when to stop refactoring depends on the projected future use of your current programming effort. For example, if you are programming a website, that is supposed to be multilingual in future, you will do something like this:

class Greeter
  GREETINGS = {
    en: "hello",
    ru: "привет",
    cn: "你好"
  }

  TARGET = {
    en: "world",
    ru: "мир",
    cn: "天地"
  }

  def do_your_grim_business( language )
    puts [ GREETINGS[ language ], TARGET[ language ] ].join( ", " ) + "!"
  end
  alias :act :do_your_grim_business
end

timothy = Greeter.new
timothy.act( :en )

That will enable your mind to grow, to expand to the bright future. But don't overdo it, because as those who've made the mistake say, Ruby is Play-Doh.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top