
Build Software from Front-to-Back - stepbeek
https://happyvalley.dev/build-software-from-front-to-back/
======
crazygringo
I'm going to disagree with both approaches, and suggest (for lack of a better
term) "middle-out".

Always define the API _first_. Figure out the _information_ necessary, and
make sure it meets _both_ front-end constraints (e.g. no information is
missing, does it need to be one call or multiple calls, etc.) and back-end
constraints (can this be efficient to retrieve from the database, does one
server have all the info, etc).

Once you've verified that the API design works for the needs of _both_ ends,
then you lock that down and let front-end and back-end teams work
independently.

And even if you're coding on your own, it forces you to think about the
information architecture first, which is a good habit to get into so you don't
paint yourself into a corner in either direction.

Front-first risks building an interface which requires data is which is too
complex to retrieve. Back-first risks building the wrong endpoints. API-first
requires you to design for both before you start building.

~~~
pydry
Ugh, last time I worked on a project that did this the API ended up designed
by "an architect" to provide data that the back end didn't have and the front
end didn't want. It was an unmitigated disaster.

Outside in drives a much more effective requirements discussion as you work
your way down the stack. If the front end asks for data that's "too complex to
retrieve" then that's usually obvious from the mock up and it is cheaper to
change it _at that point_ before code lower down the stack has been written.

It leads to much cleaner API design and better negotiations about what should
go where since the written code of the layer above effectively drives the
requirements for the layer below.

~~~
crazygringo
I'm not disagreeing with the architect part -- that's what I meant by "Once
you've verified that the API design works for the needs of both ends".

An architect working in a vacuum is _only_ going to result in unmitigated
disaster in my experience. :)

But I disagree where you say that it's usually obvious from a mock-up that the
backend is going to be too complex. In my experience that never occurs to
people at all. All too often I've seen designers spend _months_ mocking up
fantasy functionality while the backend team is drawing up tables, shards and
microservices, only for it to eventually collide in total incompatibility,
when the front-end developers say "but the back end doesn't let us do three-
quarters of this!" and the back-end developers say "but obviously you can't
get the data that way, what ever made you think you could?"

Forcing the API conversation/specification to happen at the start, rather than
in the middle, forces extreme clarity for both sides, so that necessary
critical compromises are hashed out at the beginning, instead of discovering a
horrible incompatible collision midway through.

~~~
chii
> designers spend months mocking up fantasy functionality while the backend
> team is drawing up tables, shards and microservices, only for it to
> eventually collide in total incompatibility

that's because this methodology is called waterfall, and it has proven to not
work, time and time again.

The project should not start with full requirements - it should start with a
single requirement/feature (even if that feature by itself doesn't fullfil the
purpose of the software). What is the topmost important feature? Do that part
first, and have it working end to end. It should take as little time, and done
as fast as possible. It should allow the design team to create as simplified a
design as possible, and allow the backend to use as simplified a backend as
possible. It should allow testing to be done well (good coverage, good unit
testing etc).

Then once this is done, the client will judge it, and say what can be
improved. Do that one improvement, only, before going back to the client and
repeat.

This has been what most successful projects done.

~~~
crazygringo
Obviously this is a complex topic but this applies equally well to agile as
well as waterfall.

If you're planning your sprint, the point is to figure out the API call first
together, before work starts on either front end or back end.

Real-world projects exist on a wide continuum between "maximum agile" and
"maximum waterfall", and usually fall somewhere in between. You can't build
AWS or Google Search purely out of 2-week sprints with no further advance
planning or specification. :P

------
UglyToad
Always interesting to read how others work.

I'm a backend dev who does quite a bit of frontend though I deeply dislike the
current state of frontend (bring back Webforms)

For me it all starts with the database, always. Code, ux, network is all
ephemeral. The schema, the invariants and the data are forever. (this is also
why I think microservices are often the wrong approach, you're solving a code
problem at the expense of the data)

I've been thinking about the concept of code as pipes for data and the
(incorrect) emphasis we place on code. This is why something like MongoDB
never clicked for me, code is worthless without the data it operates on and
ensuring the quality of that data takes priority over anything.

