DEV Community

Cover image for Building a Developer Profile That Keeps Working: Introducing Profile Studio
Faith Omobude
Faith Omobude

Posted on

Building a Developer Profile That Keeps Working: Introducing Profile Studio

Whilst you build, your GitHub profile tells us a lot about the kind of developer you are.

Your repositories show what you build.

Your contributions show that you build consistently.

But your profile README gives people a chance to understand who you are, what you're working on, what you're learning, and what you care about.

Recruiters, developers, collaborators, and potential employers may visit your GitHub profile before they ever speak to you.

And that's what got me thinking:

What if a GitHub profile could be more than just a README?

So I started building Profile Studio.

Customized README interface showcase my information

Contribtion graph and the dev.to integration

Introducing Profile Studio

Profile Studio started as a simple idea:

Make it easier for developers to create a good-looking GitHub profile README.

But as I kept building, the idea evolved.

I didn't want to build just another README generator.

I wanted to build a mini landing page for developers that lives directly inside their GitHub profile.

Something that could bring together:

  • πŸ‘‹ A personalized introduction
  • πŸš€ About-me information
  • πŸ› οΈ Technology stack
  • πŸ”— Social links
  • πŸ“Š GitHub statistics
  • πŸ“ˆ Contribution activity
  • πŸ’­ Developer quotes
  • πŸ“ DEV.to articles
  • 🎨 Custom branding
  • βš™οΈ DEV.to automation

The goal is simple:

Your GitHub profile should tell your story without requiring someone to dig through your repositories to understand you.


Why I Built It

I've always found it interesting that developers spend so much time building applications but sometimes spend very little time thinking about how people experience their developer identity.

Your GitHub profile is one of those places.

You might have:

  • great projects,
  • interesting repositories,
  • technical experience,
  • articles,
  • certifications,
  • open-source contributions,

but if someone lands on your profile and sees an empty or generic README, they don't immediately get that context.

Profile Studio is my attempt to solve that.

Not by replacing a portfolio.

Not by replacing your GitHub repositories.

But by creating a better front door to your developer identity.


It's More Than a README Generator

This distinction is important to me.

A README generator usually does something like:

Enter some information β†’ generate Markdown β†’ copy it.

Profile Studio goes a little further.

The application lets you configure your profile visually and generates a README that brings those different pieces together.

And now, it can also package automation for your DEV.to content.

So the generated output isn't just:

README.md
Enter fullscreen mode Exit fullscreen mode

It can also include the supporting files required to keep your DEV.to section updated automatically.

That's where the project became much more interesting from an engineering perspective.


The Architecture Behind Profile Studio

Profile-studio UI interface

Underneath the interface, Profile Studio is intentionally modular.

The application started with responsibilities living together in a large JavaScript file.

As the project grew, that became increasingly difficult to reason about.

So I started separating responsibilities.

The current architecture looks roughly like this:

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚       User / Browser     β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚
                                 β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚       Profile Studio     β”‚
                    β”‚          UI              β”‚
                    β”‚      index.html          β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚
                                 β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚          app.js           β”‚
                    β”‚   Wizard + UI State Flow  β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚                  β”‚                  β”‚
              β–Ό                  β–Ό                  β–Ό
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚  state.js  β”‚     β”‚ devto.js   β”‚     β”‚ generator  β”‚
       β”‚            β”‚     β”‚            β”‚     β”‚    .js     β”‚
       β”‚ State      β”‚     β”‚ DEV.to API β”‚     β”‚ Markdown   β”‚
       β”‚ management β”‚     β”‚ integrationβ”‚     β”‚ generation β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
                                β”‚                  β”‚
                                β–Ό                  β–Ό
                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚ DEV.to API β”‚      β”‚ README.md   β”‚
                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚ security.jsβ”‚
                         β”‚            β”‚
                         β”‚ URL + HTML β”‚
                         β”‚ sanitizing β”‚
                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚ catalog.js β”‚
                         β”‚            β”‚
                         β”‚ Tech/socialβ”‚
                         β”‚ metadata   β”‚
                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Enter fullscreen mode Exit fullscreen mode

The major pieces are separated by responsibility:

app.js

Handles the application flow and UI interactions.

state.js

Owns application state and persistence.

devto.js

Handles DEV.to-specific functionality.

generator.js

Handles README generation.

security.js

Provides output-safety utilities such as URL validation and HTML/Markdown escaping.

catalog.js

Contains the catalog of technologies, social platforms, badges, and related configuration.

That separation wasn't where the project started.

It's where the project evolved.

And that evolution taught me something important:

A working application isn't necessarily a well-engineered application.


From "It Works" to "It's Engineered"

It's very easy to look at an application and say:

"It works. Ship it."

But working is only one dimension of good software.

