Wednesday, 19 February 2025

Tech Workers: Hard vs Soft Skills (Part 2/2)

We've looked at hard skills, now let's explore soft skills!

Soft Skills

Contrary to popular belief, soft skills are not just about getting along wth other people, or getting them to think highly of you. It is about communication. It's not about proficiency in any given language and knowing fancy long words - there are plenty of people without a formal education who communicate a lot better than people who speak the Queen's English. Conversely, I've known people who are great at English, but come off so insufferable that nobody wants to deal with them. Being able to speak a language well does not automatically make one persuasive. Thus, proficiency in a language is more of a hard skill than a soft one.

It's all  about
communication.

Whether it's giving someone their flowers, managing expectations or diffusing potential (or existing!) tensions, discount soft skills at your peril. Just as a skilled programmer knows when to code and when not to code, someone well-versed in soft skills knows when to talk and when not to talk.

Soft skills are the skills that deal with communication with human beings. Human-computer interaction or just human-to-human communication? It is all relevant. Software is used by human beings, and developed by human beings. Therefore, any communication involving human beings remains a valuable skill.

What happens when you neglect soft skills?

Remember that the number one goal of software development is to solve problems and add value. In the case of your organization, it probably means to solve business problems and add business value.

Even without going into the area of personnel management, soft skills are very relevant in the software product itself. When developers concentrate on using technical skills and exclude soft skills, there's a danger that they will wind up with solutions that simply don't improve the product for the end-user. And this is important, why? Because ultimately, products are created for users. And that involves having enough empathy to understand what the end-user needs as opposed to what is technically superior.

The problem with management skills is that they're often not seen as a skill in their own right. People, for some strange reason, seem to think that programmers become better managers just because they've been writing code longer. News flash - practice in a skill improves that particular skill. Thus, practicing writing code only makes a developer better at writing code. Spending time developing software makes a dev better at developing software. Not at managing people.

Collaborative effort.

Sure, a more experienced software developer would be better at handling the software development process. Identifying potential pitfalls. Troubleshooting. But that same developer would not necessarily be good at delegation of work, managing personality clashes in a team, accounting to higher management for schedule shortfalls, and the like. These are a different set of skills, no matter how much people want to pretend otherwise.

Therefore, if you're promoted only for your technical ability, you'll get found out as soon as they start giving you subordinates. That's where any weaknesses you have at the actual art of man-management, will be exposed.

Where I stand with Soft Skills

As mentioned earlier, proficiency with the English language (or any language) does not automatically make one a good communicator. I happen to be living proof of that. There's been times I tried to describe a problem in a Service Request and fell far short of making myself understood. There have been also times I tried to describe a solution, with similar results.

Sometimes I forget that the people I speak to aren't technically trained, and that I have to be explicit when explaining certain things. Sometimes even with technically-trained personnel, it's good to spell things out just to be safe. There are times something sounds good in my head, only to sound comically wrong after I put it in writing.

Comes out wrong in writing.

That's one of the reasons I blog. Even if I never reach a wide audience, the point is the exercise in communication. Explaining technical concepts. Use of analogies. Appropriately describing my feelings and positions, both positive and negative, about certain subjects.

All said, I could always improve. All of us could. It's a skillset so wide that it covers all industries, not just software, at all levels.

In conclusion...

Hard skills are the skills that deal with computers.

Soft skills are the skills that deal with people.

In today's world, it's extremely hard to survive in the tech industry without a certain modicum of either one. There are, of course, extreme examples of each, but they are outliers.

For good or for skill,
T___T

Monday, 17 February 2025

Tech Workers: Hard vs Soft Skills (Part 1/2)

Software development is a skilled profession, but not for the reason most people think. That's because when people think of software development, the skills they associate with the industry are those of the technical variety.

However, there are two main categories of skills that make professionals valuable to their employers - hard and soft skills.

The burning question today is, which skills are more important to the tech professional? The answer to that, of course, is that they're both important. Perhaps one is more important than the other at certain stages of a tech career. There are software engineers who sneer at the concept of "being good with people". Conversely, there are people who think those who focus on hard skills are just obnoxious nerds. Who's right? Let's explore that.

Hard Skills

Hard skills are the skills that deal with tech stacks, troubleshooting and software analysis. Software is the backbone of, well, software. Thus the skills to build software are pretty damn important.

Databases, programming languages and operating systems are just tools. The true test of hard skills is the ability to get things done regardless of the tools at hand. And for that, doing rather than talking, is key.

Being good with your tools.

It's the know-how that is important, not so much the specific skillset. For instance, no one's probably going to care if you have the entire Ruby syntax memorized; but if you've dabbled enough in various programming languages that picking up a new one and being useful in it relatively quickly, it's always going to be valued.

Similarly, expertise in a specific tech stack is nice and all, but being able to pinpoint the possible fault points of a script gone wrong, regardless of the tech stack used? That's worth a lot more.

What happens when you neglect hard skills?

Well, first and most obviously, a tech practitioner who has insufficient technical skill to write even the simplest of code, probably won't last long. Even the devs who have climbed the ladder to Management and haven't done that much coding recently, know where to look for answers and what questions to ask.

