organizing – DillyBeeze Blog https://dillybeeze.com Thu, 24 Apr 2025 20:53:32 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.1 https://dillybeeze.com/wp-content/uploads/2024/07/cropped-android-chrome-512x512-1-32x32.png organizing – DillyBeeze Blog https://dillybeeze.com 32 32 How to Govern your Code Garden easily Empowered by GenAI? https://dillybeeze.com/architecture/how-to-govern-your-code-garden-easily-empowered-by-genai/ https://dillybeeze.com/architecture/how-to-govern-your-code-garden-easily-empowered-by-genai/#respond Wed, 23 Apr 2025 18:52:43 +0000 https://dillybeeze.com/?p=567 Just like a gardener prunes and shapes plants to follow a specific design, developers use linting tools to enforce architectural guidelines and ensure their code follows best practices. Both require ongoing care to identify weaknesses – whether it’s unhealthy plants or inconsistent code – and take action to correct them. With the right tools, developers can secure a solid code foundation, ensuring the codebase grows in a healthy, maintainable, and scalable way, just as a well-planned garden thrives over time. 🌱

You don’t need a PhD in machine learning to build something awesome with GenAI. If you’re a developer with a fun idea, that’s more than enough. Case in point: we built a free app named Lint-E that lets you generate custom ESLint rules using one of OpenAI’s models, GPT-4o. And yes – you can even run and validate those rules right in the UI.

Bring your own OpenAI key, craft a rule, hit “Lint Code”, and boom: you’re testing your custom AI-generated linting rule live in the UI. We even added Angular support to start playing with framework-specific rules.

So how does all this work? Let’s break it down.

Linting and ESLint 101

Linting is the process of analyzing source code to flag programming errors, stylistic issues, or suspicious constructs. Think of it like spellcheck for your code – except way smarter. It helps teams write cleaner, more consistent code. Linting is one of those things that quietly saves your life 50 times a day as a developer. Here are some practical use cases where linting really shines:

Catch Bugs Early
Description: Detect common mistakes before they cause runtime errors.
Example: Accidentally using assignment instead of comparison in a condition.
Enforce Code Style Consistency
Ensure all developers follow the same formatting and coding style.
Example: Consistent use of quotes, indentation, spacing, or semicolons.
Prevent Use of Bad Practices
Disallow risky, insecure, or outdated coding patterns.
Example: Blocking console.log, deprecated APIs, or unsafe functions.
Improve Code Quality
Encourage cleaner, more readable, and more maintainable code.
Example: Suggesting simpler expressions or consistent naming.
Custom Project-Specific Rules
Apply lint rules based on the needs of your specific application or team.
Example: Enforcing naming conventions, requiring documentation, or framework-specific rules.
Automated Checks in CI/CD
Prevent bad or non-compliant code from being merged into main branches.
Example: Blocking pull requests that fail linting during continuous integration.
Teaching and Onboarding
Help new or junior developers learn best practices by catching mistakes early.
Example: Flagging common anti-patterns or non-idiomatic code.
Enforce Architectural Boundaries
Maintain proper structure and separation of concerns in large codebases.
Example: Restricting imports between layers, preventing circular dependencies, or enforcing modular boundaries.

ESLint1 is the go-to linter for JavaScript and TypeScript. It works by parsing your code into something called an Abstract Syntax Tree (AST) 🌳, which is a structured, tree-like representation of the code. Instead of treating your code as just text, ESLint looks at the structure – like where functions start and end, what variables are declared, and what expressions are used.

An AST of any programming language is basically like grammar for natural languages – yes, the thing with conjunctions and adverbs. The sentences can be really different in terms of content like “Honey resists spoilage.” 🐝 (Archaeologists have found 3,000-year-old honey in Egyptian tombs that’s still edible!) and “Banana contains radiation.” 🍌 (Bananas contain a radioactive isotope called potassium-40). Still both sentences consist of a noun, a verb and an object. In JavaScript the function:

private function sum(a, b): number {
     return a + b;
}

Would look something like this as AST in JSON-format:

