“The best time to start was yesterday. The second best time is now.”
After weeks of thinking about it, I finally launched my own personal website — a portfolio that showcases my projects, experience, and tech blog.
In this post, I’ll share how I built it, the tools I used, what I learned along the way, and how I automated deployment using GitHub.
🧭 Why Build My Own Website?
I wanted a central place to share what I do — projects, experience, thoughts, and learning. It had to be minimal, fast, accessible, and most importantly: mine.
I also needed something easy to maintain and deploy without hassle every time I updated content.
🛠 Tools Used
- Astro: a modern framework for building ultra-fast static sites. I liked its simplicity and how easily I could render dynamic content from
.mdfiles. - GitHub Pages: a free and simple hosting solution for static websites. Just push to the
gh-pagesbranch, and it’s online. - GitHub Actions: to automate building and deployment every time I push to
main. - Tailwind CSS: already included in the template, great for keeping the design clean and consistent. I was already familiar with it from previous study, which made it easier to customize styles effectively.
🏗 Site Development
I used Astro Nano as the base template. It comes with dark mode, accessibility, a clean design, and solid structure.
Here’s what I did:
- Customized the theme, colors, and fonts
- Replaced the default content with my own
- Added my professional experience under
/work/ - Published my first project under
/projects/ - Prepared the blog structure for posts like this one
This process helped me better understand how Astro handles layouts, components, and content collections.
⚙️ Automating Deployment
This was one of the most valuable steps: automating the entire workflow.
With the help of ChatGPT, I built a GitHub Actions pipeline that:
- Triggers on push to
main - Installs dependencies and builds the project
- Copies
index.htmlas404.htmlto handle unmatched routes - Adds a
.nojekyllfile to avoid GitHub Pages issues - Pushes the contents of
dist/to thegh-pagesbranch
Now, I just write or code, commit, and the site updates itself — no manual steps.
🚀 Coming Soon
In the next blog post, I’ll dive into some Databricks topics — since that’s what I’m actively working with right now.
Thanks for reading, and see you in the next one!
title: “Stop Copy-Pasting dbutils: Introducing dbxparams” description: “How to eliminate widget duplication in Databricks notebooks with a clean, Pythonic approach” date: “2025-05-03” draft: false
If you work with Databricks notebooks, you’ve probably seen this pattern more times than you can count:
dbutils.widgets.text("source_path", "")
dbutils.widgets.text("output_table", "default.orders")
dbutils.widgets.text("full_refresh", "false")
source_path = dbutils.widgets.get("source_path")
output_table = dbutils.widgets.get("output_table")
full_refresh = dbutils.widgets.get("full_refresh")
It looks harmless… until you have dozens (or even hundreds) of notebooks that repeat the same widgets. Now imagine you need to add, remove, or rename one parameter. You end up touching every notebook manually. It’s repetitive, error-prone, and painful.
I got tired of it. That’s why I started building an open-source library: dbxparams.
1. The Idea
The core concept is simple:
- Define your parameters once as a Python class.
- Instantiate that class with
dbutils. - dbxparams automatically creates the widgets and assigns their values to the class attributes.
- Type checking ensures your parameters arrive in the correct format.
No more copy-paste. No more duplicated logic.
2. A First Example
from dbxparams import NotebookParams
class IngestParams(NotebookParams):
source_path: str
output_table: str = "default.orders_clean"
full_refresh: bool = False
params = IngestParams(dbutils)
print("Source:", params.source_path)
print("Output table:", params.output_table)
print("Full refresh:", params.full_refresh)
What happens under the hood:
-
When you call
IngestParams(dbutils):- Creates the widgets (
source_path,output_table,full_refresh). - Reads their values from the notebook UI.
- Assigns them as attributes of your class.
- Creates the widgets (
-
Type casting is automatic:
source_path→ always a string.full_refresh→ parsed as a boolean (true/false/yes/no/1/0).
-
If a required parameter is missing, dbxparams raises a
MissingParameterError.
3. Type Checking and Validation
dbxparams supports type casting for:
strintfloatbool
If the value doesn’t match, you’ll get a descriptive exception:
InvalidTypeError: Parameter 'max_rows' expected type int but received 'ten' (type str).
This makes debugging faster and your notebooks more robust.
(Support for date and datetime will come in future releases.)
4. Example in a Databricks Job
dbxparams also works seamlessly with Jobs. Instead of defining widgets manually, just pass parameters in the Job config:
{
"name": "IngestJobTest",
"tasks": [
{
"task_key": "ingest_task",
"notebook_task": {
"notebook_path": "/Workspace/dbxparams_test/job_notebook",
"base_parameters": {
"source_path": "dbfs:/FileStore/raw/orders_2025.csv",
"output_table": "analytics.cleaned_orders",
"full_refresh": "true",
"max_rows": "25000"
}
},
"existing_cluster_id": "your-cluster-id"
}
]
}
Inside the notebook:
params = IngestParams(dbutils)
print(params.source_path) # dbfs:/FileStore/raw/orders_2025.csv
print(params.output_table) # analytics.cleaned_orders
print(params.full_refresh) # True
print(params.max_rows) # 25000
5. Under the Hood
-
Inspects class annotations with
typing.get_type_hints. -
For each attribute:
- A widget is created (if not already present).
- The value is read from
dbutils.widgets. - If no value is found, it falls back to class defaults or raises
MissingParameterError. - The value is type-cast using a lightweight utility.
This design keeps notebooks clean, removes boilerplate, and ensures consistency across large ETL pipelines.
6. Roadmap
- Add support for
dateanddatetime. - Allow required parameters without type annotations.
- Publish the library to PyPI in October.
- Collect community feedback and contributions.
7. Conclusion
dbxparams is still a skeleton, but it already solves one of the most annoying problems in Databricks: parameter duplication.
By defining parameters once as a class, you get:
- Cleaner notebooks
- Centralized parameter definitions
- Automatic widget creation
- Built-in type checking
I’ll keep sharing progress and updates. If you’re interested in testing it or contributing, feel free to reach out.
Stay tuned — and no more copy-pasting dbutils.