<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Ján Hanko</title><description>A personal space for learning in public—through code, ideas, and imperfect progress.</description><link>https://janhanko.com/</link><item><title>Why Meetings Fail - and How Speaking Up Changes Everything</title><link>https://janhanko.com/blog/speaking-up-in-meetings</link><guid isPermaLink="true">https://janhanko.com/blog/speaking-up-in-meetings</guid><description>Learn how to speak up in meetings, handle unproductive discussions, and communicate with confidence at work - even if you&apos;re not the loudest person in the room.</description><pubDate>Tue, 28 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&gt; Language is a beautiful gift, so make sure every word spoken has value,
&gt; or shut your trap and keep your empty words to yourself.

## The Problem with Most Meetings

It&apos;s 2 PM and you are sitting in a room full of unknown people.
You are here because it concerns a feature you worked on for the last five months.

It is the first time for you, so you are more of a support character than someone
who plans to take an active role. Time goes by, and it is already 4 PM. You are
still sitting in the same room with the same people.\
Temperature is high, there isn&apos;t much oxygen, but there are a lot
of repeating arguments.

&gt; **(Josh (Analyst))**: So I&apos;m concerned, if new redesign of this page will not break
&gt; the functionality of the new popup and vice versa. 
&gt; 
&gt; **(Alisha (Team lead - popup team))**: It shouldn&apos;t, we knew it would overlap, and
&gt; we prepared it as requested, considering the redesign.
&gt; 
&gt; **(Mike - team lead - redesign)**: Yep, that sounds correct, they also worked
&gt; with the new style we prepared, so everything should be fine. 
&gt; 
&gt; **(Josh)**: So when can we see and test both of those features together? 
&gt; 
&gt; **(Mike)**: We can merge it at the end of the week, then next week we can start testing,
&gt; is that OK, Johny? 
&gt; 
&gt; **(Johny - team lead tester)**: Should be OK with us, test cases are ready.
&gt; 
&gt; **(Josh)**: And can we release popup without redesign if something goes wrong?
&gt; 
&gt; **(Alisha)**: Not really, but there isn&apos;t much, what could go wrong. We need to merge it and just make sure,
&gt; nothing breaks. 
&gt; 
&gt; **(Katrin - product owner)**: Popup has to go out — there is a campaign connected to it.
&gt; 
&gt; **(Josh)**: So we definitely need both features, what&apos;s the plan?
&gt; 
&gt; **(Alisha)**: If Mike&apos;s team doesn&apos;t break our feature, everything will be fine.
&gt; 
&gt; **(Mike)**: So we are the problem here?
&gt; 
&gt; **(Alisha)**: I&apos;m just saying that...
&gt; 
&gt; **(Mike)**: So you think that...
&gt; 
&gt; **(Josh)**: Can we get back to... 

## Why Meetings Get Stuck

This is the moment when finding a solution quietly stops being the goal.

The problems I see are:

* **People who can, but don&apos;t want to make a decision** (take responsibility for it)
* **Unnecessary arguing** - which doesn&apos;t bring anything to the table
* **Not enough information** - this is a specific case; it is hard to make a decision without
information, but it shouldn&apos;t jail people in the room
* **&quot;People without power&quot;** - who are **not able** or willing to share information

We have 2 team leads who started going after each other, even though
at first everything looked fine. \
We have our doubter, who didn&apos;t help. \
There is tension caused by the business people.  \
And let&apos;s say there are other people and 2 developers, who just sit quietly — didn&apos;t say
anything - yet.

## People Who Hold The Power

People who can and should move the whole meeting forward are our two team leads. \
They got too passionate and lost the sight of the goal. Instead of trying to
solve the problem, they started arguing. \
Making decisions and taking responsibility is hard. Some decisions are more difficult
than others, but making them always moves things forward - even though
we might regret them sometimes.

We could put our doubter - the organizer of the whole meeting - into this category as well. \
He is supposed to be the guide. He holds the power to call the shots and move 
the conversation in the right direction. \
Instead of dropping his voice and just asking, he could stop their conversation.
They could complain later, but now the arguing duo would look foolish if they continued.
He could even direct a specific question to the developers and let the rest cool down.

## Not Enough Information to Decide

What if there is not enough information on the table to decide anything?\
Sometimes life gets hard - terrible previous meetings,
problems at home, people forget. \
Wouldn&apos;t asking someone else sound incompetent? \
Do you trust someone who babbles and argues - or
someone who confidently says, &quot;I don&apos;t know - let me ask&quot;? \
Always acknowledge other people and show confidence in yourself.

## Why are You in The Room?

Many people struggle with speaking up in meetings -but what about you? \
You are in the room as well. \
But the room feels heavy, and this could be quite scary. \
However, this is your time to shine. \
Stand up. Everyone goes quiet. Start speaking - be confident -
you know the most important facts. 