If you want to explore your program just try out the public AST Explorer2. Your program to explore can also be written in other general-purpose programming languages (GPLs) like Rust or Python or domain-specific languages (DSLs) like CSS. ESTree is a specification for representing JavaScript syntax trees in a standard JSON format, commonly used by tools like linters, compilers, and formatters to analyze and manipulate code. Python for example has its own ast module and Java for example does not have a single universal specification like ESTree. Instead, tools like Eclipse JDT3, ANTLR4, and JavaParser define their own AST structures for Java code.

ASTs also facilitate code transformation, such as transpiling newer JavaScript syntax into older versions. They support automated refactoring, code optimization, and error detection during compilation. Many IDEs use ASTs for features like auto-completion and real-time error highlighting. Additionally, ASTs help generate documentation, detect security vulnerabilities, and enable static type checking in languages like TypeScript. They are also used in test coverage tools to identify untested code. Overall, ASTs play a vital role in improving code quality, performance, and enabling cross-language tools like Prettier and ESLint, making them indispensable in modern development workflows.

ESLint works by parsing the source code into an AST, which represents the code structure. It then applies a set of predefined or custom rules to the AST to identify potential issues or style violations. Finally, it reports any errors or warnings, helping developers maintain consistent and error-free code.

Now you probably think… I don’t care. I have these rules in my project and they work because someone once configured ESLint. And yes, ESLint comes with some great core rules and a default setting for each coding guideline that should be considered best practice basically anywhere. There are further plugins like the Angular ESLint Plugin5, that does not only provide you with framework specific functionality – e. g. @Component is usually not part of the JavaScript grammar – but also use case specific sets of rules. Obviously you will also need the Typescript ESLint Plugin6 when linting TypeScript since it is a superset of JavaScript. Therefore, the grammar differs here, too. Some fancy add-on-rule-sets to your lint rule collection are provided by plugins like the ESLint Security Plugin7 or the Unicorn ESLint Plugin8. 🦄 Whereas the latter does not lead to more unicorns within your code base but provides a nice wish bag of useful linting rules. 🌈

Though we have all these handy core rules and plugins, you are individual, and so is your project, team, architecture and codebase. Custom naming conventions, big changes or architectural constraints might demand for a tailored set of rules according to your needs. And of course you can simply create your own plugin. Which has the nice side effect of not being dependend on the plugins of others pulling you deeper into the vortex of updates, version mismatches, rule conflicts, breaking changes, performance impacts… 🌪(That’s the tornado emoticon).

To write a custom ESLint rule, you will need to understand how ESLint parses code into an Abstract Syntax Tree and how to navigate this tree to detect specific patterns. You’ll also need to know JavaScript’s syntax and how ESLint’s rule API works to define the logic for your rule. It can be challenging because writing effective rules requires both: a deep understanding of the language’s structure and the ESLint framework, as well as dealing with edge cases and ensuring your rule is both accurate and efficient. So yeah, let’s go back to these plugins….

Ooor we call upon GenAI! 🤖🪄

Sorry for the Buzzword!

We are doing GenAI. Just sounds super fancy. To sales execs.

For most devs the “doing” of Generative Artificial Intelligence really refers to the use of a model available on the market by directly or indirectly prompting it. If you get lucky the developer can reason why she decided to specifically go with that certain model, prompt-UI, IDE-integration or setup. Knowing the general fundamentals on GenAI, models, architectures and tasks they excell in as well as basic knowledge in prompt engineering is already a major win, which most devs require privately by scraping the internet rather than by being trained by their companies. We are amateur readers, too. 🤓

As a software developer what we do is:

  • Having a great idea
  • Writing awesome software
  • Picking the adequate model and attach it to our software to solve precisely specified tasks

We decided to use GPT-4o. It is a large language model, specifically a decoder-only transformer. Decoder-only models, like GPT-4o, are popular because they are well-suited for text generation, and their unified architecture makes them efficient at inference time. Unlike encoder-decoder models (such as T5), which use a separate encoder to process input and a decoder to generate output, decoder-only models handle both tasks within the same mechanism — generating output token by token while attending to the input context. This design is often simpler and faster for generation tasks, though not necessarily smaller in model size.

