What I learned while putting together my IDP (Individual Development Plan)
Source: Dev.to
Definition
Based on these reflections, I defined my initial objectives:
- Improve my technical skills
- Document the entire project in English
Defining the subject wasn’t simple, because I tried to consider not only my own development but also how the IDP could add value to the company. I wanted something useful, applicable in my daily work, and that would help me make more informed architectural decisions in the future.
I thought: working as a full‑stack developer makes it impossible to know everything, but mastering architectural principles makes all the difference, regardless of the technology stack.
So, I chose to study and apply SOLID (Single Responsibility, Open‑Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion) in practice.
From this motivation I identified a third objective:
- Become a developer capable of applying best practices from the idealisation step of a project
My main motivation came from experience. In many projects I had no mentor and learned by making mistakes while delivering the best I could in the shortest time possible. Understanding SOLID better would help me build more organised and scalable systems, directly improving the quality of my work.
Planning
I organised a list of stacks and practices that I wanted to apply:
- Laravel – using Eloquent (already part of my routine). I will focus on concepts and architecture rather than reinventing established functionalities.
- Vue.js – with the Composition API.
- ESLint & Prettier – to ensure the code follows standards without triggering IDE errors.
- Service Layer – I was unsure whether to use a Service Layer or Repository Pattern; I chose the Service Layer (explained in detail below).
Not everything I defined at the beginning was delivered (e.g., authentication, CORS, deployment, git hooks). I plan to implement those later and will focus now only on best practices and architecture.
Project subject: A map of urban legends – a vehicle to apply best practices, refine my Laravel and Vue.js skills, and deepen my understanding of SOLID principles.
Practice
Why the Composition API?
I started with Vue.js using the Options API, but in some projects the complexity grew together with file size. Switching to the Composition API on ongoing projects made the experience much smoother, as it facilitates reuse and organisation.
Applying SOLID principles to the front‑end isn’t obvious, but I focused on separating responsibilities and making the code reusable.
UI components should only handle UI
I created a src/api/ folder containing:
src/api/
├─ connect.js // configures the connection to the API
└─ legend.js // queries the API endpoints
Each file has a single responsibility.
The components depend only on the functions exported by legend.js, not on Axios directly. If I replace Axios with GraphQL, nothing in the component needs to change.
With this structure, the UrbanLegendMap.vue component only handles UI (Leaflet), consumes domain functions, and does not contain any HTTP logic.
Why the Service Layer?
Changing the ORM in a project is difficult, so implementing a Repository Pattern would add an unnecessary layer and duplicate what Eloquent already provides.
Therefore, the Service Layer is responsible for business decisions, handling approaches, and containing reusable logic – i.e., the business rules.
Each class should have a single reason to change
The controller only receives the request, calls the service interface, and returns an HTTP response, e.g.:
public function store(StoreUrbanLegendRequest $request)
{
$legend = $this->service->create($request->validated());
return (new UrbanLegendResource($legend))
->response()
->setStatusCode(Response::HTTP_CREATED);
}
No validation logic or business rules belong in the controller.
When a new legend is created, a slug is generated for URL access. This responsibility is assigned to the Model.
Thus:
- Validations → Form Requests
- Business rules → Service
- Slug generation, UUIDs, relationships → Model
Each part of the system now has a well‑defined responsibility.
Open for extension, closed for modification
The controller depends only on the service’s interface, not its concrete implementation. If we later migrate the service to an external API, we simply create another class that implements the same interface. The controller remains unchanged, and both the controller and the new service share the same logical contract.
Testing features can be beneficial
I usually test only the service or use‑case layer, but because the project is well‑structured I added both feature tests and unit tests to verify the behaviour of the whole stack.
Feature Tests
I can test the complete flow — route, middleware, request, service, model, and resource — for example:
public function test_validates_required_fields_and_returns_422(): void
{
User::factory()->create();
$res = $this->withHeaders([
'Authorization' => 'Bearer ' . $this->token,
])->postJson('/api/legend', $this->payload([
'title' => '',
]));
$res->assertStatus(422)
->assertJsonValidationErrors(['title']);
}
This doesn’t mean I’ll always test features, but since my front‑end depends exclusively on the external API, it was important to verify that the response follows HTTP principles and to help me write the documentation.
Unit Tests
Unit tests validate the business rule in isolation, for example:
public function test_list_returns_filtered_legends(): void
{
$this->service->create($this->payload([
'title' => 'Lenda - Brasília',
'city' => 'Brasília',
]));
$this->service->create($this->payload([
'title' => 'Lenda - Florianópolis',
'city' => 'Florianópolis',
]));
$results = $this->service->list(['city' => 'Brasília']);
$this->assertCount(1, $results);
$this->assertEquals('Brasília', $results->first()->city);
}
How the IDP Changed My Thinking
Throughout this Individual Development Project (IDP) my main objective was to improve my technical knowledge. I:
- Studied each step and implementation, asking why behind every line.
- Consulted many articles for both theory and practical examples.
- Built a project applying SOLID principles, discovering that every architectural decision impacts the whole system.
New Daily Questions
Before writing code I now ask myself:
- Who is responsible for this?
- Does this class have a single reason to change?
- Are there any unnecessary methods or functions?
- Can it be extended without breaking?
- Will I have a headache when maintaining it?
These questions have become part of my routine. Choosing SOLID as my main topic gave me a mindset that will accompany my professional life beyond this IDP.
Although not all planned items were completed (e.g., authentication), I consider the IDP successful. It gave me technical maturity and a solid understanding of how to structure a project from ideation onward—not just learning a technology, but learning to think about architecture intentionally.
Takeaways
- Good practices don’t depend on the stack; they depend on conscious decisions.
- The evolution continues.
Project repository: