« Back

# Code folders

Naming code is hard enough, choosing the right names for folders can be downright stressful. I can think of a dozen project where folder structure was an afterthought and code was all over the place.
I've found a simple 2D matrix that helps to classify the purpose of code, and make grouping files a much simpler problem.
AbstractConcrete
Transport??
Logic??
Service??

## y: Transport / Logic / Service

The first step is to consider your project as series of steps between an agent and some data. The agent performs an action, some logic is applied, data is retrieved or manipulated. Regardless of who the agent is - human, bot, event - or what part of the tech-stack, most programs follow this pattern.
The y axis of this matrix comes from the three areas of concern found in this flow.
Agent --> Transport --> Logic --> Service --> Data
  • Transport Layer is all about moving and choosing. Be it routes, pages, or event handlers, a transport file lets the agent make a choice and direct the program to execute a certain function.
  • Logic Layer is where the meat of your app resides. These are the functions that determine the shape and rules of your interaction: What is allowed and what isn't.
  • Service Layer is where you talk to third-party code. No program stands alone and at some point you'll need to interact with another service. Be it a database, a rest api, or an AWS resource, the service layer handles code that talks to other systems.
@note: You might be thinking that this pattern is pretty similar to MVC, and you wouldn't be wrong. This matrix broadens the concept to allow you to apply it to any codebase you want.

## x: Abstract / Concrete

Once you have a decided which layer your code resides in, we can decide if this is concrete or abstract code.
  • Concrete code is the bulk of your program. It has a single purpose that no other code performs.
  • Abstract code is reusable code that does something different depending on how you invoke it.
function getUserById(id: string) {}
// Is concrete because it will always return a user.

function groupBy<T>(list: T[], predicate: (t: T) => string) {}
// Is abstract because it will group anything by the predicate.

## Examples

Client Side
LayerTypeFile
TransportConcrete<SignUpPage/>You might have an app where there is only one page to sign up
TransportAbstract<PostLayout />A blog will have many posts, so it would be good to have an abstract layout that can wrap every page.
LogicConcrete<PasswordForm />In another app you might be able to sign up in a few places and so we would want to reuse the it.
LogicAbstract<Button/>A button is the ultimate reusable piece of logic. In almost every situation it acts like a button but performs a different action
ServiceConcreteusePostData()It's interacting with an api service to fetch some data, but it will only ever fetch Posts.
ServiceAbstractuseLocalStorage()It's a hook to interact with the localStorage service, but it abstract and makes no decisions on what gets stored.

## Example Client Folder Structure

I like this methodology because its clear foundation lets you customise your folder name and structure in a way that makes sense to your current project. You can reuse a frameworks idioms or pick names that make sense to your team. Below I've mapped the concepts to a small React client.
LayerTypeFolder
TransportConcretePages
TransportAbstractLayouts
LogicConcreteFeatures
LogicAbstractAffordances
ServiceConcreteServices
ServiceAbstractUtils
The bulk of code in a react app sits in the Logic layer so features and affordances are their own root folders. However abstract transport and service modules are less common and feel more at home grouped inside pages and services.
src/
  affordances/
    Button.tsx
    Input.tsx
  features/
    SignUpForm.tsx
    UserProfile.tsx
  pages/
    layouts/
      BlogPost.tsx
      NormalPage.tsx
    PostPage.tsx
    SignUpPage.tsx
    UserProfilePage.tsx
  services/
    util/
      useLocalStorage.ts
      useApi.ts
    usePostItem.ts
    usePostList.ts
    useUserData.ts