Three divisions of code: Composition, Modeling, Logic

Every developer wants to write good, clean code. But what does that mean? There are many principles and practices to software engineering that help lead to good code. Here is a quick list:

  1. 10/100 Principle
  2. S.O.L.I.D. Principles
  3. D.R.Y. Principle
  4. Principle of least surprise
  5. KISS – both Keep It Super Simple and Keep It Super Small
  6. YAGNI
  7. TDD
  8. Interface-based design or principle of abstraction
  9. Plan for obsolescence
  10. Principle of Generality
  11. Principle of Quality
  12. Data models have no methods
  13. Encapsulation similar to Law of Demeter
  14. Big Design Upfront or BDUF (which causes too many projects to fail and should be replaced with an MVP sketch up front)
  15. MVP – Minimal Viable Product

You can go look up any of those principles. However, it is hard to understand all of them while in college or even in the first five years of coding. Even developers who have coded for twenty years struggle to understand which principle to apply to which part of code and when.

What parts of your code do you apply these principles to? No, “Your entire code-base” is not actually the correct answer.

That leads to the three general divisions of code:

  1. Composition
  2. Modeling
  3. Logic

There are some other divisions that don’t exist everywhere, such as a user interface or UI. Many web services and APIs and libraries have no UI, so it isn’t a general division of all code. However, the UI that falls into all three of the above divisions. There are many other such examples of divisions of code that aren’t as general.

Composition

Composition is how your code is laid out. Composition involves,

  1. Files, folders, & Projects, and location of language objects in them
  2. Libraries, packages, and references
  3. How a project starts up
  4. How language objects (i.e. classes in OOO) interact
  5. Determining how your logic is called
  6. Determining how your models are created
  7. Layering your application and how interaction occurs between layers

Pieces of composition have models and logic related only to their pieces.

Common Principles used in Composition

Many of the principles and practices focus around this area. Are you using the D in SOLID, Dependency Inversion or DI for short? If so, you are working in the area of composition. In fact, a “composition root” is a common term when discussing DI. Are you using Interfaces-based design? Law of Demeter? Many of these are all in the area of composition.

  1. 10/100 Principle
  2. S. I. D. or SOLID (Especially Dependency Inversion)
  3. D.R.Y.
  4. KISS (both)
  5. TDD
  6. Interface-based design or principle of abstraction
  7. Principle of Quality
  8. Encapsulation similar to Law of Demeter
  9. Principle of Generality
  10. BDUF (or better, and MVP sketch)

Why are some left out? Well, YAGNI can be super destructive when it comes to composition. When you first start an app, it never needs a DI container, right? But you will regret following the YAGNI principle with that every time! When it comes to composition, you are going to need it.

What is the state or your composition?

Some basic questions to ask yourself to see if you have good composition?

  • Do yo have a 1-step build?
  • Do you have a single file for a single class or object?
  • How does your program startup?
  • How does it create new instances of classes and other objects? With a DI container?
  • How does it configure settings? Is this clear, easy, and in one place? Can any class easily access those settings abstractly?
  • Can you create integration tests that run any one unit or multiple units of your code with all external systems DBs, Web Services, File Systems, etc, faked or mocked?
  • Do you find models and logic

When composition is done wrong or not understood, no amount of good modeling or good logic can save your code base. The composition has to be rewritten. Have you every heard these complaints?

  • The code is hard to work with.
  • The code is spaghetti code
  • I have no idea how this code works
  • Who wrote this code?
  • It takes forever learn this code base
  • It is a nightmare just to get this code to build

These are road-signs telling you that the composition has to be rewritten. Often, when someone has what would be called “bad” code, composition is what they are talking about. Vary rarely does a code-base need a complete rewrite. Often, it needs a composition rewrite. In fact, the entire movement to refactor to Microservices and Microlibraries is all about composition, or putting small bits of logic and modeling in one well-composed place because most monoliths did it wrong.

Modeling

This is the most obvious part of code. Creating models. Often they are simple data models, but modeling can get very complex (which you should avoid when possible because KISS, right?)

