You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by "Jonathan Ellis (JIRA)" <ji...@apache.org> on 2010/01/29 21:26:34 UTC

[jira] Resolved: (CASSANDRA-741) Refactor for testability: Make class DatabaseDescriptor a real class with member methods, and non-static methods

     [ https://issues.apache.org/jira/browse/CASSANDRA-741?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Jonathan Ellis resolved CASSANDRA-741.
--------------------------------------

    Resolution: Won't Fix

No problem, if anyone else wants to pick it up and run with it, that's fine too.

> Refactor for testability: Make class DatabaseDescriptor a real class with member methods, and non-static methods
> ----------------------------------------------------------------------------------------------------------------
>
>                 Key: CASSANDRA-741
>                 URL: https://issues.apache.org/jira/browse/CASSANDRA-741
>             Project: Cassandra
>          Issue Type: Improvement
>          Components: Tools
>            Reporter: Ran Tavory
>            Priority: Minor
>
> I've stumbled across this issue when working on CASSANDRA-740 (Create InProcessCassandraServer for unit tests).
> I think the current way of how DatabaseDescriptor is implemented and used isn't great for testability perspective, readability and extensibility, here's why - 
> The class has a giant static{} block that initializes all it's static data members. This static block is hard wired to read a file named storage-config.xml form a system defined property path.
>  System.getProperty("storage-config") + File.separator + "storage-conf.xml";
> This isn't great for testing. What this means is that tests need to create the folder and put the file there (see scratch code inline the issue CASSANDRA-740). 
> Tests would rather be able to configure the class from an InputStream or something like that. However, the fact that the class initializes itself autonomously isn't helping - a driver of the class cannot tell it to initialize itself from a different input stream. dependency injection is a typical solution to these cases.
> If the class had a constructor that accepts an InputStream (and an empty one that acts at the default, reading the storage-config.xml from the file system) that would be nicer for tests.
> It would actually be nicer not only for tests, but also for readability and extensibility purposes - it would make all dependencies explicit (see more on this below) and it would be possible to extend the class by inheriting and overriding some of its methods (when everything is static it's impossible.)
> Here's a mockup of my suggestion:
> public class DatabaseDescriptor
> {
>   public DatabaseDescriptor() {
>     this(new FileInputStream(System.getProperty("storage-config") + File.separator + "storage-conf.xml");
>   }
>   public DatabaseDescriptor(InputStream input) {
>     // read xml from input
>   }
> ...
> }
> However, implementing what's suggested above, although the change is rather trivial, means changing all references to DatabaseDescriptor application wide... and there are more than 200 of those...
> It usually looks like this:
> public class RingCache
> {
>     final private int port_=DatabaseDescriptor.getThriftPort();
>     final private static IPartitioner partitioner_ = DatabaseDescriptor.getPartitioner();
> The above code would have to be changed to:
> public class RingCache
> {
>   final private int port_;
>   final private static IPartitioner partitioner_;
>   public RingCache(DatabaseDescriptor descriptor) {
>     port_ = descriptor.getThriftPort();
>     partitioner_ = descriptor.getPartitioner();
> This means making the RingCache depend *explicitly* on DatabaseDescriptor since it requires it in its constructor (and not implicitly, via a static method) so this is good for being able to test the RingCache in a unit test and is also great for readability - no hidden dependency loops.
> Actually, since the RingCache depends only on the thrift port and the partitioner, but not an the entire database descriptor, it'll make even more sense to pass only the two in the constructor. This would again make unit tests easier and code easier to understand (you don't have to wonder "what is it in the database descriptor that I need to have in order to make the RingCache work?")
> public class RingCache
> {
>   final private int port_;
>   final private static IPartitioner partitioner_;
>   public RingCache(int thriftPort, IPartitioner partitioner) {
>     port_ = thriftPort;
>     partitioner_ = partitioner;
> The suggested change is a code quality improvement and testability improvement and should not affect the logic of the app.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.