Don't waste your time building the development environment. Technology to start development at lightning speed by making Docker Compose “disposable”
"It took me half a day to build the environment" is the laziest confession an engineer can make. Every time I buy a new PC, I repeat the hellish setup process, and in the end, I get cursed with the fact that my PC doesn't work. Quit such useless work now.
Docker Compose is more than just a container management tool. This is a weapon for winning the most powerful right: ``Anyone can start development anytime, anywhere, with a single command.''
1. Throw away the negative legacy of “manual migration”
Anyone who bootstraps a container and then does manual work like, ``Oh, I need to do some migrations'' is throwing away the productivity of their team. That's not work that humans should do.
Use the `condition` of `depends_on` to build a system that runs the migration the moment the DB is ready.
`
services:
db:
image: postgres:15-alpine
health check:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
environment:
POSTGRES_DB: dev_db
app:
build: .
depends_on:
db:
condition: service_healthy
# Launch the app after migration is complete
command: sh -c "npx prisma migrate deploy && npm run start"
`
With this, by the time you hit `docker-compose up`, make a cup of coffee, and come back, you'll have a perfect environment with a DB and schema in place right in front of you. This is the correct direction for "engineer laziness."
2. Why are your builds slow? Blind spot of “.dockerignore”
90% of people who complain that "builds are slow" are skipping `.dockerignore`. Sending `node_modules` or `.git` to a container is like running a marathon with a heavy load on your back.
If you mix unnecessary garbage into the build context, Docker will send several gigabytes of data to the daemon each time. This is the true identity of the "Road of Death."
Golden rules of `.dockerignore`:
node_modules
dist
.git
.env
.DS_Store
*.log
`This alone will dramatically reduce the build context sending time. It's obvious that it feels twice as fast. Many of the ``mysterious build failures'' that beginners stumble upon begin with cache contamination due to lack of this ignore setting.
3. Manage initial data input using “code”
Placing and operating `init.sql` is fine on a small scale, but it becomes a hindrance during development when the schema changes frequently.
Use ORM (Prisma, etc.) to write a script that injects the seed value when the application starts. Since it can be synchronized with type definitions, script modifications can be completed immediately even if the table configuration changes.
// example seed.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
await prisma.user.upsert({
where: { email: '[email protected]' },
update: {},
create: { email: '[email protected]', name: 'Admin' },
});
}
main().catch(e => { console.error(e); process.exit(1); });
`If you incorporate this as a post-migration task, you will never have to worry about DB consistency again.
4. Don't complicate it, keep it simple
Technical articles on the market discourage beginners with harsh words such as ``Let's introduce Kubernetes'' and ``Let's turn it into microservices.'' However, in personal development and small-scale products, excessive abstraction is a bad thing.Use Docker Compose to complete the environment and make it disposable. This alone will dramatically improve your development experience (DX).
One final piece of advice.
The criteria for selecting a technology is not ``how popular it is,'' but ``how easy it is to slack off.'' Docker Compose is not the place to put effort into writing configurations. Think of it as the ``strongest switch'' to start development in a brain-dead state.
Starting tomorrow, we should have a greater sense of crisis about the fact that we are spending more than a minute building the environment. Automation is for lazy and smart engineers.