Of course you need to know roughly what the data will be used for and
approaching it database first can result in some nasty surprises if the
requirements change, but the rest of the code will rot and be replaced far
sooner than the database. Given the churn on frontend the schema in the
database will probably see 5 front end frameworks come and go.

Edit: having written this I realised this is also why I don't like or
understand letting your ORM handle database migrations. The code is built on
top of a dependable database, letting it inform the design of the database is
completely the wrong way round, in my opinion.

~~~
lonelappde
What goes in the database? The whole universe? What do you leave out? What do
you denormalize and index? These questions are answered by the frontend.

~~~
wolco
You store the entire universe or whatever reporting requirement demand. You
define the database structure based on the requirements of your business
logic.

The frontend requirements can help define what api's are required but if you
treat your database as dumping tables you limit what your data can do.

You add can add and remove indexes at any point. If you made a bad decision or
no decision you would add those when more information is available.

------
gavinray
I would disagree, having been on both sides of this half a dozen times each.

When you write front-to-back, you don't get an immediate sense of what the
deeper relationships and nuances of your data models are going to look like.
You're designing for what you immediately think you want to see.

This approach can work well, until you run into things that end up being a lot
more difficult to implement behind-the-scenes than the data you just expect to
appear on the page in front of you.

Personal experience/preference, but the thing that has (almost) never led me
wrong was doing a walkthrough of the domain of the application, and then
thinking about what the client-side pages and functionality are going to look
like (page-by-page, user stories), and then implementing the backend. Finally,
wire up the backend to the frontend mockups/design.

For more complex systems, there are things that need to be ironed out in their
entirety and have their modeling/relationships, and functionality proven on
the API side of things before you decide to start writing UI elements for
them.

On the flipside, having worked on projects where there have been major, multi-
month setbacks, it was nearly always because the models/domain weren't well
thought out and it needed major components to be re-worked (either UI or
backend) before we could proceed.

~~~
thanhhaimai
Having TL'ed both Frontend and Backend at Google, I don't think it's front
first or back first. It's "contract first", and here is why:

\- Assuming PRD and UX are ready. The Frontend team take a look and come up
with the Frontend data model they want. The focus is on making sure it's
easiest for them to maintain and develop the client side.

\- The Backend team take a look and come up with the Storage data model that
is flexible enough for short term future. The Backend should anticipate the
growth of the product and try not to be put in a situation where they have to
redesign the database/infrastructure.