This efficiency is one reason why decoder-only models are especially effective for tasks like writing custom ESLint rules. They generate code step by step, predicting each part based on the prompt and previous tokens — without needing a separate comprehension stage like encoder-decoder models do. This makes them ideal for open-ended generation tasks, offering a great balance between capability and cost-effectiveness. GPTs aren’t the answer to everything, but in this case, they’re hitting the nail on the head.

The Tool: Lint-E

Lint-E (soon available for public usage here lint-ai.com) is a tool that helps you write custom ESLint rules as well as validate and export them within seconds. The app consists of a Node.js backend and Angular frontend. You bring your OpenAI API key which will be used in the API request to the GPT. Your API key will be stored in the NGXS store9. In NGXS, data stored in the store is kept in JavaScript memory on the client-side, which means it’s stored in the browser’s memory (specifically, within the JavaScript runtime environment). By default, the state is non-persistent, meaning when the page is reloaded or the browser is closed, your API key will not be remembered. There is no additional persistence implemented (e.g., localStorage, sessionStorage, or a custom persistence mechanism). You get a full UI with fields to fill out:

Description (mandatory): describe what the rule should do and why you need it. The more and the more precisely the better.

Failure Example: Give an example of when the rule would throw an error (e.g. Rule: “Do not use eval!”, bad example: “eval(anyCode)”).

Framework: You can of course also create rules specifically for e.g. React or Vue. Right now we simply do not support linting them for verification. Angular is fully supported.

Category: If you write your own ESLint plugins you might want to sort rules by concerns to improve code maintainability, readability, and organization. The category will be placed in the docs-section in the rule’s metadata. To check the structure of a rule check “Custom Rules – ESLint – Pluggable JavaScript Linter”10.

Type: In ESLint, rules can be categorized as problem (rules that detect code issues requiring fixes), suggestion (rules that recommend improvements without enforcing them), or layout (rules that enforce code formatting and style consistency). The type is also part of the rule’s metadata.

Fixable: Check the box if you want the rule to enable an automatic fix option.

Tools: You might be using a build tool like Nx. In that case you need a a link to the ESLint setup for Nx monorepos shown in the blue box below.

Depending on what you selected above the green and blue ressource boxes below will provide you with links to some documentation on how to setup ESLint with your specific build tool or framework. 🛠

ESLint Version: We advise the GPT to keep the ESLint version in mind, while we only distinguish between major versions v8.x an v9.x.

Filetype: So far we support JavaScript and TypeScript linting. No JavaScript XML or HTML. We are working on optimizing that before making it public.

Just press Create Rule to have GPT create your rule and some bad example code to test your new rule on. With Lint Code you can lint the code example to lint and see if your rule works as intended. In case you asked Lint-E to add a fixable you can test it with Apply Auto Fix. Afterwards you can of course lint again and see if the applied fix made the errors go away by linting once again. We cannot garuantee that a perfect rule and / or fixable will be created immediately. We left the code editors open to adjust manually as needed.

°˖𓍢ִ໋🍃✿°.💚⋆ Writing a rule with Lint-E demo (…btw an absolute nonsense rule 🙈)

Why This is Fun (and Powerful)

With our app, all you need is a public OpenAI key and a custom rule in mind. You can:

  • Prompt GPT to generate custom rules
  • See the rule’s AST-powered logic
  • Test and validate it live in the UI
  • Copy, export and embedd the rule within seconds

It’s not just about GenAI – it’s about using GenAI as a creative tool. And when you combine that with useful ideas, knowledge and developer tools like ESLint and ASTs, the possibilities are WILD! 🐻🧸🐻‍❄️🐼 (personal obession with bears)

What’s Next?

