100% found this document useful (2 votes)
240 views32 pages

Name Construct and Structure

Uploaded by

Miguel Real
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (2 votes)
240 views32 pages

Name Construct and Structure

Uploaded by

Miguel Real
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 32

Name, Construct & Structure 

Organizing Readable Code 


 

by Khalil Stemmler 
 
​ une 16th, 2019​. 
This is version 1.0. It was published J
 
Newer versions can be downloaded from h
​ ttps://khalilstemmler.com/resources​. 
 
Found typos? Want to suggest an update? R
​ each out to me​, I’m pretty receptive to 
feedback. 
 
Check back @ ​khalilstemmler.com​ for revisions. 
 

 
 
© 2019 - Khalil Stemmler 
   
Table of Contents 
Nice to meet you! 4 

Introduction 5 
Organizing code more effectively 6 
What does it mean when code is readable? 6 
About this book 6 

Name 7 
Tips for picking good names 8 
Approach #1: Name files by Domain + Construct 8 
Approach #2: Name folders by Subdomain, and (optionally) Subdomain + 
Construct 12 
There’s a construct for everything 13 
Learn into Design Patterns 14 
Bad names 15 
Look out for too many helper/utility/service classes 15 

Construct 16 
Each construct is responsible for one type of behavior 16 
A construct instance should never be responsible for more than one subdomain 
element 17 
Architectural Boundaries 20 

Structure 22 
Project size 23 
Package by Infrastructure 24 
At a glance, this tells us nothing about the project 25 
Features are developed vertically, not horizontally 26 
Package by component 27 
Package by component for everything 28 
Univjobs’ React-Redux App Structure 28 
Tips for good structure 29 
Nesting rules 29 
Shared things 29 

In Summary 30 
Names 30 
What to look out for 30 
Constructs 30 
Structure 30 
A real life project 30 
 
 
   
Nice to meet you! 
What’s up? I’m Khalil Stemmler from k
​ halilstemmler.com​. Thanks so much for 
downloading this free ebook. I sincerely hope it’s useful to you.  
 
My goal is to help developers learn best practices towards creating and maintaining 
large scale typescript & node.js applications. I frequently publish blog posts, guides, 
books, and courses for developers building enterprise software with JavaScript & 
TypeScript. 
 
If you’d like to leave feedback on this book, suggest any other topics for me to cover, 
or simply just chat, check me on Twitter @
​ stemmlerjs​ and see what I’m working on 
@ GitHub @
​ stemmlerjs​. 
 

   
Introduction 

 
 
Have you ever come back to an old codebase and felt like it was way too hard to 
understand w
​ hat things are​, ​what they do​, and w
​ here they’re located​? 
 
I came about realizing that I wanted to write a short ebook on organizing codebases 
for readability when I was tasked with adding new code to an o
​ ld project​ I created for 
Univjobs​ a few years ago. 
 
It took me w
​ ay longer​ than I wanted it to have taken me to get things done. I found 
that I was spending a lot of time trying to figure out where things were and what they 
were responsible for. 
 
Over the past year of writing code using D
​ omain-Driven Design​, I’ve paid a lot more 
attention to how I organize my code. Also over this time, I’ve experimented with a 
bunch of different approaches to code organization and noticed a few patterns for 
extremely readable code. 
 
To summarize, it comes down to how we organize our files and folder with respect 
to the n
​ ames, constructs & structure.  
 
Naming files well, using well-understood technical constructs, and structuring our 
projects well are three ways to improve our ability to c
​ hange code quickly​.  
 
Having a
​ ll three of these​ when we’re organizing codebases makes them highly 
readable. 
 

The ultimate goal is to organize our projects to be readable & 


understandable so that we can rapidly make changes and add new 
features. 

Organizing code more effectively 


 
The fact of the matter is that we s
​ pend more time reading code than we do writing 
code​ (usually). 
 

What does it mean when code is readable? 


When code is readable, it means that we’re very quickly able to determine: 
 
- Name: what it is 
- Construct: what it does 
- Structure: where it’s located & why it’s there 
 
The faster we can discover w
​ hat it is​, ​what it does​ and w
​ here it’s located and why​, 
the more readable the code is (and the faster we can change or implement new 
things). 

About this book 


The approaches to organizing code in this book are what works for my team and I. 
You don’t have to agree with all (or any) of it, but I hope that it at the very least 
prokes thought on how you can improve your own code organization to be more 
productive. 
   