Ultimately, being dependent on someone else, can also be a bad idea. Thus, being able to take care of smaller things yourself will be useful, and that requires a certain level of technical skill. A good analogy would be drivers knowing how to change car tyres by themselves instead of relying on a mechanic. Sure, they may not always (or even often) have to do it, but it's incredibly useful in the right situation.

Changing your own tyres.

And while it's true that employees with soft skills tend to get promoted to positions of leadership, and those in positions of leadership tend to get paid more, the question really is - how much can you get away with prioritizing soft skills ahead of your technical skills, and when does it become a problem? Hard skills are like the proverbial cake while soft skills are like the icing. A cake without icing is not at all appealing, but trust me when I say there's a lot more use for such a cake than for icing with no cake. Sure, employers can promote a dev with good soft skills, but how many of such people do these employers realistically need?

The danger of letting your tech cred rot, is that if and when you do get promoted due to being able to lead - and trust me, that happens more often than not - you may struggle to command the respect of the nerds tech professionals who now report to you. There's a stereotype that says that people who are useless technically but can speak well and project confidence, get the rub. It may or may not be true, but the last thing you want to do is fit that stereotype. You want to be known as the one who got promoted due to good soft skills, not due to being useless everywhere else.

The people I've reported to, fall on various positions on the spectrum of technical ability. The easiest to work with were those who knew absolutely nothing, and those who were better than me. Obviously, in the case of those who knew more than me, it was easy to just knuckle down and take instructions. In the case of those who knew nothing, they were largely content to get out of my way and let me do my thing.

The real pain points were with the ones who had just enough technical ability to make my working life miserable. They didn't have enough ability to help write the code, but they had enough knowledge to get in my way. It looks like the solution to what I just outlined, is not to neglect your technical skills. That's certainly one way. It can also be argued that the art of not getting in the way of those reporting to you while still getting them to take you seriously, is a soft skill.

Where I stand with Hard Skills

I occupy this uncomfortable grey area where I'm significantly more technically-qualified than the average Middle Manager, but far behind those hardcore hackers with the l33t skillz, yo.

Huge gaps.

Still, if I were to be rated, depending on which specific technical area you were speaking of, I suspect there would be plenty of comments ranging from "has glaring skill gaps", "sometimes really good and sometimes really poor" and "knows his shit". But that, I suspect, is also true of almost everyone who writes code for a living. Exceedingly rare is the complete developer. That ship has sailed.

Next

We examine soft skills.

Wednesday, 12 February 2025

Web Tutorial: Valentine's Day SVG Message

Welcome to 2025's annual Valentine's Day themed web tutorial! I'm a little late this year, but the path of true love runs deep, not smooth!

I want to go light, and to that end, we'll just do a bit of SVG animation. No style tags, no JavaScript. Sound good? No? Too bad sunshine, we're totally doing it.

Here's the beginning HTML. There's an SVG tag in the body tag. We'll be doing this with only inline styling, so specify the width and height, then use inline styling to specify the margin and display properties so that it's set in the middle of the screen.
<!DOCTYPE html>
<html>
  <head>
    <title>Valentine's Day</title>
  </head>
  <body>
    <svg width="800px" height="400px" style="display:block; margin:5% auto 0 auto">

    </svg>
  </body>
</html>


Add a defs tag in here, because we are going to be specifying some backgrounds.
<svg width="800px" height="400px" style="display:block; margin:5% auto 0 auto">
  <defs>
  
  </defs>  

</svg>


The first background we will specify has an id of textBackground and it's a linear gradient. The plan is to make it fade from deep pink to light pink, then deep pink again.
<svg width="800px" height="400px" style="display:block; margin:5% auto 0 auto">
  <defs>
    <linearGradient id="textBackground" x1="0" x2="0" y1="0" y2="1">
      <stop offset="0%" stop-color="rgb(255, 50, 50)" />
      <stop offset="40%" stop-color="rgb(255, 200, 200)" />
      <stop offset="60%" stop-color="rgb(255, 200, 200)" />
      <stop offset="100%" stop-color="rgb(255, 50, 50)" />
    </linearGradient>

  </defs>  
</svg>


And we are going to have text in the SVG, with this background. We want the letters I and U, huge and bold, right in the middle of the SVG.
<svg width="800px" height="400px" style="display:block; margin:5% auto 0 auto">
  <defs>
    <linearGradient id="textBackground" x1="0" x2="0" y1="0" y2="1">
      <stop offset="0%" stop-color="rgb(255, 50, 50)" />
      <stop offset="40%" stop-color="rgb(255, 200, 200)" />
      <stop offset="60%" stop-color="rgb(255, 200, 200)" />
      <stop offset="100%" stop-color="rgb(255, 50, 50)" />
    </linearGradient>
  </defs>  

  <text x="400px" y="300px" text-anchor="middle"
    font-size="300px" font-family="Verdana" font-weight="bold"
    fill="url(#textBackground)">I U
  </text>

</svg>


We see two nice big block letters!