A garden without maintenance is a jungle. 🦥 Tailored linting can help your code garden grow as intended. Want to help us make Lint-E support other frameworks or even languages? Try it out and give us feedback. Or just bring your greatest lint rule idea and see what the GPT comes up with.

  1. https://eslint.org/ ↩︎
  2. https://astexplorer.net/ ↩︎
  3. https://projects.eclipse.org/projects/eclipse.jdt ↩︎
  4. https://www.antlr.org/ ↩︎
  5. https://www.npmjs.com/package/@angular-eslint/eslint-plugin ↩︎
  6. @typescript-eslint/eslint-plugin – npm ↩︎
  7. https://www.npmjs.com/package/eslint-plugin-security ↩︎
  8. eslint-plugin-unicorn – npm ↩︎
  9. https://www.ngxs.io/ ↩︎
  10. https://eslint.org/docs/latest/extend/custom-rules ↩︎
]]>
https://dillybeeze.com/architecture/how-to-govern-your-code-garden-easily-empowered-by-genai/feed/ 0
What if I had a Tidying Expert like Marie Kondo organize my Repository? https://dillybeeze.com/architecture/organizing-decluttering-dan-sha-ri/ https://dillybeeze.com/architecture/organizing-decluttering-dan-sha-ri/#respond Tue, 30 Jul 2024 16:28:00 +0000 https://demo.themeansar.com/newsup/lite/?p=30 Whether it’s “The Home Edit” or “Tidying up with Marie Kondo” – these popular Netflix series are all about professional and sustainable tidying. The organisation pros promise to turn chaos into a system in which we can keep order forever.

But what exactly is a system? A system is an organised and comprehensive compilation of individual parts in a specific area of knowledge or thought. It is any collection or set of individual parts that are related to each other. Professional organisers define what makes a good system: form and function. A good system saves time. You can find individual parts quickly, know where to store individual parts and can quickly adapt the system to your own needs. And you save money. You have an overview of all the individual parts in the system. Because you can find them again, you don’t have to buy new ones. A good system also takes up less space. And last but not least, you might also want to make a good impression on visitors with your system.

Simplicity is ultimate sophistication. – The Home Edit

In a system, various quality features can be more or less pronounced depending on requirements1. In a wood workshop, more emphasis is placed on expandability, as new tools like screwdrivers or nails and materials are constantly being added. In the arc42 quality model there are many more such quality features specifically for software systems.2

Of course, a system is much more than a simple file repository. From the outside, however, we simply place individual parts in a box designed for this purpose. People do this in two ways3:

  • Simply throw everything in. In this case, the users of the system are later dependent on search tools – such as the search in our IDE.
  • You think about a structure and organise everything into this structure again and again. This also enables us to navigate logically in order to find something again.

Even if we don’t consciously think about it, we tend to structure our repos in some way. Structures that I have encountered in repos are folders structured by file types, by components of a particular framework – in the case of Angular, for example, this would be pipes and directives – or folders structured by features. The latter are often advertised with metaphors such as “Screaming Architecture”. The term “screaming architecture” is used when you can recognise at first glance what the core of a new project does and what it is about.

If the system is a story, the modules are its chapters. – Eric Evans

All of the above structures have their advantages and disadvantages. However, science has shown that our brain tends to break down blocks of knowledge into packages and create objective schemas that represent the real world. It has also been shown that we activate the same areas of the brain when navigating virtually through a file system as we do when navigating in the real world, for example when we are once again looking for the peeler in the kitchen. When searching by entering a search parameter, on the other hand, it is mainly left lateralised, mostly frontal activations that are observed, which are associated with linguistic processes (Broca’s area). The navigation process still works very well even in people with severe language problems following brain damage.4 In order to be able to navigate through a system in a meaningful way, a good and understandable structure is required.

Organisation is the key to productivity. – The Home Edit

But unfortunately, we repeatedly fail to maintain an appropriate structure or neatness, neither in the home nor in our digital systems. Developers spend more than 50 % of their time trying to understand programmes.5 This is caused by domain and technical complexity, but also due to inappropriate structuring and untidyness. A system with form and function should be easy to understand.

Simplicity is a great virtue but it requires hard work to achieve it and education to appreciate it. And to make matters worse: Complexity sells better. – Edsgar Wybe Dijkstra

So what to do when the chaos is already there? Here the organizing professionals give us a few valuable steps. Tidy up and let’s go!

Step 1: Define a goal

Tidying up is annoying, takes time and there are always better things to do. That’s why we need to make time for it and find good reasons to motivate everyone involved – including ourselves. In IT projects, this often includes project managers, customers and the rest of the development team. But still ask yourself: why am I actually tidying up here? If I have managed my personal chaos well so far and have not disturbed anyone, then I may even be investing time and money unnecessarily. Concrete goals of refactoring could be to save time and money in the future, to extract components for reuse or to avoid errors.