Name 
What it is 

 
 
“There are only two hard things in Computer Science: cache 
invalidation and naming things”. -- Phil Karlton 

Choosing names for c


​ lasses​, ​files, ​and f​ olders​ can be incredibly hard sometimes. 
However, it’s kind of important to put some effort into it. 
 
It’s important because the goal of naming things is to inform the reader as quickly as 
possible ​what it is​. 
 
How do we do that? How do we name things so that it quickly informs the reader 
what it is​? 
Tips for picking good names 
Here are a few of the approaches that I use for most cases. Having these in my back 
pocket enables me to usually never spend more than a couple of seconds thinking 
about a name. 

Approach #1: Name files by Domain + Construct 


 
When naming f​ iles, ​I’ll often choose names based on the s
​ ubdomain it belongs to ​+ 
the c
​ onstruct type. 
 
You might be wondering, “what’s a domain”?  

 
 
Secondly, we should understand what c
​ onstructs a
​ re. 
 

 
Since we understand what s
​ ubdomains a
​ nd c
​ onstructs​ are now, we could use them 
to assemble names for our files by appending the c
​ onstruct​ type to the s
​ ubdomain 
(or element from the subdomain - see the image on the next page). 
 
 
 
Let’s see what some of that might look like in principle. 
 

 
 
It’s a good start, but there’s a problem. W
​ e’re not organizing our subdomains 
properly​. 
 
Things from the J
​ ob​ ​subdomain are mixed up with the U
​ sers​ ​subdomain. That’s 
definitely giving me clutter-y feels. 
 
It’s time to think about naming folders. 
Approach #2: Name folders by Subdomain, and (optionally) Subdomain 
+ Construct 
 
Naming folders by the name of the s
​ ubdomain ​is a great way to segment code so 
that you can focus on one particular part of your project at a time. 
 
Here’s a start. 
 

 
 
That’s better, but you might still feel a little bit discombobulated looking at this many 
files at one time. I like to take the next step of also creating sub-folders and naming 
them by the c
​ onstruct type​. 
 
 
I like this a lot. We talk about it more in P
​ art 3: Structure, ​but this is called 
“Packaging by Component”. 
 

There’s a construct for everything 


If we can’t decide on a good name for a file, it might be because w
​ e don’t know​ what 
type of construct the class in our file actually is. 
 
So beware of naming things “etc-manager” and “etc-implementor”, because when we 
start to do that, files become harder to understand what they’re s
​ ingularly 
responsible for ​at first glance. 
 
If you’re finding that you’re often not sure what type of construct to use, my 
suggestion is the following: 
Learn Design Patterns 
Design patterns tend to be pretty narrowly scoped solutions to common problems in 
software.  
 
For example, when I started getting into D
​ omain-Driven Design​ ​and realized that I 
needed to convert a J
​ ob​ model to different formats (to a Domain entity, to an ORM 
representation, to a DTO, etc), I went looking for a pattern. I discovered that the 
pattern was the D
​ ata Mapper pattern​. 
 
From then on, anytime I realize I need to do this particular thing, I name it an 
“​[Entity name from Domain]Mapper​”. 
 
So dig around a little bit! That’s the best way to learn design patterns. By actually 
having problems that need to get solved, to looking for the correct tool for the job, to 
implementing it, you’ll find that you’ll find that you retain that information much 
deeper than if you simply went through the entire catalog of design patterns. 
 
That being said, the best resources for to sift through are these books: 
 
- Martin Fowler’s book called Patterns of Enterprise Application Architecture 
- GoF: Design Patterns Book 
- PoSA: Pattern Oriented Software Architecture Book  
 
---  
 
Also, if you want to learn how to write cleaner code overall, check out “Clean Code” 
by Robert C. Martin (Uncle Bob). It’s a great read. 
 
Bad names 
If you want to see an entire list of ways to d
​ o evil and keep your job forever, ​check 
out this repo: h
​ ttps://github.com/Droogans/unmaintainable-code 
 

Look out for too many helper/utility/service classes 


It’s easy to call just about everything a “helper”, “utility” or “service”. Understanding if 
something should be a h
​ elper​ comes from having knowledge about the domain. 
 
I’ve talked about this topic quite a bit h
​ ere​ and h
​ ere (anemic domain models)​. 
 
 
 

   
Construct 
What it does 

