How do you remove functionality from a program in ruby? - ruby

You have some code you want to remove associated with an obsolete piece of functionality from a ruby project. How do ensure that you get rid of all of the code?
Some guidelines that usually help in refactoring ruby apply, but there are added challenges because having code that isn't being called by anything won't break any unit tests.
Update: Has anyone written anything that allows you to guess based on your version control history if there are commits where you have since deleted most, but not all, of the code and can point out the remaining code?

Current thoughts:
Identify the outermost part of the stack associated with the obsolete functionality: the binary script calling it, or the unit tests calling it.
Look for methods that are only called by methods associated with the obsolete functionality. I often use git grep for this.
In theory, running mutation testing and looking for code that used to be mutation resistant when the old test suite applied, but is now mutation prone might help. It only helps if your code was well-tested in the first place! (Or you can use code coverage tools such as rcov rather than mutation testing)
Running test suites will ensure you haven't removed anything you shouldn't have!
Using autotest can save you time if you're constantly running tests.
If your code was well-structured, it should be easier to find related methods that need to be removed.

Especially in a dynamically typed language, there is no easy way to do this. If you have unittests, thank the developer that wrote them because it will help you remove the code correctly. But you're basically SOL. Remove the code, if it breaks, put it back, figure out where it broke, attempt to work around it, and repeat.

Look at your code coverage. Any code which isn't covered may be part of the code you have left to remove (if any). (Just be sure you have removed you tests. =])

Related

Questions about setting up a working Guard-RSpec example project