Step 2: Sort out

You have decided to take the next step. This is about getting rid of anything you don’t need or that isn’t functional. A popular Japanese method here is Dan-Sha-Ri (断 (dan): cut off, 捨 (sha): throw away, 離 (ri): let go), which stands for minimalism and simplicity.6 Marie Kondo, inventor of the “Konmari method”, would say to every item: ask yourself whether it makes you happy. Anything you answer no to will be discarded. If you now go through your repo with your team and do this, there might not be any repo left. So that doesn’t quite work. Nevertheless, there are definitely unused files, commented-out functions, unused classes, unnecessary comments, etc. in our repos that can only increase their value by being deleted. Sometimes these are recognised as code smells during development, but sometimes they have been lying around for longer. That’s why we need to clean up regularly instead of just continuing to develop new features.

Only deleted code is good code. – Old developer wisdom

But there is another very special category: sentimentals. Of course, there are individual pieces or entire boxes that are hard to part with. You’ve spent a lot of time with them. You have special memories of the time you spent with them. You simply can’t part with them. That’s okay. Put them in their own box and put them somewhere in the basement. Delete them when the time is right.

Step 3: Categorise

Be strategic about the stuff you want to use. – The Home Edit

What remains, we want to categorise in order to pack it into boxes. In our software systems, these categories are often referred to as modules. An architecture is modular if it has been broken down in such a way that coherent units are created at all levels of abstraction, from which knowledge units – chunks – can be formed.7 It is an advantage if the proportions of our categories are balanced. Let’s say I want to categorise my bathroom utensils. What would I categorise then?

Most architects can think of many basic principles here. Certainly the Single Responsibility Principle8, Separation of Concerns and the Component Cohesion Principles9. In addition, measures for determining connections and dependencies within and between individual categories:

  • Cohesion: a measure of how well the individual parts of a box fit together. Are they individual parts that are primarily focussed on the respective purpose?
  • Coupling: a measure of how strongly two categories (and by categories we mean: methods, functions, classes, modules, etc.) are dependent on each other and will not work self-sufficient.

In the following, I will therefore only discuss two other concepts. An important measure for determining the optimal coupling is instability. The value of instability is made up of the following two values:

  • Afferent coupling: how many other boxes require the contents of a particular box to function?
  • Efferent coupling: how many other boxes does this box need in order to function?

The second measure is abstraction. Abstractions provide interfaces that allow the code to be tested and modified by adding elements rather than making major changes.

  • Abstract: How many abstract (non-concrete) interfaces and abstract keyword-labelled items or boxes do I have in a package?
  • Concrete: How many concrete ones do I have?

It is important to maintain a balance between sufficient abstraction and instability10. If I abstract little, but my boxes are as stable as possible or each one stands on its own, I am in the “pain zone”. In the code, for example, I would not abstract basic table functions, but would have to implement them anew each time. However, if I abstract too much, the code becomes unreadable and unusable, and I find myself in the “zone of uselessness”.

Another measure is connascence11, a generalisation of coupling and cohesion. Connascence is made up of three properties:

  • 1. Strength: there are different forms here, the strength of which varies.
  • 2. Degree: How many dependents are there?
  • 3. Locality: How far apart are they from each other?

How easily a constraint can be found and refactored depends on its form. Static forms of constraints are easy to find using static code analysis, while dynamic forms are much more difficult to refactor. Race conditions or unfavourable loading sequences lead to errors that often cannot be assigned directly. Such temporal dependencies are not recognisable to the naked eye. To eliminate them, I could, for example, categorise my bathroom utensils according to when they are used (such as a box of “morning routine” or “utensils for the sommer” where I find my sun creme and mosquito spray). Categorisation generally depends heavily on individual needs and is not constant.

Step 4: Pack into boxes

Now that you have categorised everything as desired, what type of boxes do you pack the categories into and how do you stack the boxes to make the best use of the available space? The type of box you put something in depends on how visible or easily accessible you want the content to be for all users of the repo