As Profile Studio grew, I started asking different questions:

  • Can someone else understand this code?
  • Can I change one feature without breaking three others?
  • Are important pieces tested?
  • Is user input handled safely?
  • What happens when an external service fails?
  • Can I diagnose problems when something goes wrong?
  • Does the architecture still make sense as the application grows?

The application wasn't necessarily broken.

But responsibilities were beginning to pile up.

State management was mixed with UI logic.

External integrations were mixed with application logic.

README generation was mixed into the rest of the application.

So I started refactoring.

Not because the application stopped working.

Because I wanted it to be easier to keep working.

That's one of the engineering lessons this project has been teaching me.

Good engineering isn't just about making something work. It's about making it possible for the software to continue working as it evolves.


Security Matters Even at the early stage

One of the things I didn't initially expect to spend so much time thinking about was security.

Profile Studio accepts user-provided information and external URLs.

That means the generated output cannot simply trust everything it receives.

For example, the project has safety helpers such as:

safeUrl()
Enter fullscreen mode Exit fullscreen mode

and:

escapeHtml()
Enter fullscreen mode Exit fullscreen mode

and:

escapeMdText()
Enter fullscreen mode Exit fullscreen mode

These help prevent unsafe URLs and injected markup from being blindly rendered into generated output.

This is something I think is easy to overlook when building seemingly "simple" developer tools.

You might think:

"It's only generating a README."

But the application is still processing input.

And input should be treated as input.


Testing the Application

The project also has automated tests.

At the time of writing, the test suite covers things such as:

  • DEV.to username normalization
  • DEV.to URL handling
  • DEV.to Markdown generation
  • unsafe article URLs
  • unsafe cover images
  • HTML escaping
  • Markdown escaping
  • allowed URL schemes
  • rejected JavaScript URLs
  • rejected data URLs
  • safeUrl() behavior

The current test run is:

Test run results

I also use:

node --check .\js\generator.js
node --check .\js\app.js
Enter fullscreen mode Exit fullscreen mode

and:

npm test
Enter fullscreen mode Exit fullscreen mode

as part of my development workflow.

It's a small project, but I'm trying to apply the same engineering mindset I'd want to use on larger systems.


DEV.to Integration

This is one of the features I'm particularly excited about.

If you enable the DEV.to section in Profile Studio, provide your DEV.to username, select how many posts you want displayed, and enable automated DEV.to fetches, the generated package includes the files needed to automate the README updates.

The package contains:

.github/
β”œβ”€β”€ profile-studio.json
β”œβ”€β”€ scripts/
β”‚   └── update-devto.js
└── workflows/
    └── devto-readme.yml

README.md
Enter fullscreen mode Exit fullscreen mode

The idea is that your GitHub profile can automatically keep its DEV.to section updated instead of requiring you to manually edit the README every time you publish an article.


Setting Up the DEV.to Package

I've tried to make this accessible even if you're relatively new to Git and GitHub.

You don't need to be an expert.

You need:

  • A GitHub account
  • A DEV.to account
  • Your GitHub username
  • Your DEV.to username
  • Git installed
  • The DEV.to Package ZIP generated by Profile Studio

Your GitHub Special Repository

Your GitHub profile README lives in a special repository.

The repository name must be exactly the same as your GitHub username.

For example:

GitHub username:
CloudFay

Special repository:
CloudFay/CloudFay
Enter fullscreen mode Exit fullscreen mode

So:

github.com/CloudFay/CloudFay
Enter fullscreen mode Exit fullscreen mode

The repository should be public.

And then toggle your README.md option ON


Step 1 β€” Download the DEV.to Package

When you enable the DEV.to integration and configure your username and desired number of posts, Profile Studio can generate the DEV.to package.

Download the .zip file.

For example:

Dev.to-Package.zip
Enter fullscreen mode Exit fullscreen mode

Dev.to_package.zip file


Step 2 β€” Extract the ZIP

On Windows:

  1. Right-click the ZIP.
  2. Select Extract All...
  3. Extract it somewhere convenient.

You should have something similar to:

Dev.to Package/
β”œβ”€β”€ .github/
└── README.md
Enter fullscreen mode Exit fullscreen mode

NOTE: Because .github is normally treated as a hidden folder, make sure Hidden items are enabled in File Explorer.


Step 3 β€” Create or Open Your Special Repository

Create your GitHub special repository if you don't already have one.

For example:

CloudFay/CloudFay
Enter fullscreen mode Exit fullscreen mode

Then clone it in your vscode:

git clone https://github.com/YOUR_USERNAME/YOUR_USERNAME.git
Enter fullscreen mode Exit fullscreen mode

Example:

git clone https://github.com/CloudFay/CloudFay.git
Enter fullscreen mode Exit fullscreen mode

Then enter the repository:

cd YOUR_USERNAME
Enter fullscreen mode Exit fullscreen mode