\- Then both teams meet to negotiate the "Contract", which is the API layer.
In some case, the API is more similar to the Frontend data model. In some
case, the API is more similar to the Storage data model. In other case, there
is a translation layer between Storage <-> API <-> Frontend (not as desirable,
but not the end of the world). There are standard on how API should be
designed ([https://aip.dev/](https://aip.dev/)).

\- When the contract is established, both teams can run more independently to
each other, release at different times, and only needs to sync when there is a
need for the contract to change. The API is designed to be easily extended,
but not changed or deleted. The Backend team doesn't care if the Frontend data
model exists. The Frontend team doesn't care what kind of Storage the Backend
uses. It's an abstraction.

The complexity of the project can't be entirely eliminated. A good TL makes
_explainable trade offs on which parts of the system bear the complexity_.
It's their job to think not only about the architecture, but also how the
development can be sustained in the future. This is especially true when the
product is developed by a medium-large team. The focus is no longer on having
the leanest/optimal code base. The focus is on making sure many parts of the
system can move more independently, in parallel, and that it's scale-able to
the growing business needs. It's a classic case of Amdahl's Law applicable to
real life.

Of course, this is not always applicable to small projects that is never
intended to have more than a couple engineers. Even then, when I work on solo
full stack projects, I still unconsciously do this contract first approach.

~~~
thinkloop
> Then both teams meet to negotiate the "Contract"

What you describe is pretty much front-end first with the tweak that when the
teams negotiate, the burden of proof lies on the back-end. The back-end should
contort as much as possible to satisfy the needs of the front-end, allowing it
to remain as clean and nimble as possible. Only when it matters should the
back-end be able to materially affect the shape of the api. In most cases
"mattering" means balancing the needs of this front-end with another that also
consumes the back-end.

------
pjettter
I always write "front-to-back". I write the code that uses a module,
abstraction, api, etc. Then I write that layer until the code works. This goes
on layer to layer.

To make it not become a tour-de-force, I start with a golden path, then
various aspects (validation, additional operations on data besides rendering,
etc). If the data doesn't exist yet, it's mocked. Then later, it's implemented
(or made 'live') according to the mocked "schema".

It's not exactly TDD (I rarely write a test except for integration tests or
the occasional "let's make sure it's not off-by-one"). It's not top down
either, exactly. Perhaps you could call it "needs driven development" or "user
driven development". You need it from the start and you use it as soon as
possible. From then on, it's just improvements.

If you work back-to-front, you won't have anything working until late in the
game. You're constantly imagining all the non-consequential "what-ifs".

But in a way, front-to-back is like TDD except you're not testing via unit
tests. You're testing by using. And you will be using it so much that it will
be tested thoroughly. You iterate continuously while the top layer / front end
keeps working.

Sure, there can be an overarching design. There can be an architecture. There
should be. But after that, it's about slowly molding the system towards that
design. If you have understood the design, you know when you're veering off
course. For sure, it's not like building a bridge.

~~~
stepbeek
I love user-driven design as phrasing. Although I neglected to mention it, I
quite often write basic cypress [1] tests early on to get a TDD-like
experience.

> For sure, it's not like building a bridge.

It's super interesting how many processes are inherited from traditional
engineering.

[1] [https://www.cypress.io/](https://www.cypress.io/)

~~~
pjettter
Hm. Maybe. In my experience, tests is just more code, more bugs, more
maintenance. If you need to write many tests, you're writing your code wrong.
"Just my opinion, man" ;)

------
jcadam
As a "full-stack" developer who started out on the backend and took on front-
end work later in my career, I used to build back-to-front. You generally end
up with a cleaner, more scalable, and stable solution. That nobody wants. I've
learned this lesson the hard way.

Start with the UX and work your way backwards. I don't like it from an
engineering perspective, but it's the only way to go to build products.

Users just do not care what kind of horrible kludge is running behind the
slick UI.

~~~
ab8
Agreed. Unless it is a pet project for no one but yourself, the biggest
challenge is figuring out what the problem is and arriving at a solution that
works for the user.

Since neither the user nor the programmer knows the right answer, we have to
work iterations in. Each iteration is followed by feedback. Given how often we
end up being completely wrong, it is best to get to the first feedback as
quickly as possible.

------
BrainlingPdx
Not trying to be mean, but you really don't make any sort of case for doing
this here. You just note you did it because you've become more comfortable
with the front end. It also seems like you're designing and implementing an
entire system by yourself in which case you can do whatever you want. When
dealing with a team, and an API layer that has to be used by more than just
your client, I don't see any compelling case presented here to start designing
API's specifically for UX use cases.

~~~
DEADB17
The techniques are not mutually exclusive, it depends on the context. When you
don't have a clear idea of the requirements starting "front to back" helps to
understand and gather them while building something that validates them. For
your example "back to front" sounds like a better fit.

------
wheresvic4
There is actually a "Design outside-in, develop inside-out" theory that I
found illustrated once in an HN comment. It rang so many bells for me that I
tried to write it out[1] so that I could understand it better.

[1] [https://smalldata.tech/blog/2019/01/16/design-outside-in-
dev...](https://smalldata.tech/blog/2019/01/16/design-outside-in-develop-
inside-out)

------
SnowProblem
In my experience, the only reliable way to design an API is to cycle through
"hats" like gradient descent until the API stops changing. There are no
shortcuts! And there are more hats to consider than just frontend and backend.
There's security, testability, teachability, performance, upgradability, there
are likely many uses for the API, and more. This is why API design is hard.

------
ravenstine
Just go with an approach that it's your talent stack.

For instance, if your product has a lot of UX nuances, and you aren't
artistically inclined, it can make sense to build out the interface first,
work out the UX, and then proceed to the backend from there. However, someone
with the ability to build wireframes should probably do that first, work on
the API, and come back to the frontend.

I'm good at backend stuff, but have a hard time keeping interest in a project
I'd I spend all my time in the backend. The frontend keeps me interested
because it's visual and helps me see what my goal is.

------
MattGaiser
The other reason to design front end first is that the client mostly cares
about that.

Plenty of projects I have worked on will sacrifice anything to have a frontend
match a drawing. A friend currently works on a project where finding the
purchase button requires you to scroll two inches in a widget where they hid
the scroll bar to see the purchase button on a standard 15 inch laptop (as the
mockup was built on a wide monitor).

On my current project, if there is so much as a semi-colon out of place,
communications will see it. Forget a background process? Nobody notices that.

------
stepbeek
I'm a back-end dev who's transitioned to being more full stack in the last
couple of years. I've written a little bit here on a workflow that I kind of
fell into that I've corrected recently and figured it might be useful for
other people in the same boat.

------
gfodor
Here's my post about this... from 13 years ago :)

[http://codingthriller.blogspot.com/2007/12/client-first-
deve...](http://codingthriller.blogspot.com/2007/12/client-first-development-
with-rest.html)

------
disposedtrolley
When I worked on full-stack projects, I'd always start by understanding _what_
the frontend needed to display but not necessarily _how_ , which translated
well into a database schema and some type definitions.

I would then mock these out so I could start prototyping the rest of the
frontend. This usually involved setting up UI components, pages, and linking
them up with actions. The goal of the prototype was to demonstrate a few end-
to-end (albeit mocked) flows to the user. With the flows and data types in
place, it was trivial to design a set of API endpoints and build out the
backend.

------
choward
I agree with this article. There are many developers who think of the database
schema first especially in ORM heavy frameworks like rails. Also because of
this a lot of people confuse data modeling with the database schema.

------
whateveracct
I think going in either direction is gonna have flaws. Sometimes frontend
informs the backend (rich user flow -> data dependencies) and sometimes
backend informs the frontend (often suggesting more composable and
maintainable designs)

I've worked on projects that were very front-to-back and without having a
constant eye towards the backend, the UI requirements would have ended up
dictating a non-composable, non-extensible backend. But I guess applying taste
and knowledge to these problems is kind of the point of being "full stack"

~~~
megameter
There's something to be said for treating it as an iterative process in
layers. At first you have no specification, then you have a bad specification,
and then increasingly good ones. The final implementation itself comes from
having a good spec, and when you have that it should not matter which you
start with.

The trouble comes in keeping a clear idea of what an iteration is supposed to
test or accomplish beyond "makes it better" \- and an end-to-end iteration is
expensive. That is where the idea of putting the data model or UI "first"
develops, since it lets you build from the technical details towards the
concept, as a way of constraining and filtering your thinking.

Something I want to try but have not gotten around to willfully doing, is to
treat the initial design stages as an exercise circuit of focusing on each
layer for a limited period of time each day, rotating from one to the next.

I'm pretty sure that you could get some great results if a work week were
spent doing a four hour cycle, with one hour each thinking and researching
data, interfaces, UI, and premise/market.

------
MattyRad
Not only does this approach help you determine what the backend actually needs
to do/acquire, it has the added bonus of _getting product teams to iron out
critical business logic_ (which masquerades itself as the frontend) while you
transition to backend work.

This is a huge timesaver, because if product decides to change the frontend,
you haven't committed huge resources to the backend. Building software front-
to-back helps people _agree_ on what needs to get built.

------
jordache
isn't everyone building front to back?

You firstly establish a purpose of your solution. Thinking the job to be done,
the users, the features..

Then you do a design. Likely you have a design team, that does research and
creates wireframes or high fidelity mock ups.

Then you establish requirements for the various layers in your stack.

So what I described is a fairly typical process. It is front to back.

I can't imagine someone building a product, starting with a myopic focus on
the database, followed by rest contracts, etc...

~~~
Silhouette
There are plenty of reasonable ways to build web applications. If the process
you described works for you, that's great, but others do find different
strategies effective too.

For example, your process puts great emphasis on the visual design. To me,
that aspect is almost entirely orthogonal to the software design. That's not
to say it isn't important to getting a good end result, but once you know what
interactions and information architecture you need, how you draw things on a
screen doesn't affect anything else much.

I suspect a lot of teams would start with the external models like
interactions and information architecture, then move to internal models like
database schemas or REST APIs, and then implement the former in terms of the
latter.

~~~
jordache
good point, if you are building software for other systems to consume, the UX
portion is not applicable, nearly as much

------
skaber
I think the issue here is that there's a sole developer working on the whole
app with the difficult choice of choosing where to start. I think that
creating a design that covers most test cases of the app would then let you
start from either section of the app. I am surprised OP doesn't mention
anything around GraphQL (why or why not it could help).

~~~
stepbeek
> creating a design that covers most test cases of the app

I consider this be a very hard thing to accomplish. There are generally too
many unknown unknowns. I almost always need exploratory work to figure things
out.

------
dwaltrip
I think a highly effective strategy is an outward-in somewhat recursive
iteration from high-level details towards a polished, robust solution. Of
course, the first step must be some sort of sketch, however minimal or vague,
of the user-facing functionality -- "user" can mean a number of things here,
depending on the application -- or else you have no idea what you are doing.

Something like:

1\. High-level, low fidelity sketch of the user stories and the UI

2\. High-level, low fidelity sketch of a possible database schema

3\. Refinement of UI and user stories

4\. Mid-level sketch of possible API

5\. Refinement of DB schema and backend models

6\. First pass implementation the UI

7\. First pass implementation of the backend (db + models + API)

... A few more iterations, bug testing, and voila! Of course, minor variations
of this could also work well. For example, 6 and 7 could probably be easily
switched.

------
pm
Build software through "meeting in the middle". Define the front (user
interface), define the back (data structures), and then progress towards the
middle.

After all an interface is, by definition, where two things meet and interact.
There are too many unknowns otherwise.

------
kumarvvr
I have a mindset to develop the back-end first and then go for the front-end,
and I usually do in that fashion. Theoretically it reasons as right. However,
I always find that when developing the front end, I inevitably have to add
functionality to the back-end.

Recently I started learning ASP.NET Core Razor Pages and found it quite
refreshing that the line between front-end and back-end is very much blurred
and somehow, the cognitive load is much lesser, than compared to, say, and
Angular + API stack.

I felt the same for some of the projects I developed using Django, though,
Razor Pages is even more merged when it comes to front-end and back-end.

------
bingo_cannon
It's what I call customer experience design. You can build this in terms of
user stories, UI mocks, OpenAPI spec etc depending on your customer. This
makes the expectations from the API interface very clear. Of course, it may
also mean that I'd have to deviate from pure REST but that's easy when you see
the customer value. Then the tradeoff between fast, easy and cheap is
restricted to components that don't impact the end user and can be changed
later. The last thing I'd want is to change my customer's workflow because my
entity relationships change.

------
aryehof
How foreign the problem space is for me, and how focused much of the audience
on HN seems to be on web/database software.

I'm involved with the two biggest types of software in general computing:
control systems and large complex commercial transactional systems.

The former don't feature a UI or a database. While the latter have the primary
issue of modeling a complex problem domain.

That complex model is by necessity produced without regard to any particular
human or system interface, or data persistence. Are such concepts so alien to
audiences here?

------
HatchedLake721
That’s where [https://miragejs.com/](https://miragejs.com/) helps. I’ve built
few fully functional prototype apps with full UI/UX without a single line of
backend code and with front-end acceptance tests.

If you’re prototyping greenfield product, it’ll morph many times as you build
it. Once you’re happy where it is, and you’ve stabilized on data structure
(not database schemas), then just start replacing mocks withr your API calls.
Acceptance tests will tell you if you’ve done it right.

------
agentultra
I would be careful: if you're designing a REST API to be consumed by other
developers and applications there are conventions and patterns you should
stick to.

If your product or service doesn't exist without the UI then why bother with a
REST API at all? Write a nice stateful application that is rendered server
side. There are great frameworks for this in almost every language.

A good REST API is consumed by applications and developers and they expect you
to stick to the conventions or they will turn to another provider if they can.

~~~
bdcravens
In REST, the API _is_ the front-end. You can still do the front-to-back
approach, mocking the data etc until you get the interface right. Then you
work on how the application delivers data to the interface, which is the
backend.

~~~
agentultra
If you are designing a REST interface then I recommend a domain driven design
approach. I've had a fair bit of success with that.

I also like to think in terms of denotational semantics which works rather
well with REST APIs. The entities represent the domain objects which model
what the system does. The state transfer operations become the game between
the client and the system. If the domain maps cleanly the client and the
server never have to guess or assume the state of the other. You can follow
the operations from the URLs (HATEOS, etc).

What I find happens to some systems where the design is _driven_ by the UI are
domain models that span both the client and the server. This leads to routes
that fill data for specific UIs, entities that have different representations
based on which route they're fetched from, and the dreaded "RPC over HTTP,"
that the OP seems aware of.

A lot of this can be avoided if you never intend to expose your REST API to
external developers. Just don't have one. Less to worry about.

Designing front-to-back that way makes a lot of sense. I just find that if you
do that from a UI through a REST API that a lot of teams and developers skip
on maintaining the REST conventions and then end up sad when their project
becomes difficult to maintain and onboard new developers to.

------
zuhayeer
I like building pretty skeletons of a product first, which helps to dream up
natural interfaces uninfluenced by the structure of a "backend". I've seen a
lot of people conforming their frontend to some predetermined backend
structure completely ruining the end user experience.

Also found there to be a motivational aspect to this. Since I can't push the
buttons or turn the knobs because its just UI at this point, I can't help but
breathe life into it so that I can actually use it.

------
ken
That’s what is usually called “top-down programming”, right?

------
fioan89
Casey Muratori once made a similar point in
[https://caseymuratori.com/blog_0025](https://caseymuratori.com/blog_0025).

Personally I think the approach is very similar to TDD and so for some of us
it's easier to dive first on the front-end. It's like translating user
specifications to tests and then writing the code for the tests to pass.

------
cjfd
I think one should start with whatever extension in the API between front and
back is needed. That is the point to make the compromise between the two. On
the one hand one wants to make exactly the data that the front end needs
available but on the other hand one wants something that makes sense to
request to the data. Once one has that compromise front and back end can be
developed separately.

------
chasing
Okay, but this is one of those "I've discovered I can work like this" sort of
posts that doesn't take into account the vast range of projects and project
teams.

So, sure: It's useful to be aware that you can work front-to-back, back-to-
front, front-and-back-to-middle, etc. But you still can't make this choice
without consideration and one size absolutely does not fit all.

------
atlgator
How do you build your service layer first but your APIs last? Aren't APIs part
of the service layer? The interesting thing about DynamoDB single-table design
that I'm really starting to like is it forces you to start with API calls. I
literally start with an excel spreadsheet of API declarations and
corresponding HASH/SORT keys.

------
DevKoala
Everybody is sharing how they go about their app design. This is the order
that works for me:

1\. Data Models 2\. Data Stores 3\. Business Logic 4\. Processes 6\.
Application Interfaces (resource level) 7\. Presentation Interfaces 8\. UI

------
c22
I like to build software "middle-out" from the interfaces.

------
zubairq
Totally agree with this. At yazz.com we take exactly the Visual Basic approach
too of building software from front to back and it works for simple things

------
aWidebrant
I think a better approach is back-front-back, or front-front-back; or front-
front-back and then side-to-side.

------
Vysero
I would figure you simply break it down into three components. Front end
(presenters) middle (plugin's) and back end (managers). The managers know
nothing of the front end and the presenters know nothing of the managers. That
way you can always swap out your UI for a different one, right?

If this is the case then you should develop the plugins first.

------
crdrost
Oh man, Stephen, you're gonna get a lot of conflicting views on this one,
posting it here. :)

For what it's worth I am on your side given a bunch of constraints that match
my prior experience. So I have typically worked on small scrappy IT teams at
companies that are working on something else -- whether maintaining a Roku
channel or putting together the heating ducts and plumbing assemblies for a
building or making sure your marketing companies are not making illegal
promises to customers that you can't fulfill. Inside those teams there is some
sort of pain that we are meant to alleviate -- say, executives are spending
too much time telling accounting in slipshod fashion their estimates for how
much money they anticipate will be coming in from various prospective
contracts, and roughly when it will come. The idea is born: an app which
accounting can grab information from, automatic emails to the executives, and
a user interface that fits the executives like a glove so that this is a
better-than-painless experience for the people who actually use it.

Given this context, I agree that you want to repeatedly iterate on the
frontend of the product over and over until the actual users start to change
the nature of their complaints. Their complaints started with: "I need to put
in a Flotsam which is also a Jetsam, how do I do that?" / "What do you mean, I
thought flotsam and jetsam were different things?" / "Well for established
Wakes they are, but not when we are looking at a new Surf. Then sometimes they
are different but sometimes something is both, until that Surf becomes a
Wake." So it is a failure of your domain model to match theirs.

And you are right, being able to have that domain model in a couple of JSON
structures really helps with your ability to refactor everything around,
especially if you have a type system which can just tell you "look that
function is still designed around the last iteration and it's gonna break now
with this new structure."

Those problems are really hard to fix when that data structure has already
been broken apart into tables to be stored in a relational database and then
ossified into various Data Access Objects and API calls which perform the
updates.

By contrast with this approach you have a time where the product has succeeded
in matching the user's domain model, which comes when they say something like
"hey I changed this in this other system but I am not seeing the change in
your app" or maybe just "hey I ran into a bug where it looks like the software
is no longer saving my changes." Something that reveals that they think this
software is in beta rather than pre-alpha development. You have a conversation
like, "It was never saving your changes, that's a forthcoming feature." / "Uh,
how was this ever supposed to work if it didn't save my changes?" / "No, like,
that has been part of the design from day one, but that turns out to be a
really costly part of the development effort so we wanted to get you to sign
off that this is exactly the app you want before we start to build that layer
of persistence." / "Oh. Well where can I sign up? I really want this app!"

Also really good for the idea of "build one to throw away", once you have
fixed up your domain model then it can be nice to start from a clean slate.

Let me also say where you are limited: sometimes you do have a reasonably good
guess at the domain model. For example you might be doing anthropological work
as a developer, sitting in on meetings and getting a sense for how people talk
about a system, before building the app. Or, you are interfacing with an
external API and its domain model is presented to you directly in its
documentation. Or, you are designing a game engine and the decisions are up to
you -- the "users" are people who will have to play the game later.

Here it is helpful to build back-to-front. In fact there is a really nice REST
principle which you may wish to emulate if you can, called HATEOAS. If you can
do it, it makes things so much simpler. The basic idea about HATEOAS is the
exact inversion of what you are saying: a polymorphic frontend, rather than a
frontend which knows what API calls to make and in what sequence. So the idea
is to have an intentionally crappy frontend -- it is crappy because it is
generic, the backend tells it "here are the many different sorts of objects
tracked by the system, and here are the things you can do with them," and it
configures up a crappy UI based on this skeleton which the backend gives it.
UIs created procedurally by robots reading data structure descriptions will
never be as pretty and fits-your-hands-exactly as ones you create yourself.
And the key technology which enables this front-end polymorphism is precisely
linking: a web browser is able to show all web sites and is agnostic about how
exactly everything connects because the web server tells it how everything
connects. So if you have a survey app, when you get a survey from the backend
the backend also tells you something about "to submit a new response to this
survey, POST it to this URL, and validate the contents against this schema
first." The crappy UI probably shows you the 10 questions for the survey up
above, and then down by the "submit new response" form it contains 10 answer
fields and you have to scroll between the top and the bottom for each
question. Very inconvenient, because it is generic.

But on the flip-side, you usually get a good-enough-for-developers-for-now UI
on the frontend, and now you can modify the domain model and services purely
on the backend.

My white whale is probably to combine both of these together someday. :)

~~~
stepbeek
Hey thanks for the in-depth feedback/discussion! I've definitely fallen prey
to the anti-pattern you lay out here. And it's super hard to not fall in to a
kind of sunk-cost fallacy where you begin to limp along until eventually
giving in and - as you mention - throw it out to build with a better
understanding of the domain.

> nice REST principle which you may wish to emulate if you can, called
> HATEOAS. If you can do it, it makes things so much simpler. The basic idea
> about HATEOAS is the exact inversion of what you are saying: a polymorphic
> frontend

Huh. I'd never really thought of HATEOAS in this way. I've used it before to
build an API that can be consumed by another service in a flexible way, but
have never really reached for it when building a UI. I guess this would solve
the problem by only guaranteeing relationships rather than guaranteeing the
full API?

This would definitely protect against churn when the structure of the URL's
change, but doesn't this still depend on having a solid understanding of the
domain from the get-go?

~~~
crdrost
Look at it a different way: why is our domain model hard to change?

Is it, I suspect, mostly because we failed DRY and repeated ourselves at the
various layers? (i.e. our domain model is echoed in our DB, Redis cache, API
structure, App structure, stylesheets...)

If that's the core problem, it's solvable two ways... an app with no backend,
or a front-end that is fully generic serving up a backend that calls the
domain model shots.

------
Beefin
all software is build for users, and users interact with the front end. it
makes sense to define the requirements with the front end and iterate until
its ideal before starting any backend.

------
Kagerjay
I don't think front-to-back or back-to-front are correct. From my experience,
it's always from what I've seen _outside-in_

This means understanding the problem domain. What does the app solve? Better
yet, how does the app either (1) save money/resources for the problem, or (2)
generate revenue streams?

When you start from this approach, things become much more clear. Generally
speaking, start with the UX low fidelity wireframes first. What are the user-
stories for the user? Can they log in? Can they do some CRUD functionality
relative to the problem domain?

Okay, what data does this user need for these pages? What sort of user-
activity are they going under? Create a set of datatables describing the
problem domain.

It needs a user table? check. It needs a license table? Just map out all the
data needed, and group them into appropiate tables.

Fromo there, map out the relationships in a relational format to get a better
prospective on the bigger feature

Are these features even needed according to the frontend? Okay, go from there.
What is the cost to implement each feature, and how does this impact the
development velocity / budget of the project? Go and find the sweet point of
what's defined as a MVP, and then proceed to figure out what a stage 2 looks
like.

Does the original data model have a migrationary upgrade path? Imagine if your
developing the backend. Do you forsee problems running the migrations?

Now you need to think about scalability and whether that actually matters
here. Changes are it doesn't for the vast majority of apps.

Do you need subscribers to aggregate bulkInsertions to the database? Do you
need a redis cache to prevent unnecessary calls to database? Or do you need
something more complex, because the end user is a developer and your providing
a high scalable Web API service?

Just keep cycling outside-> in until you've satisfied all the results into a
proper MVP database and a MVP UX pen paper design.

At this point, you'll want to define the API and how the frontend will consume
it. How will the backend handle it? For instance, if you spec it graphql,
prepare for a world of pain on the backend and an easy life on the frontend.

You should think about your API design, and use design patterns to think about
how you can keep the frontend as simple as possible. The state of truth should
of an application should live closest to its data source(s), so tread with
this path in mind. Sometimes the frontend does the same work (e.g. financial
calculations) to reduce the total number of calls to the backend. You might
want to consider everything else here at this point, e.g. whether websockets
are needed etc. And other factors in the application such as third party
providers.

There's many right solutions to a problem domain, but there are just as many
wrong solutions as well. Go from the business side first, and go outside-in.
The best answer is the simplest one that satisfies all criteria, both in UX
and how scalable it needs to be

------
ohvigrinia
I've got a way of doing it, where the server is basically just consisting of 4
types of endpoints:

\- CRUD on table records, which makes the data schema independent

\- Actions which can update multiple tables, call 3rd party etc

\- Queries which can go more complex things than GET or GET list, such a
search, or filtering, or sorting

\- Selections, which are gets or queries run over multiple tables and
combining the results

I'm addition each endpoint returns in JSON, but can have a

/with/:view

suffix attached to template that into HTML

I find this organizes well and covers all use cases

If anyone wants to see a Node template of this, it's

[https://github.com/cris691/servedata](https://github.com/cris691/servedata)