Our goal is to have "I ♥ U" as the final image, so let's work backwards and create a pink heart. In this case, it's a path. I copied it from a previous repository to save time, and adjusted the position.
<svg width="800px" height="400px" style="display:block; margin:5% auto 0 auto">
  <defs>
    <linearGradient id="textBackground" x1="0" x2="0" y1="0" y2="1">
      <stop offset="0%" stop-color="rgb(255, 50, 50)" />
      <stop offset="40%" stop-color="rgb(255, 200, 200)" />
      <stop offset="60%" stop-color="rgb(255, 200, 200)" />
      <stop offset="100%" stop-color="rgb(255, 50, 50)" />
    </linearGradient>
  </defs>  

  <text x="400px" y="300px" text-anchor="middle"
    font-size="300px" font-family="Verdana" font-weight="bold"
    fill="url(#textBackground)">I U
  </text>

  <path d="M 350 150
    q -50 -60, -100 0
    q -50 80, 100 150
    q 150 -70, 100 -150
    q -50 -60, -100 0
    Z"
  >

  </path>

</svg>


We set the fill to a gradient background which we'll create shortly, The outline will be a translucent pink.
<path d="M 350 150
  q -50 -60, -100 0
  q -50 80, 100 150
  q 150 -70, 100 -150
  q -50 -60, -100 0
  Z"

  fill="url(#pinkheartBackground)" stroke="rgba(255, 200, 200, 0.2)" stroke-width="10px"
>

</path>


Because we haven't created the background yet, you should only see the outline of the heart.


In the definitions, create the pinkheartBackground gradient. It will be radial, going from almost white, then pink, then deep pink.
<defs>
  <linearGradient id="textBackground" x1="0" x2="0" y1="0" y2="1">
    <stop offset="0%" stop-color="rgb(255, 50, 50)" />
    <stop offset="40%" stop-color="rgb(255, 200, 200)" />
    <stop offset="60%" stop-color="rgb(255, 200, 200)" />
    <stop offset="100%" stop-color="rgb(255, 50, 50)" />
  </linearGradient>

  <radialGradient id="pinkheartBackground" cx="10%" cy="10%" r="90%" fx="10%" fy="10%">
    <stop offset="0%" style="stop-color:rgb(255, 250, 250); stop-opacity:1" />
    <stop offset="20%" style="stop-color:rgb(255, 220, 220); stop-opacity:1" />
    <stop offset="90%" style="stop-color:rgb(220, 200, 200); stop-opacity:1" />
    <stop offset="100%" style="stop-color:rgb(200, 150, 150); stop-opacity:1" />
  </radialGradient>

</defs>  


There's a pink heart!


We're now going to cover the letters with red hearts. To that end, let's first define the gradient. It's basically a copy of pinkheartBackground but with redder hues.
<defs>
  <linearGradient id="textBackground" x1="0" x2="0" y1="0" y2="1">
    <stop offset="0%" stop-color="rgb(255, 50, 50)" />
    <stop offset="40%" stop-color="rgb(255, 200, 200)" />
    <stop offset="60%" stop-color="rgb(255, 200, 200)" />
    <stop offset="100%" stop-color="rgb(255, 50, 50)" />
  </linearGradient>

  <radialGradient id="pinkheartBackground" cx="10%" cy="10%" r="90%" fx="10%" fy="10%">
    <stop offset="0%" style="stop-color:rgb(255, 250, 250); stop-opacity:1" />
    <stop offset="20%" style="stop-color:rgb(255, 220, 220); stop-opacity:1" />
    <stop offset="90%" style="stop-color:rgb(220, 200, 200); stop-opacity:1" />
    <stop offset="100%" style="stop-color:rgb(200, 150, 150); stop-opacity:1" />
  </radialGradient>

  <radialGradient id="redheartBackground" cx="10%" cy="10%" r="90%" fx="10%" fy="10%">
    <stop offset="0%" style="stop-color:rgb(255, 150, 150); stop-opacity:1" />
    <stop offset="20%" style="stop-color:rgb(255, 100, 100); stop-opacity:1" />
    <stop offset="90%" style="stop-color:rgb(220, 0, 0); stop-opacity:1" />
    <stop offset="100%" style="stop-color:rgb(200, 0, 0); stop-opacity:1" />
  </radialGradient>

</defs>  


Now let's create one heart. It's a copy of the pink heart, but using redheartBackground as the fill, and a red outline.
<text x="400px" y="300px" text-anchor="middle"
  font-size="300px" font-family="Verdana" font-weight="bold"
  fill="url(#textBackground)">I U
</text>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
>

</path>


<path d="M 350 150
  q -50 -60, -100 0
  q -50 80, 100 150
  q 150 -70, 100 -150
  q -50 -60, -100 0
  Z"

  fill="url(#pinkheartBackground)" stroke="rgba(255, 200, 200, 0.2)" stroke-width="10px"
>

</path>


But you won't see much, because that red heart will be directly behind the pink heart. Let's apply a bit of translation and rotation to it. We won't scale this one, but let's include it in there, anyway. transform-origin should be set to the middle of the heart.
<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(100, -50) rotate(-30) scale(1, 1)"
>

</path>


Now you can see a bit of it peeking out!


