2

I am writing some python 3 bioinformatics software and was wondering about the best way to write it in an OOP format. I am pretty sure a lot of my classes are violating the SRP principle, but I'm not entirely sure of how to refactor them (partly because they are quite small).

For example, I have a ProcessedInput class for processing a user input and standardising it for downstream analysis. Presumably this violates the SRP as it would need changes if any of the processing steps needed to change. However, as each step is just a single function, I'm not sure it makes sense to make each one it's own class (FileReader, FileScraper, etc). I could pull the methods out into functions and make a standalone function with whats currently contained in the innit method, but I like having all the functions in the same class as they're all related.

I've used this somewhat procedural class setup in a few classes, so I'd be interested in knowing if it's bad practice. Perhaps it's best to make smaller defined classes - or maybe that's too much abstraction that overly complicates the code?

Thanks! Tim

class ProcessedInput:
    def __init__(self, filepath, accession, ignore_pseudo, target_regions):
        if filepath != None and accession == None:
            self.records = self.read_genbank(filepath)
        elif filepath == None and accession != None:
            self.records = self.scrape_genbank(5, accession)
        else:
            raise ValueError(f'Input not recognised - either filepath ({filepath}) or accession ({accession}) must be None')
        self.accession = accession
        self.filepath = filepath
        self.proteins = self.collect_proteins(self.records, 
                                              ignore_pseudo)
        if target_regions != None:
            self.user_specified_proteins = self.filter_proteins(self.proteins, 
                                                                target_regions)
        else:
            self.user_specified_proteins = self.proteins
        self.record_flags = self.find_flag(self.user_specified_proteins, 
                                           flags = ['locus_tag', 'protein_id'])
        
    def read_genbank_file(self, path):
        #read path to file object
        return file
    def scrape_genbank_file(self, number_of_attempts, accession):
        #scrape file from public database, handle scrape fail with exception
        #read scraped response to file object (same as read_file output)
        return file
    def collect_proteins(self, file, ignore_pseudo):
        #parse file to get proteins of interest for downstream processing - ignore pseudo proteins if desired
        return proteins
    def filter_proteins(self, proteins, target_regions):
        #filter collected proteins to those in specific region of query (e.g. first half of genome) 
        return filtered_proteins
    def find_flag(self, proteins, flags_to_test):
        #each protein is associated with metadata, and I need to pick a 
        #persistent id from that metadata to use as a general protein identifier.
        #This tests each flag in flags_to_test to confirm the flag is a field in 
        #every protein's metadata, and all values associated with the flag are unique
        return flags

1 Answer 1

8

If you are sure that you are violating the SRP, what actual problems does that cause you?

Years ago someone analysed common problems and found root causes. With the SRP, the problem is not that a class has multiple responsibilities, the problem is that a single class becomes too big and complicated (because of multiple responsibilities). But SRP violation itself is not the problem.

If you have a class that becomes so big and complicated that it’s a problem, you can have a look at the reasons why it is so big. If you find “the class is so big because it has two responsibilities and I could easily split it into two simpler classes with one responsibility each” then go ahead and split it. If it had five trivial responsibilities and is easily capable of handling them, leave it. If the two responsibilities are so intertwined that splitting it creates two classes of almost the same size, then SRP will not help you.

And you can look at a bigger picture. If a class has responsibilities to make coffee, make tea, make toast, boil eggs, fry eggs and half a dozen more, maybe it has a single responsibility to make breakfast? Look at people around you, nobody has only one responsibility.

1
  • 1
    I wish I could up-vote this answer more than once. The last paragraph really frames the problem. Commented May 16 at 12:14

Your Answer

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

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