Constructs are the tools (or patterns) in our software development toolbox that we 
plug together to build web applications (mappers, controllers, views, models, etc).  
 

Each construct is responsible for one type of behavior 


Mappers​ m
​ ap data​ between domain objects, ORM models, dtos and the like. 
 
Controllers​ h
​ andle web requests​. 
 
Domain Entities​ have zero ​infrastructure-layer​ dependencies and d​ escribe the 
modeled attributes and capabilities of real-life entity​. 
 
Repositories​ are responsible for r​ etrieving and persisting domain entities​. 
 
In Angular, R
​ outeGuards​ g
​ uard routes​ and allow for custom logic to be plugged in to 
determine if a route can be routed to or not​. 
 
--- 
 
Every construct should be s​ ingularly responsible for one thing​. A ​Mapper​ should 
never also inherit the behaviours​ of a C
​ ontroller​, and vice-versa. 
 

A construct instance should never be responsible for more than 


one subdomain element 
 
Let’s say we implemented a J
​ obMapper​ like so: 
 
 

 
 
This J
​ obMapper​ is pretty narrowly scoped. It’s only responsible to mapping the J ​ ob 
domain entity. That’s great. 
 
Now, let’s say that we needed to also return the U ​ ser​ that the ​Job​ belonged to as a 
key called o
​ wnedByUser​ in the ​JobDTO​ like this: 
 

 
 
Where the U
​ serDTO​ has the following properties: 
 

 
 
What should we do with our t ​ oDTO()​ method on the J​ obMapper​? 
 
Should we also define how we map U ​ ser​s to U
​ serDTO​s from within the J
​ obMapper​’s 
toDTO()​ ​method like this? 
 

 
 
No​. At this point, we should create another Mapper: U
​ serMapper​. 
 

 
 
And then delegate that responsibility to the U
​ serMapper​ in our J
​ obDTO​. 
 

 
 
Much better.  
What we’re doing here is performing quality control on our architectural boundaries. 

Architectural Boundaries 
 
If we have a construct named "​UserMap​" in an application that trades vinyl (we 
actually will soon , check out ​this repo​), we should be careful thinking about our 
architectural boundaries​ when we mention entities from other subdomains in our 
application, like "​vinyl​" or "​billing​", from the “​users​” subdomain. 
 
Here’s an example of a U
​ serRepo​ interface from my D
​ omain-Driven Design with 
TypeScript course​. 
 

 
 
Yes, this ​is​ a ​UserRepo​ in the ​users​ subdomain, but it seems like the observable 
responsibility is actually to r​ etrieve​ V
​ inyl​. 
 
It would probably make more sense to create a V
​ inylRepo​. 
 
These are the types of constant discussions that we need to have if we care about 
software design and architecture. We’ll n
​ ever​ get everything right the first time 
around. 
 

Why should we care so much about architectural boundaries? 

If we keep our code siloed in architectural boundaries, it l​ eaves options open for us 
in the future to potentially do many different things if our project grows. Some of 
those things are to: 
 
a) delegate ownership of parts of the project to separate teams 
i) If we keep boundaries at bay, this means we’ll be able to break apart 
the application so that separate development teams could set up their 
own version control and testing pipelines. 
 
b) microservice deployment 
i) If we keep boundaries at bay, we can not only separate our code 
logically, but physically too. 
ii) Code can be split into separate repos and communication between the 
deployments could take place over the network (HTTP, RabbitMQ, etc). 
 
Either way, as codebases grow larger, and more developers join our company, we 
look for ways to improve productivity and at scale. Keeping an eye on boundaries 
can make transitions a whole lot less painful. 
 
 

   
Structure 
Where it belongs 

 
Structure ​is most concerned with w
​ here we place files​ and h
​ ow we lay out our 
folders​. Structure is code organization and asks the question, “are things where 
they’re meant to be”? 
 
When our first guesses towards finding a particular file are correct, it greatly 
improves productivity. 
 
When we have to guess and flip through too many files and folders, our productivity 
tanks. 
 
Project size 
This is increasingly difficult as projects grow in size. When projects are small, it 
might be pragmatic to use a flat file structure and simple, yet generic names.  
 
Take this file structure example of a script written to automate users into a 
MailChimp List. 
 
 

 
 
How much can you tell about the project from this structure and the file names? 
 
