I have a function that was written because several methods used the same sequence of code so an abstraction was useful. The function takes a string representing the path to a registry key and then a list of 3-tuple containing attributes to update the key.
This function is subsequently called updateKeyAttributes
:
_ROOT_MASK = {HKEY_CLASSES_ROOT: 'HKEY_CLASSES_ROOT',
HKEY_CURRENT_USER: 'HKEY_CURRENT_USER'}
def updateKeyAttributes(hiveroot: HKType, key: str, attrs: Sequence[Tuple[Optional[str], int, Optional[Any]]) -> None:
try:
with CreateKeyEx(hiveroot, key, 0, KEY_WRITE) as open_key:
for name, typ, value in attrs:
SetValueEx(open_key, name, 0, typ, val)
except OSError as err:
path = f'{_ROOT_MASK[hiveroot]\\{key}'
raise RegistryError(f'Failed to update key attributes: {path}') from err
As I was looking at this function, I started to wonder if it is violating the SRP?
To me, its responsibility is to "update the attributes of a particular key", and that it's only job. However, how granular does that "single responsibility" go?
The body of the function does 3 things:
- Creates (subsequently Opens) a handle to an HKey
- Sets the values of the attributes for the HKey
- Raises a wrapped exception if #1 or #2 fail
Is the SRP that granular or is my understanding that the function is only responsible for updating, and conversely not deleting, valid within the SRP? I've read that SRP only applies to how classes behave together in a program, but not about whether it relates to how standalone methods. Surely at some point a method does something more than just a single thing:
def main():
program_init()
program_run()
program_cleanup()
Unless your granularity is "it managed the programs lifespan"...
Edit:
In the event it is a violation, I can pull some out:
def updateKeyAttributes(key: HKType, attrs: Sequence[Tuple[Optional[str], int, Optional[Any]]) -> None:
for name, typ, val in attrs:
SetValueEx(key, name, 0, typ, val)
try:
with CreateKeyEx(hiveroot, key, 0, KEY_WRITE) as open_key:
updateKeyAttributes(open_key, attrs)
except OSError as err:
path = f'{_ROOT_MASK[hiveroot]\\{key}'
raise RegistryError(f'Failed to update key attributes: {path}') from err
But now the module will have, two try/except
blocks rather than sharing a common function.