For example, a library with all user interface components should be easy to find and easily accessible for everyone.

A place for everything, and everything in its place. – The Home Edit

However, we don’t want to have all the boxes all over our bathroom, but rather stack them as sensibly as possible on our shelves. The order and stacking height are decisive for the complexity. On the one hand, the complexity of the system depends on the number of boxes and the parts they contain. This can often not be influenced. However, the stacking height and the width of the structure are also decisive. These become larger and larger over time. Dan-Sha-Ri has a simple “one-touch rule” for this: everything in the system should be accessible with two hand movements.

We can not only stack boxes or place them next to each other so that each box is part of the whole. We can also nest boxes inside each other and pack smaller boxes into large ones as categorical subordination.

Step 5: Labelling

Now that we’ve sorted everything neatly, we still need to label it so that we know what’s in the boxes later on.

Remember your code is for a human first and a computer second. Humans need good names. – Martin Fowler

Good names are pronounceable, searchable and consistent in the domain. It is important to choose and keep only one word per specialised or technical concept. Further good tips on naming can be found in various wellknown coding literature.

Step 6: Retain and maintain

This brings us to the last step. How can we now maintain our new order?

Now I’m a pretty lazy person and am prepared to work quite hard in order to avoid work. – Martin Fowler

In 1969, Meir M. Lehman conducted an empirical study at IBM to improve the efficiency of the company’s programming. The study received little attention within the company and had no impact on development practice. Subsequently, however, a number of researchers have attempted to fathom the laws of programme development dynamics12. Not all laws could be clearly confirmed and some laws could only be observed after the commercialisation of the systems studied. The scientist Pirzada came to the conclusion that commercial pressure limits the growth of the software and promotes the deterioration of the system. Furthermore, the laws only apply to E-type systems. E-type (evolutionary) programmes mirror human processes or a part of the real world. This type of programme attempts to solve a task that involves humans or the real world. Here is an extract:

  • I. Law of constant change: A type E system must be constantly adapted, otherwise it will become less and less satisfactory in practice.
  • II. law of increasing complexity: When a type E system is changed, its complexity increases and it becomes more difficult to develop it further unless work is done to maintain or reduce the complexity.
  • III Law of Familiarity Maintenance: In general, the incremental growth (growth rate trend) of Type E systems is slowed by the need to maintain familiarity.
  • VI. law of feedback system: E-type evolutionary processes are multi-stage, multi-loop, feedback systems with multiple participants.

Conclusion

It can be deduced from this that a system cannot simply be built or tidied up once and then left alone. A system must be constantly tidied up and important design decisions must be made again and again. If these decisions are delayed and individual parts are thrown in at random, the result is disorganisation. On the one hand, we need permanently installed “clutter detectors” in our local environment and in our pipelines: formatter, linter, tests. On the other hand, we need to schedule time to clean up. We further need to maintain familiarity and get everyone on track on where stuff goes and how things are structured.

Dan-Sha-Ri has a few more tips for you:

  • Make tidying up a habit.
  • If you build something new, think about whether you already have it, and if so, replace the old one completely.
  • Think carefully about whether you really need the new solution or the new part.

Nobody expects us to build systems that tell stories. But only form and function turn chaos into a system. What’s more, a good order that works for all users of the system should not be determined by a single person. Good decisions are only made as a team.