For example:

cd CloudFay
Enter fullscreen mode Exit fullscreen mode

Then run in order to open the repository in your Vscode:

code . 
Enter fullscreen mode Exit fullscreen mode

Step 4 β€” Copy the Package Files

This is where the PowerShell commands make the setup much easier.

If your extracted package is inside your Downloads folder, you can copy the .github folder directly into your repository with:

Copy-Item "$HOME\Downloads\.github" ".github" -Recurse -Force
Enter fullscreen mode Exit fullscreen mode

Then copy the generated README:

Copy-Item "$HOME\Downloads\README.md" "README.md" -Recurse -Force
Enter fullscreen mode Exit fullscreen mode

These commands essentially tell PowerShell:

Take the package's .github directory and README and place them into the repository I'm currently working in.

Verify the .github files

Run:

Get-ChildItem ".github" -Recurse -Force
Enter fullscreen mode Exit fullscreen mode

You should see the automation files.

Then verify the README:

Get-ChildItem "README.md" -Recurse -Force
Enter fullscreen mode Exit fullscreen mode

Your repository should now look approximately like:

YOUR_USERNAME/
β”‚
β”œβ”€β”€ .github/
β”‚   β”œβ”€β”€ profile-studio.json
β”‚   β”œβ”€β”€ scripts/
β”‚   β”‚   └── update-devto.js
β”‚   └── workflows/
β”‚       └── devto-readme.yml
β”‚
└── README.md
Enter fullscreen mode Exit fullscreen mode

Important: The .github directory must be directly inside the root of your special repository.

You do not want:

YOUR_USERNAME/
└── Dev.to Package/
    └── .github/
Enter fullscreen mode Exit fullscreen mode

You want:

YOUR_USERNAME/
β”œβ”€β”€ .github/
└── README.md
Enter fullscreen mode Exit fullscreen mode

Step 5 β€” Check Git

Before committing anything, run:

git status
Enter fullscreen mode Exit fullscreen mode

You should see your README and .github changes.

Then:

git add README.md .github
Enter fullscreen mode Exit fullscreen mode

Create a commit:

git commit -m "Add DEV.to integration"
Enter fullscreen mode Exit fullscreen mode

And push:

git push origin main
Enter fullscreen mode Exit fullscreen mode

And then you see this:

My special repository


Step 6 β€” Check GitHub Actions

Once the changes reach GitHub:

  1. Open your repository.
  2. Go to Actions.
  3. Find the DEV.to workflow.
  4. Open the workflow run.
  5. Check whether it completed successfully.

GitHub Actions is responsible for running the automation.

the Actions workflow

Jobs run successfully


Step 7 β€” Visit Your Profile

Finally, visit:

https://github.com/YOUR_USERNAME
Enter fullscreen mode Exit fullscreen mode

Your generated README should now appear on your profile.

And if the DEV.to automation is configured correctly, your articles can be updated automatically according to the package configuration.


A Small Project, A Lot of Engineering Lessons

Profile Studio started with a relatively simple goal.

Generate a better GitHub profile README.

But building it has exposed me to a much bigger set of engineering problems:

  • State management.

  • Modular architecture.

  • External API integration.

  • Output security.

  • Testing.

  • Git workflows.

  • GitHub Actions.

  • Developer experience.

  • Automation.

And perhaps most importantly:

  • maintainability.

The project is still evolving.

That's actually part of the point.

I'm building it, breaking things, fixing things, refactoring things, testing things, and documenting what I'm learning along the way.


What's Next?

There are still plenty of things I'd like to explore with Profile Studio.

The project is becoming less about:

"How do I generate a README?"

and more about:

"How can I help developers build a better representation of themselves on GitHub?"

There are features I'd like to improve.

There are architectural decisions I'd like to revisit.

There are probably bugs I haven't discovered yet.

And there are definitely things I would design differently if I started the project again today.

That's part of building software.

You don't always learn everything before you build.

Sometimes building is how you learn.


Try Profile Studio

If you're a developer and want to create your own GitHub profile, you can try Profile Studio here:

πŸš€ Try Profile Studio

The project is open source, so if you're interested in the implementation, you can also explore the codebase:

πŸ’» View the Profile Studio source code

If you find something that could be improved, have an idea for a feature, or simply want to contribute, I'd love to hear from you.


Final Thought

I'm learning that building software isn't just about getting to the moment where you can say:

"It works."

It's also about asking:

"Can I understand it six months from now?"

"Can someone else contribute to it?"

"Can I safely change it?"

"What happens when something fails?"

"Can I trust what the application produces?"

Those questions are what turn a working application into an engineered application.

And Profile Studio is giving me a very practical place to learn those lessons.

I'm still building. I'm still learning. And this is only the beginning. πŸš€

Top comments (0)