Now we are going to place differently translated, rotated and scaled red hearts in the SVG. You don't have to do it exactly how I did, I just did these at random.
<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(100, -50) rotate(-30) scale(1, 1)"
>

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(200, 0) rotate(90) scale(0.8, 0.8)"
>

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(200, 50) rotate(-20) scale(1, 1)"
>

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(0, 50) rotate(-90) scale(0.8, 0.8)"
>

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(-150, -100) rotate(-20) scale(1, 1)"
>

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(-150, 100) rotate(50) scale(0.8, 0.8)"
>

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(-50, -50) rotate(-50) scale(1, 1)"
>

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(50, -150) rotate(-20) scale(0.5, 0.5)"
>

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(0, -100) rotate(-80) scale(0.5, 0.5)"
>

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(-250, 150) rotate(100) scale(0.5, 0.5)"
>

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(-50, 50) rotate(-60) scale(0.5, 0.5)"
>

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(150, 50) rotate(80) scale(0.5, 0.5)"
>

</path>

<path d="M 350 150
  q -50 -60, -100 0
  q -50 80, 100 150
  q 150 -70, 100 -150
  q -50 -60, -100 0
  Z"

  fill="url(#pinkheartBackground)" stroke="rgba(255, 200, 200, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(0, 0) scale(1, 1)"
>

</path>


Yep, all these hearts.


Now on to animation!

We've set the stage. We want the pink heart to look like it fell right onto the heap of red hearts. To do that, we first scale the pink heart upwards, i.e, increase its size.
<path d="M 350 150
  q -50 -60, -100 0
  q -50 80, 100 150
  q 150 -70, 100 -150
  q -50 -60, -100 0
  Z"

  fill="url(#pinkheartBackground)" stroke="rgba(255, 200, 200, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(0, 0) scale(1.5, 1.5)"
>


See what we did to the pink heart?


Now, we are going to simulate a fall "towards" the red hearts. TO that end, we will reduce the size of the pink heart in animation. To that end we will add the animateTransform tag. What we are going to alter is the transform attribute, thus transform will be the value of attributeName. We want to alter the scale, so that's the value of type. from and to attributes are straightforward. The original values are 1.5, and we want to scale it down to 0.5.
<path d="M 350 150
  q -50 -60, -100 0
  q -50 80, 100 150
  q 150 -70, 100 -150
  q -50 -60, -100 0
  Z"

  fill="url(#pinkheartBackground)" stroke="rgba(255, 200, 200, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(0, 0) scale(1.5, 1.5)"
>
  <animateTransform
    attributeName="transform"
    type="scale"
    from="1.5 1.5"
    to="0.5 0.5"
  />

</path>


Then we further add details. begin will be set to 0 seconds so that the animation fires off as soon as the SVG loads. dur is how long the animation lasts, and I specified 1.5 seconds. We set repeatCount to 1, which means it only happens once.
<animateTransform
  attributeName="transform"
  type="scale"
  from="1.5 1.5"
  to="0.5 0.5"
  begin="0s"
  fill="freeze"
  dur="1.5s"
  repeatCount="1"

/>


Refresh. Your pink heart should appear large, then grow smaller as it "falls".


Here, I've added some more scaling animations to reflect the pink heart shaking as it "hits" the red hearts and stops. You notice that the last one has an id, finalPinkHeartScale. This is a bad naming convention because this is far from "final", but in any case, we need this one to have an id because we are going to be taking reference from it.
<path d="M 350 150
  q -50 -60, -100 0
  q -50 80, 100 150
  q 150 -70, 100 -150
  q -50 -60, -100 0
  Z"

  fill="url(#pinkheartBackground)" stroke="rgba(255, 200, 200, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(0, 0) scale(1.5, 1.5)"
>
  <animateTransform
    attributeName="transform"
    type="scale"
    from="1.5 1.5"
    to="0.5 0.5"
    begin="0s"
    fill="freeze"
    dur="1.5s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.5 0.5"
    to="0.6 0.6"
    begin="1.5s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />


  <animateTransform
    id="finalPinkHeartScale"
    attributeName="transform"
    type="scale"
    from="0.6 0.6"
    to="0.5 0.5"
    begin="1.7s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

</path>


Time to animate the red hearts. We want each red heart to look like the pink heart is "absorbing" it. So we should have it move back towards the center of the pink heart and shrink till nothing while doing that. Let's use the first red heart as an example. Add an animation. Again attributeName is transform, type is translate, and we take reference from the path tag's transform attribute's translate directive. From that value to 0, which is, not-so-coincidentally, where the pink heart is.
<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(100, -50) rotate(-30) scale(1, 1)"
>
  <animateTransform
    attributeName="transform" type="translate" from="100 -50" to="0 0"
  />   
 
</path>


We need to make it start half a second after finalPinkHeartScale ends. I set this animation's duration at 1 second. We don't want this to repeat, so set repeatCount to 1.
<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(100, -50) rotate(-30) scale(1, 1)"
>
  <animateTransform
    attributeName="transform" type="translate" from="100 -50" to="0 0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="1s" repeatCount="1"
  />    
</path>


Here's a second animation. This one makes the red heart shrink to 0. Again, the from attribute should take reference from the path tag's transform attribute's scale directive. We need to add the additive attribute and set it to sum. This is so that it doesn't mess up the first animation.
<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(100, -50) rotate(-30) scale(1, 1)"
>
  <animateTransform
    attributeName="transform" type="translate" from="100 -50" to="0 0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="1s" repeatCount="1"
  />  

  <animateTransform
    attributeName="transform" type="scale" from="1 1" to="0 0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="1s" repeatCount="1" additive="sum"
  />  

</path>