&gt; I already consulted this with Susan. There is no real overlap in the features. \
&gt; We can put them together after the meeting. Then we can deploy them on the testing environment. \
&gt; Testers can start tomorrow. Is xyz testing environment OK, Johny?... (silence)

At this moment, you have done everything necessary. 

Your team lead cools down. Now he remembers, what you told him. The meeting can continue
as it should, and people leave satisfied.

What you did - standing up - you gave an important signal, that you have something to say.\
This is something people usually understand instinctively, no matter how lost they are.
This is only one form of body language - and it always plays a big role.


## Speak If You Have Something Important to Say

What should you take from this? \
Live and feel your conversations and interactions, don&apos;t just speak. 
Be humble, but confident. \
Listen to great speakers and learn from them. \
Sometimes, a few words have more power
than lengthy explanations. \

That&apos;s something I&apos;m still working on and trying to understand.
This isn&apos;t just workplace thing, there are plenty of every day interactions,
work on them.

Last but not least, don&apos;t rely only on your words. \
Silence, body language, voice - don&apos;t be afraid to use them. Sometimes we are up,
sometimes down, but we are learning, getting better... growing.</content:encoded></item><item><title>Embracing the Suck: Start Before You’re Ready</title><link>https://janhanko.com/blog/start-before-you-are-ready</link><guid isPermaLink="true">https://janhanko.com/blog/start-before-you-are-ready</guid><description>A personal reflection on overthinking, perfectionism, and finally starting. Why embracing imperfection and learning in public might be the best thing you can do.</description><pubDate>Tue, 28 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&gt; The story of the man who started many things and didn&apos;t finish any is better
&gt; than that of the one who didn&apos;t start at all. That&apos;s something I&apos;ve been trying to tell
&gt; myself for a long time. And writing this first post is one of those things.

## Why I Didn’t Start

For a long time, I wanted to create something, but in my head there were always
big thoughts - it must be great, help someone else, it shouldn&apos;t be basic stuff
you can find anywhere... It definitely shouldn&apos;t be something philosophical
that has nothing to do with what you are pursuing in your career.
Don&apos;t forget: if you put something out there, the whole world will see it,
so you&apos;d better not embarrass yourself. \
That&apos;s where I was stuck.

To put it into perspective, I&apos;m kind of a software engineer, so the idea was
to share some work, some problems and solutions, some overviews of what 
I was learning, and so on. \
You know - those typical engineering posts, full of code snippets and words normal people
wouldn&apos;t understand. Every normal developer blog/log.

## The Problem With Perfectionism

My idea of professionalism was narrow.\
At heart, I’m someone who can write ten emojis in one sentence,
so you can imagine how uncomfortable that version of professionalism felt. \
Sooner or later, I realized that the life of a developer isn’t really just about code.

During all this time, it wasn&apos;t just thinking about something - I even produced a few &quot;articles&quot;, if you can
call them that. Mostly messy thoughts on topics I was working on - but putting stuff on paper, 
helps me think. \
That&apos;s also one of the reasons I wanted to start publishing in the first place. 
They still exist - you should never delete your ideas. It&apos;s nice to come back
and see the way your mind worked in the past. 

The reality is, this will probably reach very few people. \
It might not help anyone. \
But it already serves its purpose. It exists because it matters to me — and maybe it helps
you too.

## Why I Finally Started

What was I looking for all this time? I&apos;m still not sure.\
What I do know is that I wasted a lot of time overthinking instead of doing something -something that makes it hard to start before you’re ready
If my work were done in the same way, nothing would ever get done.\
So would some chaotic articles be a good representation of someone
aspiring to be a great software engineer? No - at least in my head. \
But would great articles be a good representation of me? Probably not. \
It isn&apos;t about representing how smart you are, but how much you can grow - 
at least that&apos;s how I think now.

I&apos;m not the same person I was yesterday, or even one minute ago.
I want to be me - to stay serious when it matters, and not so much when nothing is going on.\
This is supposed to be a hobby, not another job.\
I would probably enjoy it even if it were part of a job,
but that enjoyment would fade over time, and I would eventually stop - as I have in the past.\
But I want to see where this will take me - it&apos;s about the path, not the goal.

## Embracing the Suck

So what does all this have to do with &quot;embracing the suck&quot;? \
I embrace that I suck - and you should as well.
It will take many repetitions, and it will hopefully never be perfect, because that would 
mean there&apos;s nowhere to grow. \
And if you&apos;re not growing, you&apos;re declining - be it a person, a business,
a job, whatever.

## What This Blog Will Be

What is this supposed to be about? Who knows. \
One day there might be an article about how 
you do some spark magic, another about how you bake a delicious chocolate cake :D