Sources

  1. https://en.wikipedia.org/wiki/List_of_system_quality_attributes ↩︎
  2. https://quality.arc42.org/ ↩︎
  3. The Effect of Folder Structure on Personal File Navigation, O. Bergman, S. Whiiaker, M. Sanderson, R. Nachmias, A. Ramanoorthy, 2010, American Society for Information Science and Technology ↩︎
  4. Navigating through digital folders uses the same brain structures as
    real world navigation, Y. Benn, O. Bergman, L. Glazer, P. Arent, I. D. Wilkinson, R. Varley & S. Whittaker
    ↩︎
  5. An Empirical Validation of Cognitive Complexity as a Measure
    of Source Code Understandability, M. M. Barón, M. Wyrich, S. Wagner ↩︎
  6. https://medium.com/@amandaorganizelover/spark-joy-or-dan-sha-ri-the-outcome-of-two-different-organizing-methods-are-very-362930467786 ↩︎
  7. https://jax.de/blog/modularisierung-und-kognitive-psychologie/ ↩︎
  8. https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html ↩︎
  9. https://kariera.future-processing.pl/blog/object-oriented-metrics-by-robert-martin/
    ↩︎
  10. Building Evolutionary Architectures, N. Ford, R. Parsons, P. Kua & P. Sadalage ↩︎
  11. https://connascence.io ↩︎
  12. The evolution of the laws of software evolution. A discussion based on a systematic literature review., I Herraiz, D. Rodriguez, G. Robles & J. M. Gonzales-Barahona, several universities in Madrid Spain, 2013 ↩︎

]]>
https://dillybeeze.com/architecture/organizing-decluttering-dan-sha-ri/feed/ 0
I am in a toxic Relationship with a Common Folder. How can I get out of it? https://dillybeeze.com/architecture/toxic-relationship-with-common-folder/ https://dillybeeze.com/architecture/toxic-relationship-with-common-folder/#respond Tue, 30 Jul 2024 14:26:00 +0000 https://demo.themeansar.com/newsup/lite/?p=26 Do you have a box of leftovers at home? A box where you don’t know exactly what’s in it. It could contain anything. If you’re looking for something, then definitely have a look in this box. Things get tangled up in the box easily. Things exist in the box that you’ve long wanted to throw away. It takes ages to find something in this box again.

Actually, you should have tidied the box long ago and then comes that one Sunday when you finally decide to tidy it up. Maybe you’ll be like me. I do it every two years. Then I either throw the box away completely or put it in the cellar as it is, because tidying up is far too much effort for me, I’ve already bought replacements for most of the contents anyway or I prefer to buy something new instead.

From time to time, our repos also contain boxes with names such as “Common” or “Shared” – whether as a suffix, prefix or stand-alone. I also summarise folders, files and other resources with such generic labels as common structures. These terms act like instructions for use instead of a descriptive name. However, I have rarely come across common structures that really only contain “common” content. When developers don’t know what to do with something, they put it in the leftover box. Since there are many different and quite justified opinions on this topic, I decided to talk to a neutral authority about it: ChatGPT.

ChatGPT:

Files and resources that are used multiple times in different parts of a project or application are placed in a commons folder. The purpose of the common folder is to avoid redundant code and promote reusability.

Sounds good at first. Files and resources that are used “multiple times” are placed in a box like this. But is something “common” if at least two people use it or if everyone uses it? If everyone is allowed to use it or only a closed group? If they actually use it or if they could just use it in general but haven’t used it yet or perhaps never will?

Wouldn’t it be important, especially for things that I want to use frequently and in many places, to be able to find them quickly with the help of a precise name? So I asked ChatGPT what they would expect to find in such a box.

ChatGPT:

Utility functions and classes:
  • Helper functions that are used in several modules, such as formatting functions or validation functions
  • Generic classes that are used multiple times, such as base classes for certain components
Constants and configuration files:
  • Global constants, such as API endpoints and configuration values
  • Configuration files that are used across projects
Common components and widgets:
  • UI components that are reused in different parts of the application, such as buttons or form fields
  • Layout components or themes that ensure a consistent presentation
Styles and assets:
  • Shared CSS files or styles that are used in multiple areas
  • Shared images, icons or other static resources
Utilities and libraries:
  • Third-party libraries or libraries developed in-house that are required across projects
  • Abstractions of external services or API clients
Tests and mock data:
  • Common test helpers or mock data needed in different test cases

Thank you. But if she can describe to me so precisely what belongs in a common folder, why not just create structures with the same name and in which you can find exactly these things? I have already found other things in common folders. The things that ChatGPT expects here sound like cross-sectional solutions that I find in almost every software system. So I philosophised a bit more with ChatGPT and we came to the same conclusion, that common structures can easily be misunderstood.

ChatGPT:

Unclear limitation of content: You might think that everything that is used multiple times belongs in the commons folder, which can lead to a cluttered and unstructured folder.

  • Misleading naming: The term “common” is very general and could be interpreted differently by developers.
  • Lack of documentation: Without documentation, it could be unclear which files are in the common folder and how they should be used.
  • Confusion about responsibilities: It could be unclear who is responsible for the maintenance and upkeep of the content in the commons folder.