We add a third animation to "reset" rotation to 0. As before, the additive attribute is sum.
<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(100, -50) rotate(-30) scale(1, 1)"
>
  <animateTransform
    attributeName="transform" type="translate" from="100 -50" to="0 0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="1s" repeatCount="1"
  />  

  <animateTransform
    attributeName="transform" type="scale" from="1 1" to="0 0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="1s" repeatCount="1" additive="sum"
  />  

  <animateTransform
    attributeName="transform" type="rotate" from="-30" to="0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="1s" repeatCount="1" additive="sum"
  />  

</path>


Now do this for all red hearts! I varied the begin and dur attributes for all of them.
<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(100, -50) rotate(-30) scale(1, 1)"
>
  <animateTransform
    attributeName="transform" type="translate" from="100 -50" to="0 0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="1s" repeatCount="1"
  />  

  <animateTransform
    attributeName="transform" type="scale" from="1 1" to="0 0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="1s" repeatCount="1" additive="sum"
  />  

  <animateTransform
    attributeName="transform" type="rotate" from="-30" to="0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="1s" repeatCount="1" additive="sum"
  />  
</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(200, 0) rotate(90) scale(0.8, 0.8)"
>
  <animateTransform
    attributeName="transform" type="translate" from="200 0" to="0 0"
    begin="finalPinkHeartScale.end+1s" fill="freeze" dur="0.5s" repeatCount="1"
  />  

  <animateTransform
    attributeName="transform" type="scale" from="0.8 0.8" to="0 0"
    begin="finalPinkHeartScale.end+1s" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

  <animateTransform
    attributeName="transform" type="rotate" from="90" to="0"
    begin="finalPinkHeartScale.end+1s" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />
  
</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(200, 50) rotate(-20) scale(1, 1)"
>
  <animateTransform
    attributeName="transform" type="translate" from="200 50" to="0 0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="0.5s" repeatCount="1"
  />  

  <animateTransform
    attributeName="transform" type="scale" from="1 1" to="0 0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

  <animateTransform
    attributeName="transform" type="rotate" from="-20" to="0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(0, 50) rotate(-90) scale(0.8, 0.8)"
>
  <animateTransform
    attributeName="transform" type="translate" from="0 50" to="0 0"
    begin="finalPinkHeartScale.end+1s" fill="freeze" dur="0.5s" repeatCount="1"
  />  

  <animateTransform
    attributeName="transform" type="scale" from="0.8 0.8" to="0 0"
    begin="finalPinkHeartScale.end+1s" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

  <animateTransform
    attributeName="transform" type="rotate" from="-90" to="0"
    begin="finalPinkHeartScale.end+1s" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(-150, -100) rotate(-20) scale(1, 1)"
>
  <animateTransform
    attributeName="transform" type="translate" from="-150 -100" to="0 0"
    begin="finalPinkHeartScale.end+1s" fill="freeze" dur="0.5s" repeatCount="1"
  />  

  <animateTransform
    attributeName="transform" type="scale" from="1 1" to="0 0"
    begin="finalPinkHeartScale.end+1s" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

  <animateTransform
    attributeName="transform" type="rotate" from="-20" to="0"
    begin="finalPinkHeartScale.end+1s" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(-150, 100) rotate(50) scale(0.8, 0.8)"
>
  <animateTransform
    attributeName="transform" type="translate" from="-150 100" to="0 0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="0.5s" repeatCount="1"
  />  

  <animateTransform
    attributeName="transform" type="scale" from="0.8 0.8" to="0 0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

  <animateTransform
    attributeName="transform" type="rotate" from="50" to="0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(-50, -50) rotate(-50) scale(1, 1)"
>
  <animateTransform
    attributeName="transform" type="translate" from="-50 -50" to="0 0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="1s" repeatCount="1"
  />  

  <animateTransform
    attributeName="transform" type="scale" from="1 1" to="0 0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="1s" repeatCount="1" additive="sum"
  />  

  <animateTransform
    attributeName="transform" type="rotate" from="-50" to="0"
    begin="finalPinkHeartScale.end+0.5s" fill="freeze" dur="1s" repeatCount="1" additive="sum"
  />  

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(50, -150) rotate(-20) scale(0.5, 0.5)"
>
  <animateTransform
    attributeName="transform" type="translate" from="50 -150" to="0 0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="0.5s" repeatCount="1"
  />  

  <animateTransform
    attributeName="transform" type="scale" from="0.5 0.5" to="0 0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

  <animateTransform
    attributeName="transform" type="rotate" from="-20" to="0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(0, -100) rotate(-80) scale(0.5, 0.5)"
>
  <animateTransform
    attributeName="transform" type="translate" from="0 -100" to="0 0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="1s" repeatCount="1"
  />  

  <animateTransform
    attributeName="transform" type="scale" from="0.5 0.5" to="0 0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="1s" repeatCount="1" additive="sum"
  />  

  <animateTransform
    attributeName="transform" type="rotate" from="-80" to="0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="1s" repeatCount="1" additive="sum"
  />  

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(-250, 150) rotate(100) scale(0.5, 0.5)"
>
  <animateTransform
    attributeName="transform" type="translate" from="-250 150" to="0 0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="1s" repeatCount="1"
  />  

  <animateTransform
    attributeName="transform" type="scale" from="0.5 0.5" to="0 0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="1s" repeatCount="1" additive="sum"
  />  

  <animateTransform
    attributeName="transform" type="rotate" from="100" to="0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="1s" repeatCount="1" additive="sum"
  />  

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(-50, 50) rotate(-60) scale(0.5, 0.5)"
>
  <animateTransform
    attributeName="transform" type="translate" from="-50 50" to="0 0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="0.5s" repeatCount="1"
  />  

  <animateTransform
    attributeName="transform" type="scale" from="0.5 0.5" to="0 0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

  <animateTransform
    attributeName="transform" type="rotate" from="-60" to="0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

