D.S

langrsoft.com

single responsibility principle – Langr Software Solutions

single responsibility principle – Langr Software Solutions single responsibility principle – Langr Software Solutions Consulting and Training for Software Teams Learning Great Practices From Constraints The Maryland high school I attended helped me get my early career off the ground. In 1980, I took my first computer class. A friend and his geek cohorts had already learned enough to swarm all over the HP/3000 machine we used. They quickly knew more about it than the operator hired by the school. I learned that our machine and the terminals (HP-2640A’s, I believe) had been donated to the school. But before giving up the terminals, the donor cracked them open and removed some of the terminal memory, no doubt to help beef up the terminals for their newer system. The terminal memory allowed you to scroll back: by default, you got one page at a time (25×80, or maybe 24×80 to accommodate the f-keys line at the bottom). Later, when I started working at the University of Maryland–a job I got mostly because of my high school experience with the HP/3000–I had a wondrously souped-up terminal that allowed me to scroll back a whopping ten or so pages! For whatever dumb reason, however, it was possible to remove even some of the first screen’s worth of memory. So instead of a 25×80 display, we effectively had a 17×80 display. You’d see 17 lines of output, followed out by a functionally-dead and black bottom third of the screen. The effect this constraint had on editing programs was overwhelming. We used a line editor (TDP/3000 was the nicer one that HP offered), which meant you had to explicitly tell the editor to display certain lines when you wanted to view them. It went something like: > list 34-49 … 16 lines of code displayed here … > The list command itself could scroll off the screen, but you still had a new command prompt taking up one more line, effectively leaving us with 16 lines maximum of code that I could see on-screen at any given time. I got very good at figuring out n:n+15. The result: I learned very early on to compose my programs so that many, if not most, of my functions were short–no more than 16 lines! Otherwise, I’d spend far too much time listing lines appearing earlier or later in a function (to emulate scrolling up and down). This habit became a key part of the successful parts of my programming career. My programs were usually structured to be very easy to maintain, and I never had lots of problems with pinpointing and fixing defects. Creating short methods is a great practice that I still find value in today. Easier Testing Using the SRP This simple file monitor class notifies listeners when a watched file is modified: public class FileMonitor { private Set<FileChangeListener> listeners = new HashSet<FileChangeListener>(); private int duration; private File file; private long lastModified; public FileMonitor(String filename, int duration) { this.file = new File(filename); lastModified = file.lastModified(); this.duration = duration; } public void start() { boolean isDaemon = true; long initialDelay = duration; new Timer(isDaemon).schedule( new FileMonitorTask(), initialDelay, duration); } public void addListener(FileChangeListener listener) { listeners.add(listener); } class FileMonitorTask extends TimerTask { @Override public void run() { if (file.lastModified() > lastModified) { lastModified = file.lastModified(); for (FileChangeListener listener: listeners) { listener.modified(); } } } } } A FileMonitor schedules a TimerTask that just checks the modified date from time to time, and compares it to the last modified date. The code above seems like a typical and reasonable implementation. FileMonitorTask could be an anonymous inner class, of course. I spent more time than I would have preferred test-driving this solution, since I made the mistake of test-driving it as a single unit. These tests had to deal with the vagaries of threading due to the Timer scheduling. import java.io.*; import java.util.*; import org.junit.*; import static org.junit.Assert.*; public class FileMonitorTest { private static final String FILENAME = "FileMonitorTest.properties"; private static final int MONITOR_DURATION = 1; private static final int TIMEOUT = 50; private FileMonitor monitor; private File file; private List<FileChangeListener> fileChangeNotifications; private Thread waitThread; @Before public void initializeListenerCounter() { fileChangeNotifications = new ArrayList<FileChangeListener>(); } @Before public void createFileAndMonitor() throws IOException { FileUtils.writeFile(FILENAME, "property=originalValue"); file = new File(FILENAME); monitor = new FileMonitor(FILENAME, MONITOR_DURATION); } @After public void deleteFile() { FileUtils.deleteIfExists(FILENAME); } @Test public void shouldNotifyWhenFileModified() throws Exception { monitor.addListener(createCountingFileChange