:::info - **Location:** K1/0/85 - **Date Session 1:** 13 July 2023 - **Date Session 2:** 16 November 2023 - **Article Link:** [Twelve quick tips for software design](https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1009809) - **Agenda** 1. Brief intro `2 min` 2. Discussion `43 min` - **Participants:** - - **Host Session 1:** @mbluteau - **Host Session 2:** Kingsley ::: ## Brief Intro Specifically targeted at helping scientists design better software so that it doesn't turn into a tangled mess. I (MB) have been quite focussed on studying software design because this is the section of the Intermediate RSE Course that I think needs the most work. AS: concrete case studies ## Discussion ### Session 1: Tips 1--6 - Tip 1: The idea that we should create documentation to make it appear like we followed a rational design process is nice, but it doesn't give any practical advice for how much attempt at design and requirements collection should be done in advance. - CM: but this shouldn't be an excuse to do no forethought and planning - JN: what you do at the beginning for planning is determined on a case-by-case basis - Also, prefers looking at thoroughly documented code rather than something like a UML diagram - CM: but for very complex things, you probably do want a higher level view - CM: some practical advice is probably just to have some notes of a plan and then that can turn into the design docs - Box 1 about challenge and response: is going through the history of a piece of software really the best way to explain its design? Or should this rather be done from "first principles" and make it look like the rational design process was followed? - CM: unclear what they are trying to say here - JN: perhaps this is trying to say that you actually shouldn't try and give the whole history - recording your design decisions an important - Tip 2: Design for people's cognitive capacity - MB: I feel like there is a missed point in this section related to how functions should be as close to pure as possible. Pure functions mean you don't have to keep track of any out-of-scope state that might affect the function. So, another way of saying this is to make functions as independent of state as possible; less possible with methods because have some state is sort of the point. - CM: Prehaps less about dependencies and more about inter-dependencies and the state that comes with that which is what causes the cognitive load - CM: hand hold users rather than hand-hold developers (so making things easier and less cognitive load for them with small argument lists) - CM: - Tip 3: Design in coherent levels - I have read a recent book, _A Philosophy of Software Design_, and it presents this in a slightly different manner, referring to clean abstraction levels that have simple interfaces and low overall complexity. The shortness of methods/functions is usually a good idea, but not the defining criterion. - Moreover, it it explicitly argues against "shallow" methods. The shallower methods are, the more you need to have and the greater the chance of increased complexity. - This isn't a licence to write mammoth funcitons and classes, but it does challenge the conventional wisdom that functions should always be super short. - CM: however, there should be the consideration of context. For an API, sure it is good to have small interfaces with lots of functionality, but perhaps there are convenience functions internally that are fine to be a single line - Refactor to use a new `stillEvolving()` function - But it does force them to jump to another piece of code to find out how what the stopping condition is. This is fine if the stopping condition is a bit complex, but in this case I would argue that because it is so simple, it doesn't make sense to split it into a separate method/function. - Of course, this is trouble with really simple examples that need to be conveyed in a very short space and time - JM: agreed - JM: there are plenty of examples at UKAEA which would benefit from reducing the length of the method and - Tip 4: Design for evolution - Information hiding and separating interface from implementation is a very sensible suggestion here - Design by Contract is somewhat taking this to an extreme by very rigidly specifying the interface. Has anyone ever used this and think it is actually worth the time? - Tip 6: Use common patterns - I think this is a well made point. A discussion I had recently also made the point that design patterns can often be mis-applied. This is also a point made in _A Philosophy of Software Design_:  > "The greatest risk with design patterns is over-application. Not every problem can be solved cleanly with an existing design pattern; don't try to force a problem into a design pattern when a custom approach will be cleaner. Using design patterns doesn't automatically improve a software system; it only does so if the design patterns fit. As with many ideas in software design, the notion that design patterns are good dosn't necessarily mean that more design patterns are better." - So the trouble with design patterns is knowing when they are applicable. Does this risk outweigh the benefits of using them? ### Session 2: Tips 7--12 - Tip 7: Design for delivery - Wide definition of DevOps - Some people love logging - Tip 8: Design for testability - Decoupling/abstraction good for removing features - Tip 9: Design as if code were data - Level of abstraction depends on knowledge - Too much abstraction obfuscates code - Tip 10: Design graphically - Don't talk about code architecture/use whiteboard much as a team - Some people write things out in draft, some write function/class signatures + docstrings - UML is hard to learn, write and maintain - Tip 11: Design for everybody - Security - Accessibility - Allow colour palettes to be configured - "Most accessible" default difficult to find - Internationalisation? - Tip 12: Design for contribution - Plug in frameworks only useful for larger software - Reduces burden on maintainer - Unix tools are composable