</path>

<path d="M 350 150 q -50 -60, -100 0 q -50 80, 100 150 q 150 -70, 100 -150 q -50 -60, -100 0 Z"
  fill="url(#redheartBackground)" stroke="rgba(255, 0, 0, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(150, 50) rotate(80) scale(0.5, 0.5)"
>
  <animateTransform
    attributeName="transform" type="translate" from="150 50" to="0 0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="0.5s" repeatCount="1"
  />  

  <animateTransform
    attributeName="transform" type="scale" from="0.5 0.5" to="0 0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

  <animateTransform
    attributeName="transform" type="rotate" from="80" to="0"
    begin="finalPinkHeartScale.end" fill="freeze" dur="0.5s" repeatCount="1" additive="sum"
  />  

</path>


See all these hearts starting to move...


...and some of them are still staying in place...


...but eventually they all get "absorbed".


This does not look all that realistic. The pink heart should actually get bigger the more red hearts it "absorbs". So add another animation to increase the size of the pink heart, half a second after finalPinkHeartScale ends, to coincide with some of the "absorbings".
<path d="M 350 150
  q -50 -60, -100 0
  q -50 80, 100 150
  q 150 -70, 100 -150
  q -50 -60, -100 0
  Z"

  fill="url(#pinkheartBackground)" stroke="rgba(255, 200, 200, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(0, 0) scale(1.5, 1.5)"
>
  <animateTransform
    attributeName="transform"
    type="scale"
    from="1.5 1.5"
    to="0.5 0.5"
    begin="0s"
    fill="freeze"
    dur="1.5s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.5 0.5"
    to="0.6 0.6"
    begin="1.5s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    id="finalPinkHeartScale"
    attributeName="transform"
    type="scale"
    from="0.6 0.6"
    to="0.5 0.5"
    begin="1.7s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.4 0.4"
    to="0.7 0.7"
    begin="finalPinkHeartScale.end+0.5s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

</path>


A little more...
<path d="M 350 150
  q -50 -60, -100 0
  q -50 80, 100 150
  q 150 -70, 100 -150
  q -50 -60, -100 0
  Z"

  fill="url(#pinkheartBackground)" stroke="rgba(255, 200, 200, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(0, 0) scale(1.5, 1.5)"
>
  <animateTransform
    attributeName="transform"
    type="scale"
    from="1.5 1.5"
    to="0.5 0.5"
    begin="0s"
    fill="freeze"
    dur="1.5s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.5 0.5"
    to="0.6 0.6"
    begin="1.5s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    id="finalPinkHeartScale"
    attributeName="transform"
    type="scale"
    from="0.6 0.6"
    to="0.5 0.5"
    begin="1.7s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.4 0.4"
    to="0.7 0.7"
    begin="finalPinkHeartScale.end+0.5s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.5 0.5"
    to="0.9 0.9"
    begin="finalPinkHeartScale.end+1s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

</path>


...and some more.
<path d="M 350 150
  q -50 -60, -100 0
  q -50 80, 100 150
  q 150 -70, 100 -150
  q -50 -60, -100 0
  Z"

  fill="url(#pinkheartBackground)" stroke="rgba(255, 200, 200, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(0, 0) scale(1.5, 1.5)"
>
  <animateTransform
    attributeName="transform"
    type="scale"
    from="1.5 1.5"
    to="0.5 0.5"
    begin="0s"
    fill="freeze"
    dur="1.5s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.5 0.5"
    to="0.6 0.6"
    begin="1.5s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    id="finalPinkHeartScale"
    attributeName="transform"
    type="scale"
    from="0.6 0.6"
    to="0.5 0.5"
    begin="1.7s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.4 0.4"
    to="0.7 0.7"
    begin="finalPinkHeartScale.end+0.5s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.5 0.5"
    to="0.9 0.9"
    begin="finalPinkHeartScale.end+1s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

 <animateTransform 
    attributeName="transform"
    type="scale"
    from="0.7 0.7"
    to="1 1"
    begin="finalPinkHeartScale.end+1.5s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
 />
</path>


Finally, I have an animation applied on the stroke-width attribute that will carry on indefinitely once the pink heart has grown to its full size.
<path d="M 350 150
  q -50 -60, -100 0
  q -50 80, 100 150
  q 150 -70, 100 -150
  q -50 -60, -100 0
  Z"

  fill="url(#pinkheartBackground)" stroke="rgba(255, 200, 200, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(0, 0) scale(1.5, 1.5)"
