Single Responsibility Principle in Security Scripts

The Single Responsibility Principle (SRP) says a function or module should have one reason to change — it should do one thing, and do it well. In security scripting, this means breaking a script into small, focused functions rather than one long block of code.

Why It Matters for Security Work

Security scripts often evolve quickly. You might start by parsing IPs, then add hash extraction, then add reporting, then add command-line arguments. If everything is in one block, it becomes fragile.

Small functions make it easier to:

  • Test — each function can be checked independently
  • Debug — find which regex or parsing step is wrong
  • Reuse — use extract_ips() in another script later
  • Review — a teammate can read and verify one logical step at a time

A Bad Example

One function reads, parses, counts, and reports everything:

def analyze_logs(path):
    with open(path) as f:
        data = f.read()
    ips = re.findall(r"\d+\.\d+\.\d+\.\d+", data)
    counts = Counter(ips)
    for ip, count in counts.most_common(5):
        print(f"{ip}: {count}")

This works, but it is hard to extend. If you later want to extract hashes or paths, you modify the same function.

A Better Example

Each step is its own function:

def read_log(path):
    with open(path, "r", encoding="utf-8") as f:
        return f.read()

def extract_ips(text):
    return re.findall(r"\b(?:\d{1,3}\.){3}\d{1,3}\b", text)

def top_items(items, n=5):
    return Counter(items).most_common(n)

def main():
    text = read_log("access.log")
    ips = extract_ips(text)
    for ip, count in top_items(ips):
        print(f"{ip}: {count}")

Now extract_ips() could be reused in another script, and top_items() works for any list of strings.

Guidelines for Applying SRP

  • Name functions by what they do, not by where they are used. extract_ips(text) is better than do_log_stuff().
  • Return values, do not print inside functions. Let the caller decide what to do with the output.
  • Keep functions short enough to read at once. If you need to scroll, it may be doing too much.
  • Group related steps in main(). main() is the coordinator, not the worker.
  • Separate parsing from file I/O and output. Parsing should work on a string, not depend on a file.

When to Break It

SRP is a guideline, not a rule. For very small scripts, a few extra lines in one function is fine. But as soon as a script is shared, reused, or handles attacker-controlled data, the cost of a messy function grows fast.