Almost anything can be modeled. A Person:

public class Person
{
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public int Age { get; set; }
}

Models can be small or big, though smaller is better.

Usually models are simple and easy to use. However, if you break some of the principles, models become difficult and cumbersome. For example, if you break the Data models don’t have methods principle, your models are now both modeling and providing logic, which could indicate the model now has two responsibilities, so the Single Responsibility Principle is broken.

Interfaces are automatically excluded from code coverage. Since data models shouldn’t have methods, they should not have tests. You can mark them as so, for example, in C# you can give a model class an attribute [ExcludeFromCodeCoverage], and there is likely an equivalent for whatever language or testing framework you are using.

Models are very common and there can be very many in a code base.

 

What do you model?

It is hard not to answer everything here, but really, you don’t model composition or logic. You model things. Nouns. Now, an action can be a noun, so while you don’t model logic, you might model a List<T> with an Add action, as it is common to add things to a list, however, the act of adding is not part.

Nouns represented in code are modeled. Data represented in code is modeled.

Behavior is modeled. Behavior is best described by an interface. All interfaces are models (not to be confused with data model classes, which is another type of modeling). Interfaces may be for composition or logic classes, and while the concrete composition or logic class itself isn’t a model, the creation of an interface is the act of modeling a single responsibility’s behavior.

Common Principles used in Modeling

  1. I in SOLID
  2. Principle of Quality
  3. Data models have no methods
  4. KISS (both)
  5. Principle of Generality (Think generics, such as modeling a list or collection with List<T>)
  6. Encapsulation similar to Law of Demeter (If your model is small enough and is shared between layers, it should be OK to be public right? Interfaces should be public, right?)
  7. TDD (except in data models, unless you break the Data models don’t have methods principle)
  8. YAGNI – helps keep models small
  9. Avoid model nesting hell (not a principle you hear much, but is very specific to models)

Notice this has way fewer principles than composition? That is because it is easier to do and more natural to get right.

What is the state or your modeling?

Some basic questions to ask yourself to see if you have good modeling?

  1. Are your models small and simple?
  2. Do you follow the Data models have no methods principle?
  3. Do you limit nesting of models? (Or do you have a nesting nightmare?)
  4. Does the code’s separate layers have their own models? Or do you practice model translation between layers?
  5. Does the average model have no more than 10 properties or fields?

Logic

When we talk about if conditions, looping, algorithms, data manipulation, hitting servers, reading or writing data, we are talking about the logic area. This is the meat of you code. This is where and how work gets done.

Logic classes are very common and there can be very many in a code base. When you are writing methods and doing things, you are writing logic.

What is the state or your logic?

Some basic questions to ask yourself to see if you have good modeling?

  1. Is all your logic decoupled into small 10/100 principle following single responsibility classes?
    1. If not, then, Oh, wait, that is composition and your composition is bad. Keep the logic, fix the composition.
  2. Is your logic code 100% unit tested?
  3. Does your logic code have parameter value coverage?

If you have bugs in logic, it is almost always due to lack of testing. 100% code coverage isn’t always enough if you don’t have parameter value coverage.

Common Principles used in logic

  1. 10/100 Principle
  2. S. and D. of SOLID – all dependencies should be injected and not part of a single responsibility
  3. D.R.Y. Principle – Don’t repeat your logic
  4. Encapsulation – Just make all your concretes private and their interfaces public and have a factory that returns concretes of interfaces
  5. KISS – both Keep It Super Simple and Keep It Super Small
  6. YAGNI – Don’t wrote logic you don’t need (unless you are writing an API for other consumers, then anticipated needs, prioritize them, get early customer feedback on them, and add them)
  7. TDD – Extremely important here as logic must be tested
  8. Interface-based design or principle of abstraction (almost a repeat of the D in SOLID)
  9. Principle of Generality – Sometimes, when the logic can be generic it should be
  10. Principle of Quality – Yes, this applies to all three

 

 

Leave a Reply

How to post code in comments?