>
  <animateTransform
    attributeName="transform"
    type="scale"
    from="1.5 1.5"
    to="0.5 0.5"
    begin="0s"
    fill="freeze"
    dur="1.5s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.5 0.5"
    to="0.6 0.6"
    begin="1.5s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    id="finalPinkHeartScale"
    attributeName="transform"
    type="scale"
    from="0.6 0.6"
    to="0.5 0.5"
    begin="1.7s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.4 0.4"
    to="0.7 0.7"
    begin="finalPinkHeartScale.end+0.5s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.5 0.5"
    to="0.9 0.9"
    begin="finalPinkHeartScale.end+1s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.7 0.7"
    to="1 1"
    begin="finalPinkHeartScale.end+1.5s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animate
    attributeName="stroke-width"
    values="10px; 50px; 10px"
    begin="finalPinkHeartScale.end+1.5s"
    fill="freeze"
    dur="0.5s"
    repeatCount="indefinite"
  />

</path>


Tell me this ain't awesome.



Final touches...

This is entirely superfluous, but still fun to do. Add two circles to the SVG. Both are a translucent deep pink, though the second one is more translucent. You won't see anything since both have r attributes set to 0.
<path d="M 350 150
  q -50 -60, -100 0
  q -50 80, 100 150
  q 150 -70, 100 -150
  q -50 -60, -100 0
  Z"

  fill="url(#pinkheartBackground)" stroke="rgba(255, 200, 200, 0.2)" stroke-width="10px"
  transform-origin="50% 50%" transform="translate(0, 0) scale(1.5, 1.5)"
>
  <animateTransform
    attributeName="transform"
    type="scale"
    from="1.5 1.5"
    to="0.5 0.5"
    begin="0s"
    fill="freeze"
    dur="1.5s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.5 0.5"
    to="0.6 0.6"
    begin="1.5s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    id="finalPinkHeartScale"
    attributeName="transform"
    type="scale"
    from="0.6 0.6"
    to="0.5 0.5"
    begin="1.7s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.4 0.4"
    to="0.7 0.7"
    begin="finalPinkHeartScale.end+0.5s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.5 0.5"
    to="0.9 0.9"
    begin="finalPinkHeartScale.end+1s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animateTransform
    attributeName="transform"
    type="scale"
    from="0.7 0.7"
    to="1 1"
    begin="finalPinkHeartScale.end+1.5s"
    fill="freeze"
    dur="0.2s"
    repeatCount="1"
  />

  <animate
    attributeName="stroke-width"
    values="10px; 50px; 10px"
    begin="finalPinkHeartScale.end+1.5s"
    fill="freeze"
    dur="0.5s"
    repeatCount="indefinite"
  />
</path>

<circle r="0" fill="rgba(200, 150, 150, 0.8)">

</circle>

<circle r="0" fill="rgba(200, 150, 150, 0.5)">

</circle>


We want each circle to traverse the perimeter of the pink heart. So we'll input the path for the pink heart into an animateMotion animation. We want this to begin only after finalPinkHeartScale. The duration is set to 5 seconds and we set this to animate forever.
<circle r="0" fill="rgba(200, 150, 150, 0.8)">
  <animateMotion
    path="M 350 150
    q -50 -60, -100 0
    q -50 80, 100 150
    q 150 -70, 100 -150
    q -50 -60, -100 0
    Z"
    begin="finalPinkHeartScale.end+1.5s"
    fill="freeze"
    dur="5s"
    repeatCount="indefinite"
  />

</circle>

<circle r="0" fill="rgba(200, 150, 150, 0.5)">

</circle>


And here's another animation, this one animating the r attribute from 5 to 10 pixels. This animation is faster and will also repeat forever.
<circle r="0" fill="rgba(200, 150, 150, 0.8)">
  <animateMotion
    path="M 350 150
    q -50 -60, -100 0
    q -50 80, 100 150
    q 150 -70, 100 -150
    q -50 -60, -100 0
    Z"
    begin="finalPinkHeartScale.end+1.5s"
    fill="freeze"
    dur="5s"
    repeatCount="indefinite"
  />
  
  <animate
    attributeName="r"
    values="5px; 10px; 5px"
    begin="finalPinkHeartScale.end+1.5s"
    fill="freeze"
    dur="0.5s"
    repeatCount="indefinite"
  />

</circle>

<circle r="0" fill="rgba(200, 150, 150, 0.5)">

</circle>


We'll do the same for the second circle, but with slightly different animaton values for contrast.
<circle r="0" fill="rgba(200, 150, 150, 0.8)">
  <animateMotion
    path="M 350 150
    q -50 -60, -100 0
    q -50 80, 100 150
    q 150 -70, 100 -150
    q -50 -60, -100 0
    Z"
    begin="finalPinkHeartScale.end+1.5s"
    fill="freeze"
    dur="5s"
    repeatCount="indefinite"
  />
  
  <animate
    attributeName="r"
    values="5px; 10px; 5px"
    begin="finalPinkHeartScale.end+1.5s"
    fill="freeze"
    dur="0.5s"
    repeatCount="indefinite"
  />
</circle>

<circle r="0" fill="rgba(200, 150, 150, 0.5)">
  <animateMotion
    path="M 350 150
    q -50 -60, -100 0
    q -50 80, 100 150
    q 150 -70, 100 -150
    q -50 -60, -100 0
    Z"
    begin="finalPinkHeartScale.end+1.5s"
    fill="freeze"
    dur="3s"
    repeatCount="indefinite"
  />
  
  <animate
    attributeName="r"
    values="3px; 10px; 3px"
    begin="finalPinkHeartScale.end+1.5s"
    fill="freeze"
    dur="0.5s"
    repeatCount="indefinite"
  />

