Building AppointDent: A Microservices Journey in Dental Appointment Management
Project Genesis
Discovering AppointDent: A Journey to Simplify Dental Care in Sweden
From Idea to Implementation
1. Initial Research and Planning
2. Technical Decisions and Their Rationale
- TypeScript was chosen for its strong typing capabilities, which help catch errors early in the development process.
- Node.js was selected as the runtime environment due to its non-blocking architecture, making it suitable for handling multiple requests simultaneously.
- Vite.js was adopted for its fast build times and hot module replacement, enhancing the development experience.
- Solid.js was chosen for the client-side framework because of its fine-grained reactivity and performance benefits.
- The use of Tailwind CSS allowed for rapid UI development with a utility-first approach, enabling the team to create responsive designs efficiently.
3. Alternative Approaches Considered
-
Monolithic Architecture: Initially, the team contemplated a monolithic architecture for simplicity. However, this approach would have made scaling and maintaining the application more challenging as the project grew. The decision to adopt microservices ultimately provided greater flexibility and ease of deployment.
-
Different Frontend Frameworks: Other frameworks such as React and Angular were evaluated for the frontend. However, Solid.js was favored for its performance and simplicity, which aligned with the team’s goal of creating a fast and responsive user interface.
-
Traditional REST APIs: While REST APIs were considered for service communication, the team opted for the publish-subscribe model using MQTT to enable real-time updates and notifications, which were critical for the appointment management features.
4. Key Insights That Shaped the Project
-
User-Centric Design: The importance of a user-friendly interface became evident during user testing sessions. Feedback from potential users led to iterative design changes that improved the overall experience, emphasizing the need for intuitive navigation and clear communication of appointment statuses.
-
Scalability Needs: As the team began to implement features, it became clear that scalability would be crucial for handling varying loads, especially during peak appointment times. This realization reinforced the decision to use a microservices architecture, allowing the team to scale services independently based on demand.
-
Continuous Integration: The adoption of continuous integration practices proved invaluable in maintaining code quality and facilitating collaboration among team members. Regular testing and code reviews helped catch issues early, ensuring a smoother development process.
-
Real-Time Communication: The necessity for real-time notifications and updates became a focal point of the project. Implementing the publish-subscribe model not only enhanced user engagement but also improved the overall reliability of the appointment management system.
Under the Hood
Technical Deep-Dive: AppointDent
1. Architecture Decisions
Key Architectural Choices:
- Microservices: Each service (e.g.,
appointment-service
,dentist-service
) operates independently, which allows for easier updates and scaling. - MQTT Protocol: The use of the MQTT protocol for communication between services enhances the system’s ability to handle real-time notifications and updates efficiently.
- Distributed System: The architecture is designed to run on multiple machines, which improves fault tolerance and load distribution.
Example of Service Communication:
const mqtt = require('mqtt');
const client = mqtt.connect('mqtt://broker.hivemq.com');
client.on('connect', () => {
client.subscribe('appointment/notifications', (err) => {
if (!err) {
console.log('Subscribed to appointment notifications');
}
});
});
client.on('message', (topic, message) => {
console.log(`Received message: ${message.toString()}`);
});
2. Key Technologies Used
Front-End Technologies:
- TypeScript: Provides type safety and enhances code quality.
- Solid.js: A reactive UI library that offers high performance and fine-grained reactivity.
- Tailwind CSS: A utility-first CSS framework that allows for rapid UI development.
Back-End Technologies:
- Node.js: The runtime environment for building server-side applications.
- Express.js: A web framework for Node.js that simplifies the creation of APIs.
- SQLite3: A lightweight database solution used for storing application data.
Example of an Express.js Route:
const express = require('express');
const router = express.Router();
const Appointment = require('../models/Appointment');
router.post('/appointments', async (req, res) => {
try {
const appointment = new Appointment(req.body);
await appointment.save();
res.status(201).send(appointment);
} catch (error) {
res.status(400).send(error);
}
});
3. Interesting Implementation Details
Monorepo Structure:
Stress Testing:
k6
, which allows for simulating high loads on the application to ensure it can handle real-world usage scenarios. The stress-testing scripts are located in a dedicated folder, making it easy to run tests independently.Example of a k6 Test Script:
import http from 'k6/http';
import { check, sleep } from 'k6';
export default function () {
const res = http.post('http://localhost:3000/appointments', {
patientId: '12345',
dentistId: '67890',
time: '2023-10-01T10:00:00Z',
});
check(res, { 'status was 201': (r) => r.status === 201 });
sleep(1);
}
4. Technical Challenges Overcome
Challenge: Managing Service Communication
Challenge: Continuous Integration Setup
.gitlab-ci.yml
to work with GitHub Actions, ensuring that automated testing and deployment processes remained intact.Example of a GitHub Actions Workflow:
name: CI
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '18.x'
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
Conclusion
Lessons from the Trenches
Key Technical Lessons Learned
- Microservices Architecture: Implementing a microservices architecture taught us the importance of service independence and scalability. Each service can be developed, deployed, and scaled independently, which enhances the overall system’s resilience and flexibility.
- Communication Protocols: Utilizing the MQTT protocol for inter-service communication highlighted the significance of choosing the right communication method for distributed systems. It allowed for efficient message passing and reduced latency.
- Continuous Integration: The integration of CI practices improved our development workflow significantly. Automated testing and static analysis helped catch issues early, ensuring higher code quality and reducing the time spent on debugging later in the development cycle.
- Stress Testing: Conducting stress tests using tools like k6 provided insights into system performance under load, helping us identify bottlenecks and optimize resource allocation.
What Worked Well
- Team Collaboration: The use of GitLab for version control and CI/CD facilitated effective collaboration among team members. The ability to review code and run tests before merging into the main branch helped maintain code quality.
- Modular Design: The monorepo structure allowed for clear organization of the project components, making it easier for team members to navigate and understand the codebase. Each service having its own README file provided clarity on functionality and setup.
- User-Centric Features: Features like appointment notifications and an integrated map for finding dentists were well-received during user testing, demonstrating the importance of user feedback in shaping the application.
What You’d Do Differently
- Documentation: While the README is comprehensive, we could have included more detailed API documentation for each service. This would have made it easier for new developers to onboard and understand how to interact with the services.
- CI/CD Migration: Migrating the CI/CD pipeline to GitHub sooner would have streamlined our development process. We underestimated the time required to set up a new pipeline, which delayed some testing and deployment processes.
- Testing Coverage: We could have invested more time in writing unit tests for individual components. While integration tests were useful, having a robust suite of unit tests would have caught more issues early in the development process.
Advice for Others
- Start with a Clear Architecture: Before diving into development, spend time designing the architecture. A well-thought-out architecture can save a lot of time and effort later on.
- Embrace CI/CD Early: Implement continuous integration and deployment practices from the start. This will help maintain code quality and streamline the development process.
- Prioritize User Feedback: Regularly seek feedback from potential users throughout the development process. This will help ensure that the final product meets user needs and expectations.
- Document Everything: Maintain thorough documentation for both the codebase and the development process. This will aid in onboarding new team members and provide a reference for future development.
What’s Next?
Conclusion
Project Development Analytics
timeline gant

Commit Activity Heatmap
Contributor Network

Commit Activity Patterns

Code Frequency

- Repository URL: https://github.com/wanghaisheng/AppointDent
- Stars: 0
- Forks: 0
编辑整理: Heisenberg 更新日期:2024 年 12 月 30 日