I'm trying to set up a working ruby project with guard-rspec.
I've mixed together the general method of a tutsplus tutorial with some new syntax as described in the RSpec videos and another post. The project can be found in the stack-overflow-question branch on github.
I'm also trying to practice namespacing as described in Programming Ruby 1.9. So eventually I'd like to have example.rb in my lib/example/ directory.
There's 4 questions I have about my project:
What do I need to put in my Guardfile to watch specific directories in my project for changes? I've several different ways which can be seen in my Guardfile as comments labelled like:
# Watch Specific Directory Attempt X
What is the difference between uncommenting lines 8 and 9 in my Guardfile (bellow Uncomment and set this to only include directories you want to watch) and adding "named group captures" like watch(%r{^lib/(?<path>.+)\.rb$}) { |m| "spec/lib/#{m[:path]}_spec.rb" } as described here
Where do I need to put the --clear option to make it persistent? I know I can run it with my binstub like bin/guard --clear and I've tried putting that in my Guardfile however it didn't work.
Are there any glaring convention, syntax, or clarity mistakes that you see in my project? I feel like I'm duck taping this whole thing together and I'd appreciate some guidance in piecing this thing together in a sensible way.
I'll answer the question in the title and cover the "sub-questions" as I go.
The best way to set up a project (as of now) is to use bundle exec guard --init rspec. This should give reasonable defaults to start work immediately. It's not perfect, but there is a lot of work planed to improve things, so do ask questions on GitHub instead (makes more sense).
Guard has to maintain backward compatibility, so there are some "non-intuitive" things for now and skimming through all the docs first (and wiki) is a good investment to quickly know what's available and where. Asking when confused or in doubt is also a good idea (one issue per question is best).
Guard uses a DSL to simplify setting up listeners. This is a bit non-intuitive and clunky at times, but it does help organize actions into groups, which can help maintain complex workflows. The DSL's command for e.g. clearing the terminal automatically is: (clearing: on). (This answers question 3).
There are all kinds of uses and scenarios, so Guard tries hard to make everyone happy and on every platform too. Guard uses Listen, which watches directories recursively (due to restrictions on OSX mostly). This usually isn't a problem, but for huge directions on OSX this can be very, very slow. That's why Guard lets you select which top directories to watch (like 'lib', 'app', etc.). Watching the whole project directory is very convenient, so that is still the default. More info on this is at the Listen project. So by default all directories (:directories statement) are "physically watched" (take up operating resources), though in Guard you only configure which changes you want to respond to (which is what watch statements do).
The words chosen are a bit misleading at times. E.g. watch in the DSL actually means: "out of all the changes happening, select changes matching ...". The block passed to watch is given the results of the match. That block should return a list of files for the current guard plugin to run. So "watch" probably is more misleading than helpful. "match" would probably be a better choice and it might replace "watch" in the future.
The guard-rspec project runs RSpec on changed files. You can see the exact RSpec commands if you run guard with the debugging option on, e.g. bundle exec guard -d. To simplify setup, Guard::RSpec uses a DSL that should work out-of-the-box if your project follows a given setup. E.g. dsl.watch_spec_files_for(ruby.lib_files) is defined here: so it pretty much already should do what you want if you put all your tested source files in lib. For other folders, you can add your own. E.g. Rails projects typically have sources also in an app directory, so in the default Guard::RSpec template there's an statement: dsl.watch_spec_files_for(rails.app_files) with the pattern defined as: rails.app_files = %r{^app/(.+)\.rb$} If you have a typical case that isn't covered, open an issue in that project. (covers question 2).
Everything looks fine in the example project and suggestions are mostly based on taste or preference. E.g.
Instead of let (:greeter) { Example::RSpecGreeter.new }, I'd use RSpec's implicit subject (but some may argue that it's less explicit and less readable)
if you're testing Example::RSpecGreeter, I'd recommend putting that class in a separate file and including it instead (require 'example/rspec_greeter')
you might add RubCop/Guard::RuboCop for detecting convention issues (covers 4th question)
you might want to check out Guard's own Guardfile used to test itself for a more "real-life" setup without the documentation clutter.
for best results I think it's best to copy a whole existing project and rename the parts you want to change. Usually there are many hours spent still fine-tuning things like alternate RSpec configs for Travis, special gem release tasks, certain workarounds and conveniences, etc.

Am I allowed to check in a failing test [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
Our team is having a heated debate as to whether we allow failing unit tests to be checked-in to source control.
On one side the argument is that yes you can as long as it is temporary - to be resolved within the current sprint. Some say even that in the case of bugs that may not be corrected within the current sprint we can check-in a corresponding failing test.
The other side of the argument is that those tests, if they are checked-in must be marked with the Ignore attribute - the reasoning being that the nightly build should not serve as a TODO list for a developer.
The problem with Ignore attribute however is that we tend to forget about the tests.
Does the community have any advice for us ?
We are a team of 8 developers, with a nightly build. Personally I am trying to practice TDD but the team tends to write unit tests after the code is written
I'd say not only should you not check in new failing tests, you should disable your "10 or so long-term failing tests". Better to fix them, of course, but between having a failing build every night and having every included test passing (with some excluded) - you're better off green. As things stand now, when you change something that causes a new failure in your existing suite of tests, you're pretty likely to miss it.
Disable the failing tests and enter a ticket for each of them; that way you'll get to it. You'll feel a lot better about your automated build system, too.
I discussed this with a friend and our first comment was a recent geek&poke :) (attached)
To be more specific - all tests should be written before (sa long as it's supposed to be TDD) but those checking an unimplemented functionality should have their value prepended with negation. If it's not implemented - it shouldn't work. [If it works - the test is bad] After implementing a test you remove the ! and it works [or fails, but then it's there to do so :) ].
You shouldn't think that tests are something written once and always right. Tests can have bugs too. So editing a test should be normal.
I'd say that checking in (known) failing tests should of course be only temporary, if at all. If the build is always failing, it loses its meaning (we've been there and that's not pretty).
I guess it would be ok to check in failing tests if you found a bug and could reproduce it quickly with a test, but the offending code is not "yours" and you don't have the time/responsibility to get into it enough to fix the code. Then give a ticket to someone who knows his way around and point to the test.
Otherwise I'd say use your ticket system as a TODO list, not the build.
It depends how you use tests. In my group, running tests is what you do before a commit in order to check that you (likely) have not broken anything.
When you are about to commit, it is painful to find failed tests that seem vaguely possibly related to your changes but still strange, investigate for a couple of hours, then realize it cannot possibly be because of your changes, do a clean checkout, compile, and find that indeed the test failures come from the trunk.
Obviously you do not use tests in the same way, otherwise you wouldn't even be asking.
If you were using a DVCS (e.g., git) this wouldn't be an issue as you'd commit the failing test to your local repository, make it work, and then push the whole lot (test and fix) back to the team's master repository. Job done, everyone happy.
As it seems you can't do that, the best you can do is to first make sure that the test is written and fails in your sandbox, and then fix that before committing. This might or might not be great TDD, but it's a reasonable compromise with the working practices of everyone else; working with your co-workers is more important than following some ivory tower principle in every aspect, since the author of the principle isn't located in the cubicle next door…
The purpose of your nightly build is to give you confidence that the code written the day before hasn't broken anything. If tests are often failing then you can't have that confidence.
You should first fix any failing tests you can and delete or comment out/ignore the other failing ones. Every nightly build should be green. If its not then there is a problem and that's immediately obvious now since it should have run green.
Secondly, you should never check in failing tests. You should never knowingly break the build. Ever. It causes unnecessary noise, distractions and lowers confidence. It also creates an atmosphere of laziness around quality and discipline. With respect to ignored tests which are checked in, these should be caught and addressed in your code reviews, which should be covering you test code as well.
If people want to write their code first and tests later, this is OK (though I prefer TDD), but only tested code which runs green should be checked in.
Finally, I would recommend changing the nightly build to a continuous integration build (run on each code check in) which might just change people's habits around code check-in.
I can see that you have a number of problems.
1) You are writing failing tests.
This is great! However, someone is intending to check those in "to be fixed within the current sprint". This tells me that it's taking too long to make those unit tests pass. Either the tests are covering more than one or two aspects of behaviour, or your underlying code is far too complex. Refactor the code to break it up and use mocks to separate the responsibilities of the class under test from its collaborators.
2) You tend to forget about tests with [Ignore] attributes.
If you're delivering code that people care about, either it works, or it has bugs which require the behaviour of the system to be changed. If your unit tests describe that behaviour but the behaviour doesn't work yet, then you won't forget because someone will have registered a bug. However, see point 1).
3) Your team is writing tests after the code is written.
This is fairly common for teams learning TDD. They might find it easier if they thought of the tests not as tests to check if their code is broken, but examples of how another developer might want to use their code, with a description of the value that their code provides. Perhaps you could pair with them and help them learn from what they already know about writing tests afterwards?
4) You're trying to practice TDD.
Do or do not. There is no try. Write a test first, or don't. Learning never stops even when you think you're doing TDD well.

Is it bad practice to leave commented-out code in production releases

I regularly see production code from developers (large companies and individuals) that contains code that has been commented out. Presumably this removes earlier attempts at achieving the functionality that didn't work for some reason.
To my mind, this is messy, but potentially has some benefits e.g. on returning to refactor or extend the code, the developer can see what has been tried previously.
Are there any security or best-practice aspects to this?
Best practice is to use SCM. If you think the old code is really something people will want to refer to in the future, leave a comment of "// We used to do it another way, which had interesting property X -- see revision 103" rather than leaving whole chunks of code that don't do anything.
Commenting out code has its place, but that place is quickie tests that aren't even worth the time to do a branch.
If the code is worth keeping, it's worth more than being lost in a comment somewhere. If it is not worth keeping, kill it with fire.
Code should be stored in source control.
Comments should be reserved to explain difficult to understand code or the reason for doing something out of the ordinary.
Best practice is that your code shows only the current. You should be using an SCM that deals with code history.

How can I find unused methods in a Ruby app?

I have a Ruby app with a lot of classes/modules, and some of them are not used. Is there an easy way of finding out which?
I was thinking to do a profile, and then work with it's output. Any other ideas?
A coverage tool, like rcov might help.
https://github.com/relevance/rcov
As you find methods that are not covered by tests, you should write tests for them or find out if they are used at all.
Removing unused methods is part of refactoring, if you have too many classes that can be a code smell that needs refactored also.
You can put raise (or raise Exception if you don't want it caught) to the start of the suspect method. If nothing breaks, then it might not be in use (either that, or something's catching the exceptions).

What is the ruby test tool called that 'breaks' your code to see how tight your tests are?

A wee while ago I ended up on a page which hosted several ruby tools, which had 'crazy' names like 'mangler' or 'executor' or something. The tool's job was to modify you production code (at runtime) in order to prove that your tests were precise.
Unfortunately I would now like to find that tool again, but can't remember what it was called. Any ideas?
I think you're thinking about Heckle, which flips your code to make sure your tests are accurate. Here:
http://seattlerb.rubyforge.org/heckle/
Maybe you're thinking of the Flay project and related modules:
http://ruby.sadi.st/Ruby_Sadist.html
Also you can try my mutant. Its AST based and currently runs under MRI and RBX in > 2.0 mode. It only has a killer for rspec3, but others are possible also.

Resources