</circle>


And there you have the two translucent deep pink circles traversing the perimeter of the pink heart.


Well, it's been a pleasure!

SVG animations can be a lot of fun, especially when we're just doing silly inconsequential stuff like that. Have a nice, romantic week!

Don't U just ♥ SVG?
T____T

Thursday, 6 February 2025

Tech Democratization in the Era of Artificial Intelligence

There's a term that I have been seeing more of late: Tech Democratization. More precisely, I first heard it while watching this speech by Nvdia CEO Jensen Huang.



"And so I think that democratizing, activating every region, activating every country to join the A.I advance, is probably one of the more important things, rather than convincing everybody it's too complicated, it's too dangerous, it's too mystical and only two or three people in the world should be allowed to do that."


To be honest, the first time I heard the term, I was perturbed and more than a little offended. Like what, tech needs to be democratized? As opposed to it being a dictatorship right now? However, after researching the term a bit, it's not as acrimonious as one might think.

So, what is Tech Democratization exactly?

Tech Democratization describes a state of tech where creation of software (web portals, applications and such) can be carried out without relying on the expertise of technically qualified people. In short, laypeople would no longer need tech professionals for these things.

At least, that's the promise of Tech Democratization. It brings the power to create, to the masses, instead of keeping it in the hands of the elite few. More importantly, the power to create without needing a technical foundation acquirable only by years of training. As a concept, Tech Democratization is not new. One could even argue that it started all the way back in the 60s where high level languages were created so that people like me wouldn't need to deal with Assembly, thus opening up possibilities for a less hardcore breed of nerd.

Building without the
need for expertise.

How about frameworks? Frameworks were created back in the day (and are still in use now) to reduce repetition in coding, and thus reduce the amount of code developers needed to write for a typical application. Now that code in scaffolding no longer needed to be written from scratch, surely this meant that application programming was now opened to a lot more people.

Web development came up with content management systems and even entire website builders to allow the man in the street to create websites without needing to know any HTML, CSS or JavaScript. Low-Code platforms bring this to a new level, allowing laypeople to create simple applications without knowing having much of a technical foundation at all.

From this point of view, A.I is merely the latest in a long line of innovations that outsource the repetitive parts of writing code to the system, so that the human can focus on the creative bits.

The Scariness of Tech Democratization

A.I is a tool made by actual software engineers. Even if non-technical people can now use this tool to create software that would previously be out of their reach, this still does not make them engineers. It sounds obvious now the way I say it, but it is human nature to get carried away by the perception of ones own perceived ability.

The danger is that non-technical people using A.I as a tool to generate code, will start thinking that they can replace actual developers. It does not matter whether or not this is true. What matters is that these laypersons, having not actually encountered software development in all its glorious and terrible complexity, will create a few working apps and start wondering what the big deal is, precisely because they are unburdened by that knowledge.

How much should
non-techies control?

Imagine a world in which software that runs air traffic routes or maintains banking transactions, is created with the help of A.I and people who don't actually understand software development, but are given the ability to act as if they do. Are you afraid yet? No? Perhaps you should be.

Me? I'm at the tail end of my career. Professionally, there's nothing I could lose to A.I that I don't already plan on giving up in a few years. I don't fear losing my job to A.I. It's a tiny consequence compared to the terrible implications I just outlined. And that's all I'm doing - outlining those implications. In no way do I think Tech Democratization is a bad thing.

Besides, it would be hypocritical of me to start decrying Tech Democratization now. I, too, am a beneficiary of Tech Democratization. Were it not for the significant effort put in by engineers better than myself, I would not have the tools - databases, operating systems and programming languages - I use so readily today. I recognize and acknowledge my privelege, and would never presume to place myself in the same bracket as the tech professionals who made those tools.

There's a stark difference between developers benefitting from such tools, and laypersons doing the same. Developers have (generally) the technical foundation, in some cases to the point where those tools would merely be helping them do things they already know how to do, but faster. Laypersons, on the other hand, would be hapless infants without those tools, at least where accomplishing those specific technical tasks were concerned. That, I think, is an important distinction.

In conclusion

Look, I'm not some sort of tech elitist or wannabe gatekeeper. I'm just not. But it's one thing to allow the general public the power to write software. It's quite another to consider them on the same level as people who have been doing this for years (or, in the case of Jensen Huang, claim that "everyone is now a programmer"), just because there are tools to help them accomplish the same goals. That is laughable.

Faster than Phelps.

It is absurdity on the level of me claiming to be as qualified an athlete as Michael Phelps just because I can outpace him on a jetski. Or claiming to be as qualified as my family doctor just because I can read up on medical symptoms on WebMD.

Tech Democratization has value. Like all things with value, however, one has to know exactly how far to take it. Speeding up the work of developers or automating away routine tasks is a great idea. Giving every schmuck the tools to write simple apps? Also a pretty good idea. Allowing them to think that software development is actually that easy? There are not enough words in the dictionary to describe what a horrible idea that would be.

Democracy now!
T___T