*So if you are here and have read until now - welcome. If you&apos;d like to point out how bad it is, 
feel free to contact me. Criticism has huge value.*

This is me starting before I feel ready.
Let’s see where it goes.</content:encoded></item><item><title>Spark on Kubernetes Tutorial (Beginner-Friendly with Minikube)</title><link>https://janhanko.com/blog/spark-on-kubernetes-minikube</link><guid isPermaLink="true">https://janhanko.com/blog/spark-on-kubernetes-minikube</guid><description>How to run Spark on Kubernetes, step by step</description><pubDate>Tue, 28 Apr 2026 00:00:00 GMT</pubDate><content:encoded>This post is a beginner-friendly introduction to *Spark on Kubernetes*,
the guide I wish I had when I first tried it.

If you&apos;re trying to run Spark on Kubernetes locally,
this guide will walk you through a working example step by step.

We’ll go through examples from the [official documentation](https://spark.apache.org/docs/latest/running-on-kubernetes.html)
and run them on a local Minikube cluster. \
Along the way we’ll break things down and look under the hood.

This is beginner-friendly, but we’ll assume:

* Some basic understanding of Spark
* Basic knowledge about containers
* No prior Kubernetes experience

I hope it will help you avoid frustration on your journey through this Spark jungle.

---

## Basic Concept of Spark on Kubernetes

Instead of one big cluster, you can run many Spark mini clusters.
Each submitted job runs as its own small minicluster,
which gets cleaned up after the job is finished.

That means you get:

* **Driver** – running as a pod

    * Communicates with the Kubernetes API to orchestrate your mini cluster
    * Communicates with executors to coordinate job execution
* **Executors** – running as separate pods

    * Actually perform the work you requested

![spark-on-kubernetes.svg](../images/spark-on-kubernetes.svg)

With that in mind, let’s jump straight into it.

---

## Hands-on Example (Running Spark on Kubernetes with Minikube)

You will need:

* [Minikube](https://minikube.sigs.k8s.io/docs/) – if you are not familiar at all, don’t worry, you only need the first three steps from their [tutorial](https://minikube.sigs.k8s.io/docs/start/?arch=%2Flinux%2Fx86-64%2Fstable%2Fbinary+download)
* [Spark](https://spark.apache.org/downloads.html) – download so you can follow along (I had version 4.0.1 locally when writing this)
* [Official Spark Docker image 4.0.1](https://hub.docker.com/layers/library/spark/4.0.1-scala2.13-java21-ubuntu/images/sha256-8efec9176dc78129e1883bfcd862762451e1f75226b858f2067508aacf103058) – the newest available version with Scala (at the time of writing)


---

### Documentation Example

Every command is executed from the main folder of your downloaded binaries.

This is what you will find in the official documentation:

```shell
$ ./bin/spark-submit \
    --master k8s://https://&lt;k8s-apiserver-host&gt;:&lt;k8s-apiserver-port&gt; \
    --deploy-mode cluster \
    --name spark-pi \
    --class org.apache.spark.examples.SparkPi \
    --conf spark.executor.instances=5 \
    --conf spark.kubernetes.container.image=&lt;spark-image&gt; \
    local:///path/to/examples.jar
```

---

### Spark Submit Script

Let’s begin with the core script we are running: `spark-submit`.
This script is part of every Spark binary and is your gateway to run anything in Spark.

Based on your configuration, `spark-submit` tells Spark how to run your workload.

---

### Kubernetes API Server Host and Port

If you are not familiar with Kubernetes (as I wasn’t at the time),
you might ask: what is the k8s-apiserver?
You can check the explanation in the [official documentation](https://kubernetes.io/docs/concepts/overview/kubernetes-api/).

Basically, Kubernetes manages containerized workloads.
Your submit script tells Kubernetes, through the API, what it requires,
and then Kubernetes takes over - creating, deleting, and modifying workloads as needed.

With Minikube, if you run:

```shell
$ minikube ip
```

You’ll get the local IP address of your Minikube cluster.
The port you need to know is **8443**, the default for Minikube.

Then change the `--master` command to:

```shell
  --master k8s://https://&lt;your-minikube-ip&gt;:8443
  # or in your shell
  --master k8s://https://$(minikube ip):8443
```

This tells your submit script where the Kubernetes API is available.

---

### Workload You Want to Run

```shell
  --class org.apache.spark.examples.SparkPi
```

This line tells Spark what you actually want to run.
You can find this specific class in the examples directories of your downloaded Spark binaries:

```
&lt;path-to-your-spark-binaries&gt;/examples/src/main/scala/org/apache/spark/examples
```

The **SparkPi** class is the one your example calls.

---

### Docker Images for Spark

Since Kubernetes runs containerized workloads, you must specify the Docker image using:

```shell
    --conf spark.kubernetes.container.image=&lt;spark-image&gt;
```

In our case, we can use the prebuilt image, which already contains everything we need.

```
apache/spark:4.0.1-scala2.13-java21-ubuntu
```

---

### Bundled JAR

The last line refers to the example JAR packaged inside the container.
For cluster deploy mode, it points to:

```
local:///opt/spark/examples/jars/spark-examples.jar
```

You can also find a corresponding JAR in your downloaded Spark binaries:

```
&lt;path-to-your-spark-binaries&gt;/examples/jars/spark-examples_2.13-4.0.1.jar
```

Locally, you won’t see `spark-examples.jar` because it is a symbolic link
inside the Docker container.

---

### Putting It All Together

Here’s the full command you should be able to use:

```shell
$ ./bin/spark-submit \
    --master k8s://https://$(minikube ip):8443 \
    --deploy-mode cluster \
    --name spark-pi \
    --class org.apache.spark.examples.SparkPi \
    --conf spark.executor.instances=5 \
    --conf spark.kubernetes.container.image=apache/spark:4.0.1-scala2.13-java21-ubuntu \
    local:///opt/spark/examples/jars/spark-examples.jar
```

If you run it on Minikube, the driver pod will start but will fail immediately:

```shell
 Caused by: io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: GET at: https://kubernetes.default.svc/api/v1/namespaces/default/pods/org-apache-spark-examples-sparkpi-38d3dc9c3d8a8786-dr
```

This happens because Kubernetes requires permissions for everything.
Using the default [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) won’t allow the driver pod to create or manage pods.

---

### RBAC Hell

For testing, we can create a Spark service account and a role binding to allow
the test application to run. This is only for testing.
In a real cluster, you’d want stricter permissions ([least privilege](https://kubernetes.io/docs/concepts/security/rbac-good-practices/#least-privilege)).

```shell
$ kubectl create serviceaccount spark
$ kubectl create clusterrolebinding spark-role --clusterrole=edit --serviceaccount=default:spark --namespace=default
```

You can also find this in the [Spark documentation](https://spark.apache.org/docs/latest/running-on-kubernetes.html#rbac).

---

### The Real Working Example

Now tweak your submit command:

```shell
$ ./bin/spark-submit \
    --master k8s://https://$(minikube ip):8443 \
    --deploy-mode cluster \
    --name spark-pi \
    --executor-memory 2G \
    --class org.apache.spark.examples.SparkPi \
    --conf spark.executor.instances=2 \
    --conf spark.kubernetes.container.image=apache/spark:4.0.1-scala2.13-java21-ubuntu \
    --conf spark.kubernetes.authenticate.driver.serviceAccountName=&quot;spark&quot; \
    local:///opt/spark/examples/jars/spark-examples.jar
```

This should finally work. \
I reduced the number of executors and executor memory
so it doesn’t eat up all your local resources.

---

### Check the Expected Result

```shell
$ kubectl get pods
```

Expected output:

```shell
NAME                                                        READY   STATUS        RESTARTS   AGE
org-apache-spark-examples-sparkpi-46c3389c3da281d4-driver   1/1     Running       0          23s
spark-pi-4450d19c3da2a0fc-exec-1                            1/1     Running       0          15s
spark-pi-4450d19c3da2a0fc-exec-2                            1/1     Running       0          15s
```

This shows one driver and two executors, as defined in the submit script.

If you see:

```shell
NAME                                                        READY   STATUS        RESTARTS   AGE
org-apache-spark-examples-sparkpi-46c3389c3da281d4-driver   1/1     Completed       0          23s
```

The job finished and executors were cleaned. In that case, run the command again, or try:

```shell
$ kubectl get pods -w
```

This allows you to watch pods being created and deleted in real time.

---

### Cleaning Up Pods

To remove single pod manually:

```shell
$ kubectl delete pods &lt;pod-name&gt;
# example
$ kubectl delete pods spark-pi-27719e9c572a28d9-driver

# Or delete all pods in your Minikube cluster:
$ kubectl delete pods --all
```

---

## That’s Just the Beginning

If you made it to the end and it works, great job!
If not, don’t worry — try again, experiment, and you might find yourself enjoying it.

Quick recap of how to run Spark on Kubernetes locally:

* Set up a local Kubernetes cluster with Minikube
* Configure your spark-submit command
* Point Spark to the Kubernetes API
* Specify the correct Docker image
* Configure RBAC permissions
* Run the job and verify pods

I hope by the end you have a basic understanding of what’s happening on this small scale.
There’s much more to learn — the Spark + Kubernetes ecosystem is huge.
In the future, I’d like to cover useful tips and traps I ran into along the way.</content:encoded></item></channel></rss>