ChatGPT also presented me with a solution to each problem. Firstly, the recommendation to define clear guidelines on what belongs in this box. Secondly, I should create a README file that contains the purpose and content of the folder. I should define responsibilities – i.e. appoint a maintainer or a whole team that is responsible for the common box. I also found this tip particularly interesting:

ChatGPT: Use more specific names like “shared”, “utils”, “components”, “assets”, depending on the type of files that will be stored there. This creates more clarity.

I think at this point I realised that ChatGPT and I were not going to reach a consensus on clarity. If it takes so much help to explain something, is this really the right approach? However, ChatGPT continues to adhere to common structures such as a common folder:

ChatGPT: A well-organised commons folder helps keep code clean and maintainable by avoiding redundant implementations and promoting code reusability.

On the one hand, ChatGPT discreetly hides the precondition “well organised” here. Secondly, is ChatGPT really talking about a common folder or does it really mean abstraction? Abstraction aims to derive and generalise general schemas for solving a problem. These schemas can be located in a central location, which means that they do not burden the code base, there is only one point of maintenance and, in the best case, they can be reused. This “central location” is then often a common structure. Abstraction also offers us advantages when clearly labelling files, classes and other components.

The purpose of abstracting is not to be vague, but to create a new semantic level in which one can be absolutely precise. – Edsger W. Dijkstra

If I manage to extract a concrete observation – a schema – from a specific implementation, then this gives me the opportunity to name this schema precisely. It could be extracted and is no longer hidden in other constructs that are labelled under completely different, for example, more technically driven names. Terms such as “common”, “tools” or “shared” are the opposite of precise naming.

After several unhappy long-term relationships with common structures, I was allowed to help design a frontend structure myself in 2022 and decided to avoid using “common” or “shared” in or as a label. We went through with it and it actually worked. Common structures – if “well organised” – solve the problem of central storage of abstract and cross-sectional solutions that are or can be used by a wide variety of consumers. Nevertheless, they harbour risks that can exceed the added value. In addition to creating common structures, what options do we have to achieve the aforementioned goals?

Goal: Store shared files and resources centrally

Open more and smaller boxes: Nobody said that all shared resources have to be in one folder. Instead of one large common box, professional organisers recommend many small boxes that can be stacked on top of each other, next to each other or inside each other. Each box has its own unique label. If a new item does not fit into any of the existing crates, it is time to rethink, reorganise or open a new mini crate. Of course, you can now hide these crates behind a common façade – which always means just one more click.

Goal: Regulate access rights – Common is there for everyone?

In practice, naming one folder “Common” or “Shared” and not others rarely protects against unwanted access. If you have packed everything into smaller boxes, it will be even easier to assign specific access rights. It is not the naming that indicates the possible areas of use, but documentation including models that explain structures to us and rules that kick in when we use resources outside the defined area of use. Tools that support us in this are, for example, Module Boundaries in Nx or Spring Modulith.

Common structures are the silent spaces of a screaming architecture. They rarely provide readers with further information and leave room for interpretation. This can be a good thing, but gives individual team members a lot of responsibility. They have to interpret and decide for themselves what the label means. The label on a box alone restricts the room for interpretation.

It holds everybody accountable – and that’s the item that should live in that bin, nothing else. – The Home Edit

If all team members have a clear idea and common definition of what they will find in this box and what can be stored here, it can certainly work. Whether in the household or in our repos, this requires increased communication, trust and/or control. There are certainly teams that have their common structures under control and know them well. However, neither “common” nor “shared” should be a label that is tied around a hodgepodge of leftovers that don’t really fit anywhere else. In this case, leftover boxes are more the result of idleness in dealing with the contents of the box, structuring it and finding suitable labels. If you put such a box of leftovers in your repo, you shouldn’t be surprised if your colleagues throw things in there too. So don’t set the leftover box trap for your colleagues.

]]>
https://dillybeeze.com/architecture/toxic-relationship-with-common-folder/feed/ 0