An assumption would be that the m
​ ailchimp.js ​does the bulk of the work. Maybe it’s 
what actually connects to the MailChimp API. Not sure what l​ ist.js ​is responsible for, 
but since we have so few files, I wouldn’t quarrel too much with this. 
 
As soon as the project starts getting more complex, you can be sure I’ll be looking 
for ways to be more declarative with these files and folder names. 
 

Package by Infrastructure 
This is an important topic.  
 
Most developers starting out, package their applications by infrastructure. This is the 
opposite of packaging your application by component. 
 
Package by infrastructure is when we name our t​ op level folders ​by the construct 
name. 
 
To illustrate, here’s the folder structure of the old project that I was working on that 
spawned my motivation to write this book. 
 

 
 
If it’s not obvious why this is n
​ ot useful​, let me make an analogy. 
 
Imagine picking up a dictionary looking to find a particular word. 
 
When you open the dictionary, it’s not sorted by a
​ lphabetical order​, but instead it’s 
sorted by “the types of words”.  
 
So “long words”, “short words”, “scary words”, “funny words”... 
 
It would take you much longer and considerably more cognitive energy to find what 
you’re looking for. 
 
That’s what we’re doing here with p
​ ackaging by infrastructure​. 
 

At a glance, this tells us nothing about the project 


 
There’s a term called S
​ creaming Architecture​ from Uncle Bob’s “Clean Architecture” 
book (I recommend it highly). It means that when we open a project’s codebase, the 
code should p
​ ractically be screaming at us ​what type of project we’re looking at. 
 
Within seconds, you should be able to determine: “hey, this is a healthcare 
application” or “this is a restaurant app”.  
 
Having code organized by c
​ onstruct a
​ t the top-level doesn’t help us understand the 
project. 
 

   
Features are developed vertically, not horizontally 
When we develop features, it pretty much cuts across the entire stack. For example, 
let’s say a POST request gets fired off by the client to C
​ reate a User​. Here’s how that 
might cut across several constructs.  
 
 

  
 
 
Imagine that all of those constructs are in separate folders, away from each other. 
 
That means, in order to develop one feature, you have to f​ lip between several layers 
of folders​ to find the right construct to edit. 
 
I believe we as humans can only remember at max 7 or so things at one time. So this 
approach isn’t very human-friendly. 
 
So let’s go back to the human-friendly approach. 
 

Package by component 
 
In order words, packaging to be b​ rain-friendly​. 
 
Here’s that same project, but this time refactored to use package by component. 
 

 
 
Doesn’t that tell you so much more? 
 
Package by component for everything 
I used to think that this only really applied to backend code, but now also convinced 
this is the way to organize code i​ n general​. 
 

Univjobs’ React-Redux App Structure 


The entirety of the Univjobs application is split into the m
​ odular silos by “feature”​ (or 
component, as we’ve been referring to it). 
 
For example, the Create Job feature looks like this: 
 

 
 
Everything related to a particular feature (container components, validation logic, 
styles, services, redux, models, etc) lives in a s
​ ingle individual feature module​. 
 
This has made it incredibly easy to identify where I need to go in the project to 
change code. 
 
So here’s my approach for good structure: 
Tips for good structure 
1. Start the first layer by identifying the features (or components or modules, 
whatever you want to call it). 
2. The second layer in holds the constructs. Refer to the construct names here. 
 
 

Nesting rules 
Sometimes, we’re in a feature that is split into several sub-features. 
 
I’ll repeat #1 until I’m at the lowest sub-feature and then implement #2. 
 

Shared things 
Be sure to identify when things are shared and place them in a shared module. For a 
good example of this, see the s
​ ource code for khalilstemmler.com​. 
 
 

   
In Summary 
Name, Construct and Structure all contribute to the readability of your project. As 
projects grow, it becomes harder to keep the same level of productivity up, so 
special attention to these three things becomes vital. 

Names 
What it is. 

What to look out for 


Look out for naming things too generally and assigning the code that lives inside of 
the files way too much responsibility. 
 
For a guide on this, c
​ heck out this article​. 
 

Constructs 
What it does. 
 

Structure 
Where it belongs. 
 
 

A real life project 


I’m working on a Domain-Driven Design with TypeScript course where we build a 
Vinyl Trading Enterprise application​ called “White Label”.  
 
I’ll be putting into practice what I’ve taught in this book, so if you want to see a real 
life example, check out t​ he repo​. 
 

You might also like