<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Ben - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Ben - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 16 May 2026 16:28:54 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/justanothertechlead/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Why Vibe Coding Won't Destroy Software Engineering ]]>
                </title>
                <description>
                    <![CDATA[ AI is disrupting all industries at a pace not seen at any time in history. Technologies and industries that were once dominated by one or two companies or were very much “human-focused” are coming under threat. Google is losing ground to AI search, t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/why-vibe-coding-wont-destroy-software-engineering/</link>
                <guid isPermaLink="false">682df55da72360814bcae9ef</guid>
                
                    <category>
                        <![CDATA[ vibe coding ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AI Coding Assistant ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ #ai-tools ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ben ]]>
                </dc:creator>
                <pubDate>Wed, 21 May 2025 15:46:37 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747835351675/3d178f26-c528-48b8-8ac2-32811a5672cf.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>AI is disrupting all industries at a pace not seen at any time in history.</p>
<p>Technologies and industries that were once dominated by one or two companies or were very much “human-focused” are coming under threat.</p>
<p><a target="_blank" href="https://www.smoothseo.co/blog/misc/what-the-numbers-say-about-ais-growing-role-in-search/">Google is losing ground to AI search</a>, <a target="_blank" href="https://www.axios.com/2022/03/28/automation-long-haul-truckers-jobs">truck drivers</a> may soon be a thing of the past, and low-skilled clerical <a target="_blank" href="https://news.sky.com/story/ai-risks-up-to-eight-million-uk-job-losses-with-low-skilled-worst-hit-report-warns-13102214">jobs are being lost every day</a>.</p>
<p>Will this disruption destroy the Software Engineering industry? I don’t think so, and I’ll tell you why.</p>
<h3 id="heading-heres-what-well-discuss">Here’s what we’ll discuss:</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-the-phenomenon-of-vibe-coding">The Phenomenon of "Vibe Coding"</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-ai-has-changed-software-development">How AI Has Changed Software Development</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-productivity-paradox">The Productivity Paradox</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-human-engineers-are-still-critical">Why Human Engineers Are Still Critical</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-ai-as-a-capability-multiplier">AI as a “Capability Multiplier”</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-critical-skills-for-the-ai-era">Critical Skills for the AI Era</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-path-forward">The Path Forward</a></p>
</li>
</ol>
<h2 id="heading-the-phenomenon-of-vibe-coding"><strong>The Phenomenon of "Vibe Coding"</strong></h2>
<p>If you follow tech discussions on X, you've likely seen the term "vibe coding" – the practice of building software through trial and error, intuition, and AI-generated code snippets without deep technical knowledge.</p>
<p>Modern AI assistants such as GitHub Copilot and ChatGPT can generate full functions, fix bugs, and create components based on simple descriptions. “Vibe Coders” are claiming that human coders will soon become obsolete.</p>
<p>From my perspective, these AI tools function more as skill multipliers than replacements.</p>
<p>They help talented developers work faster while exposing gaps in knowledge for less skilled programmers. Those lacking technical foundations will face problems they can't solve, but engineers who blend AI assistance with solid expertise will be able to be incredibly productive.</p>
<h2 id="heading-how-ai-has-changed-software-development"><strong>How AI Has Changed Software Development</strong></h2>
<p>The software industry has seen rapid adoption of AI coding tools based on Large Language Models that analyze code repositories to predict and suggest next steps.</p>
<p>These tools have transformed daily programming work by:</p>
<ul>
<li><p>Suggesting complete functions as you type</p>
</li>
<li><p>Creating API endpoints from plain language descriptions</p>
</li>
<li><p>Eliminating hours spent on standard code patterns</p>
</li>
<li><p>Automating documentation tasks</p>
</li>
<li><p>Handling repetitive logic quickly</p>
</li>
</ul>
<p>This shift toward "vibe coding" speeds up feature delivery. Programmers can now build without mastering every technical detail – they describe what they want, get AI suggestions, and adjust until the code works.</p>
<p>The risk? Developers often push code they can't explain. They move quickly during building but struggle when systems break or need changing.</p>
<p>There's also a concerning trend of non-programmers selling AI-built applications. Recently, someone with zero coding background launched a paid service created entirely through AI prompts, only to face a data breach days later when hackers exploited basic security flaws. This is dangerous. It has wasted people's money and exposed their data. Imagine if this became common place due to the rise of “vibe coders”?</p>
<p>For anyone considering building software who isn’t a software engineer, there are a few basic levels of security that you need to consider:</p>
<ul>
<li><p>Adding authentication to your API endpoints: People can scan for open ports and endpoints across the internet. If they can then call your API endpoints without being authenticated, it can cause all sorts of problems</p>
</li>
<li><p>Do not store passwords in plain text. This is a big no no. If you do this and your database gets exposed, those passwords are there for all to see. And if we’re being real, people re-use passwords, so those passwords will be their passwords for other sites too.</p>
</li>
<li><p>SSL: Make sure your website is secure and has an up to date SSL certificate. Transmitting data in plain text is dangerous.</p>
</li>
<li><p>Lock down unused ports: If you are hosting a backend service, make sure that any ports that you don’t use are locked down and people aren’t able to connect to them.</p>
</li>
<li><p>If you have areas where people can upload files, limit the uploads to specific file types.</p>
</li>
</ul>
<p>Those are just a few considerations around security for your site or product, but there are many more.</p>
<h2 id="heading-the-productivity-paradox"><strong>The Productivity Paradox</strong></h2>
<p>AI assistance dramatically increases code output – but volume doesn't equal value in software engineering.</p>
<p>These tools excel at syntax but have no understanding about system architecture, scalability concerns, and maintenance requirements. Just as typing speed doesn't create a better novel, code generation speed doesn't produce better software systems.</p>
<p>AI works for individual functions but struggles with architectural decisions, security planning, and long-term support needs. Without proper review and understanding, AI-generated code often becomes tomorrow's tech-debt and maintenance burden.</p>
<p>Consider this scenario: A developer implements an AI-created authentication system that works in isolation but causes subtle failures in users signing up to the product. Finding and fixing these integration issues might take experienced staff several days – negating any initial time savings. This is a quick path to losing money and trust.</p>
<h2 id="heading-why-human-engineers-are-still-critical"><strong>Why Human Engineers Are Still Critical</strong></h2>
<p>While AI tools handle syntax well, they cannot:</p>
<ol>
<li><p>Plan systems that grow with user demand</p>
</li>
<li><p>Create reliable deployment and testing pipelines</p>
</li>
<li><p>Anticipate unusual but critical failure cases</p>
</li>
<li><p>Make smart tradeoffs between performance and cost</p>
</li>
<li><p>Find non-obvious security weaknesses</p>
</li>
</ol>
<p>Great engineers think beyond code. They develop patterns that help entire teams, select the right technologies, and plan both for success and failure scenarios.</p>
<p>Software creation involves complex tradeoffs: Do we prioritize speed or stability? Flexibility or simplicity? These decisions require both technical expertise and business knowledge.</p>
<p>The highest value engineers I work with spend more time thinking than typing. They consider: How will requirements evolve? What stress points might emerge? How will the system recover from failures?</p>
<p>As basic code generation becomes widely accessible, your value comes from understanding system interactions. The competitive edge will be with those who know why certain approaches succeed, where they might fail, and how to build resilient solutions.</p>
<p>Per the above, there are some things that AI without proper oversight can not do.</p>
<p>AI can, for instance, be great at passing simple prompts to create solutions to well known problems. If you use this prompt, for example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747771377197/8aae1332-f852-435a-a724-a1770a4163bf.png" alt="Prompt: &quot;Create a Python module that will tell you if some input JSON is valid&quot;" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Here’s the code you might get:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">is_valid_json</span>(<span class="hljs-params">input_string: str</span>) -&gt; bool:</span>
    <span class="hljs-string">"""
    Checks if the input string is valid JSON.

    Args:
        input_string (str): The JSON string to validate.

    Returns:
        bool: True if valid, False otherwise.
    """</span>
    <span class="hljs-keyword">try</span>:
        json.loads(input_string)
        <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
    <span class="hljs-keyword">except</span> json.JSONDecodeError:
        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
    user_input = input(<span class="hljs-string">"Enter a JSON string to validate: "</span>)
    <span class="hljs-keyword">if</span> is_valid_json(user_input):
        print(<span class="hljs-string">"✅ The input is valid JSON."</span>)
    <span class="hljs-keyword">else</span>:
        print(<span class="hljs-string">"❌ The input is NOT valid JSON."</span>)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    main()
</code></pre>
<p>Pretty basic.</p>
<p>I would not, though, ask an AI to build me a complex Forex Trading platform.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747771546630/d212d814-7785-4391-8e01-79e80c05da44.png" alt="d212d814-7785-4391-8e01-79e80c05da44" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>I’ll save you reading through all of the response, but suffice it to say that it was not able to do this for me.</p>
<p>I thought I’d break that down to a slightly smaller subset of a financial trading platform:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747771773603/b65e1a13-97aa-4276-81c7-55303e5a04c6.png" alt="Prompt: &quot;Create me an endpoint for a FIX message for an FX Financial security. Make it in Python and I want to be able to accept J messages. Security is key here, so I need this to be as secure as possible.&quot;" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Now, I will admit, this got closer. Here was the result:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> fastapi <span class="hljs-keyword">import</span> FastAPI, Request, HTTPException, Header
<span class="hljs-keyword">from</span> pydantic <span class="hljs-keyword">import</span> BaseModel, Field
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> Optional
<span class="hljs-keyword">import</span> hmac
<span class="hljs-keyword">import</span> hashlib
<span class="hljs-keyword">import</span> logging

app = FastAPI()

<span class="hljs-comment"># === CONFIGURATION ===</span>
SHARED_SECRET = <span class="hljs-string">b"super_secure_shared_secret"</span>  <span class="hljs-comment"># Keep this secure</span>

<span class="hljs-comment"># === LOGGING SETUP ===</span>
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(<span class="hljs-string">"ems.fix"</span>)

<span class="hljs-comment"># === Pydantic Model for Execution Report (simplified) ===</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExecutionReport</span>(<span class="hljs-params">BaseModel</span>):</span>
    msg_type: str = Field(default=<span class="hljs-string">"J"</span>, const=<span class="hljs-literal">True</span>)
    cl_ord_id: str  <span class="hljs-comment"># Tag 11</span>
    order_id: str   <span class="hljs-comment"># Tag 37</span>
    exec_id: str    <span class="hljs-comment"># Tag 17</span>
    exec_type: str  <span class="hljs-comment"># Tag 150</span>
    ord_status: str <span class="hljs-comment"># Tag 39</span>
    symbol: str     <span class="hljs-comment"># Tag 55 (e.g., EUR/USD)</span>
    side: str       <span class="hljs-comment"># Tag 54 (1=Buy, 2=Sell)</span>
    leaves_qty: float  <span class="hljs-comment"># Tag 151</span>
    cum_qty: float     <span class="hljs-comment"># Tag 14</span>
    avg_px: float      <span class="hljs-comment"># Tag 6</span>
    transact_time: str <span class="hljs-comment"># Tag 60 (ISO8601 string)</span>

<span class="hljs-comment"># === Helper: HMAC Validator ===</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">verify_signature</span>(<span class="hljs-params">payload: bytes, signature: str</span>) -&gt; bool:</span>
    computed = hmac.new(SHARED_SECRET, payload, hashlib.sha256).hexdigest()
    <span class="hljs-keyword">return</span> hmac.compare_digest(computed, signature)

<span class="hljs-comment"># === Endpoint ===</span>
<span class="hljs-meta">@app.post("/fix/execution-report")</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">receive_execution_report</span>(<span class="hljs-params">
    request: Request,
    x_signature: Optional[str] = Header(<span class="hljs-params">None</span>)
</span>):</span>
    body = <span class="hljs-keyword">await</span> request.body()

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> x_signature <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> verify_signature(body, x_signature):
        logger.warning(<span class="hljs-string">"Invalid or missing signature."</span>)
        <span class="hljs-keyword">raise</span> HTTPException(status_code=<span class="hljs-number">403</span>, detail=<span class="hljs-string">"Unauthorized"</span>)

    <span class="hljs-keyword">try</span>:
        report_data = ExecutionReport.parse_raw(body)
        logger.info(<span class="hljs-string">f"Execution Report received: <span class="hljs-subst">{report_data.dict()}</span>"</span>)
        <span class="hljs-comment"># ✅ Here, you'd handle order updates, booking, etc.</span>
        <span class="hljs-keyword">return</span> {<span class="hljs-string">"status"</span>: <span class="hljs-string">"ok"</span>, <span class="hljs-string">"message"</span>: <span class="hljs-string">"Execution Report received"</span>}
    <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
        logger.exception(<span class="hljs-string">"Invalid payload format."</span>)
        <span class="hljs-keyword">raise</span> HTTPException(status_code=<span class="hljs-number">400</span>, detail=<span class="hljs-string">f"Invalid FIX message format: <span class="hljs-subst">{str(e)}</span>"</span>)
</code></pre>
<p>But this does not come close to the final version. Even if you could use this code as a part of your trading system, unless you know how to build and architect and entire software system, where do you go from here? You can tell your clients that they can send you an “ExecutionReport”, but then what?</p>
<p>I’ve read and heard the arguments that you “just need to be better at prompting to build bigger systems”. But where does the benefit come from then? The complexity of financial trading systems is beyond comprehension. Prompting a system well enough, with enough information to make it fully featured, scalable, secure, and extensible (not to mention able to be debugged) would itself be a mammoth task. So where is the time being saved? Is it even possible?</p>
<p>I’m yet to see any proof anywhere that anyone has build such a complex system without the oversight of a human, and I’m not convinced we will see it at any point in the near future.</p>
<h2 id="heading-ai-as-a-capability-multiplier"><strong>AI as a “Capability Multiplier”</strong></h2>
<p>These AI tools help magnify existing capabilities rather than replacing them. Skilled developers become far more productive, while less skilled ones generate problems more quickly.</p>
<p>Effective engineers use AI to:</p>
<ul>
<li><p>Handle basic implementation tasks</p>
</li>
<li><p>Create initial project frameworks</p>
</li>
<li><p>Compare different solution approaches</p>
</li>
<li><p>Move past challenging problems</p>
</li>
</ul>
<p>Meanwhile, less capable developers use AI to mask skill gaps, implementing solutions they neither understand nor can modify. When these implementations fail, they lack the knowledge to fix them independently.</p>
<p>This widens the skill gap. Top engineers leverage AI for mechanical tasks while focusing on higher-value thinking. Those using AI as a substitute for learning face limitations when working beyond the AI's knowledge boundaries.</p>
<p>A good example of something that AI is perfect for is translation logic:</p>
<p>Let’s say I have Python Dataclass representing an" “InternalUser”. I also have a Django ORM representation of the same entity. If I wanted to convert one to the other, I can just paste both representations in to ChatGPT and get it create me a conversion function. Notice that the conversion function also takes into account that the field names aren’t exact matches:</p>
<pre><code class="lang-python"><span class="hljs-meta">@dataclass</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InternalUser</span>:</span>
    id: str
    email: str
    hashed_password: str
    full_name: str
    role: UserRole
    status: AccountStatus
    created_at: datetime
    updated_at: datetime
    address: Optional[Address] = <span class="hljs-literal">None</span>
    preferences: Preferences = field(default_factory=Preferences)
    login_activity: LoginActivity = field(default_factory=LoginActivity)
    tags: List[str] = field(default_factory=list)
    notes: Optional[str] = <span class="hljs-literal">None</span>
</code></pre>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InternalUser</span>(<span class="hljs-params">models.Model</span>):</span>
    id = models.CharField(primary_key=<span class="hljs-literal">True</span>, max_length=<span class="hljs-number">100</span>)  <span class="hljs-comment"># Use UUIDField if preferred</span>
    email = models.EmailField(unique=<span class="hljs-literal">True</span>)
    hashedPassword = models.CharField(max_length=<span class="hljs-number">256</span>)
    fullName = models.CharField(max_length=<span class="hljs-number">255</span>)
    role = models.CharField(max_length=<span class="hljs-number">20</span>, choices=UserRole.choices, default=UserRole.USER)
    status = models.CharField(max_length=<span class="hljs-number">20</span>, choices=AccountStatus.choices, default=AccountStatus.PENDING)
    createdAt = models.DateTimeField(default=timezone.now)
    updatedAt = models.DateTimeField(auto_now=<span class="hljs-literal">True</span>)

    address = models.OneToOneField(Address, null=<span class="hljs-literal">True</span>, blank=<span class="hljs-literal">True</span>, on_delete=models.SET_NULL)
    preferences = models.OneToOneField(Preferences, on_delete=models.CASCADE)
    loginActivity = models.OneToOneField(LoginActivity, on_delete=models.CASCADE)

    tags = models.JSONField(default=list, blank=<span class="hljs-literal">True</span>)  <span class="hljs-comment"># List of strings</span>
    notes = models.TextField(null=<span class="hljs-literal">True</span>, blank=<span class="hljs-literal">True</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"<span class="hljs-subst">{self.fullName}</span> (<span class="hljs-subst">{self.email}</span>)"</span>
</code></pre>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> Optional
<span class="hljs-keyword">from</span> myapp.models <span class="hljs-keyword">import</span> InternalUser <span class="hljs-keyword">as</span> ORMInternalUser, Address <span class="hljs-keyword">as</span> ORMAddress, Preferences <span class="hljs-keyword">as</span> ORMPreferences, LoginActivity <span class="hljs-keyword">as</span> ORMLoginActivity
<span class="hljs-keyword">from</span> mydataclasses <span class="hljs-keyword">import</span> InternalUser <span class="hljs-keyword">as</span> DCInternalUser  <span class="hljs-comment"># assuming your dataclass lives here</span>


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">convert_internal_user_to_model</span>(<span class="hljs-params">dc_user: DCInternalUser</span>) -&gt; ORMInternalUser:</span>
    <span class="hljs-comment"># Create or update Address if provided</span>
    orm_address: Optional[ORMAddress] = <span class="hljs-literal">None</span>
    <span class="hljs-keyword">if</span> dc_user.address:
        orm_address = ORMAddress.objects.create(
            street=dc_user.address.street,
            city=dc_user.address.city,
            state=dc_user.address.state,
            postalCode=dc_user.address.postal_code,
            country=dc_user.address.country
        )

    <span class="hljs-comment"># Create Preferences</span>
    orm_preferences = ORMPreferences.objects.create(
        newsletterOptIn=dc_user.preferences.newsletter_opt_in,
        darkModeEnabled=dc_user.preferences.dark_mode_enabled,
        language=dc_user.preferences.language
    )

    <span class="hljs-comment"># Create LoginActivity</span>
    orm_login_activity = ORMLoginActivity.objects.create(
        lastLogin=dc_user.login_activity.last_login,
        loginAttempts=dc_user.login_activity.login_attempts,
        lastIpAddress=dc_user.login_activity.last_ip_address
    )

    <span class="hljs-comment"># Create InternalUser</span>
    orm_user = ORMInternalUser.objects.create(
        id=dc_user.id,
        email=dc_user.email,
        hashedPassword=dc_user.hashed_password,
        fullName=dc_user.full_name,
        role=dc_user.role.value,
        status=dc_user.status.value,
        createdAt=dc_user.created_at,
        updatedAt=dc_user.updated_at,
        address=orm_address,
        preferences=orm_preferences,
        loginActivity=orm_login_activity,
        tags=dc_user.tags,
        notes=dc_user.notes
    )

    <span class="hljs-keyword">return</span> orm_user
</code></pre>
<p>This is a basic example, but extrapolate this out to an entire internal data model and you’ve saved hours and hours of code.</p>
<p>You can even then ask it to create you the function stubs of the tests:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pytest
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime
<span class="hljs-keyword">from</span> yourmodule.dataclasses <span class="hljs-keyword">import</span> InternalUser, Address, Preferences, LoginActivity, UserRole, AccountStatus
<span class="hljs-keyword">from</span> yourmodule.conversion <span class="hljs-keyword">import</span> dataclass_to_django_internal_user


<span class="hljs-meta">@pytest.mark.django_db</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_internal_user_conversion_basic_fields</span>():</span>
    <span class="hljs-comment"># Test that basic fields (email, name, etc.) are correctly copied</span>
    <span class="hljs-keyword">pass</span>


<span class="hljs-meta">@pytest.mark.django_db</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_internal_user_conversion_with_address</span>():</span>
    <span class="hljs-comment"># Test that address fields are properly mapped to the ORM model</span>
    <span class="hljs-keyword">pass</span>


<span class="hljs-meta">@pytest.mark.django_db</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_internal_user_conversion_with_preferences</span>():</span>
    <span class="hljs-comment"># Test preferences like dark mode, newsletter opt-in, and language</span>
    <span class="hljs-keyword">pass</span>


<span class="hljs-meta">@pytest.mark.django_db</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_internal_user_conversion_with_login_activity</span>():</span>
    <span class="hljs-comment"># Test login attempts, last IP, and last login datetime</span>
    <span class="hljs-keyword">pass</span>


<span class="hljs-meta">@pytest.mark.django_db</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_internal_user_conversion_with_tags_and_notes</span>():</span>
    <span class="hljs-comment"># Test tags list and optional notes field</span>
    <span class="hljs-keyword">pass</span>


<span class="hljs-meta">@pytest.mark.django_db</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_internal_user_conversion_with_missing_optional_fields</span>():</span>
    <span class="hljs-comment"># Ensure None fields like address or lastLogin don’t break conversion</span>
    <span class="hljs-keyword">pass</span>


<span class="hljs-meta">@pytest.mark.django_db</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_internal_user_conversion_saves_correctly</span>():</span>
    <span class="hljs-comment"># Save all related models and main InternalUser model and check database</span>
    <span class="hljs-keyword">pass</span>
</code></pre>
<p>Now, I’m not suggesting that you take these as is and don’t add your own thought in to each possible test scenario, but it’s a great start.</p>
<p>These pieces of “grunt work” were never what we paid the top engineers for. These were just the things that they had to do to get the job done. People didn’t enjoy these tasks. They weren’t fulfilling.</p>
<h2 id="heading-critical-skills-for-the-ai-era"><strong>Critical Skills for the AI Era</strong></h2>
<p>As AI handles more coding tasks, successful engineers must develop strengths in areas where human judgment remains essential:</p>
<p>Systems thinking becomes the primary skill – understanding component interactions, identifying potential failures, and designing for future growth. This capability comes from experience, not prompting.</p>
<p>You should build expertise in infrastructure and deployment processes. Software that works in development but fails in production creates no value. So, learn about <a target="_blank" href="https://www.freecodecamp.org/news/learn-continuous-integration-delivery-and-deployment/">continuous integration</a>, <a target="_blank" href="https://www.freecodecamp.org/news/how-to-set-up-monitoring-for-nodejs-applications-using-elastic/">monitoring</a> systems, and <a target="_blank" href="https://www.freecodecamp.org/news/beginners-guide-to-cloud-computing-with-aws/">cloud platform capabilities</a>.</p>
<p>You should also master <a target="_blank" href="https://www.freecodecamp.org/news/rest-api-design-best-practices-build-a-rest-api/">API design</a> – the interfaces between systems. <a target="_blank" href="https://www.freecodecamp.org/news/design-an-api-application-program-interface/">Well-designed APIs</a> enable team independence. Poor interfaces create bottlenecks affecting everyone.</p>
<p>Another key skill is being able to integrate security throughout the development process. A single oversight can result in breaches, damaging both customer trust and business standing.</p>
<p>Make sure you develop communication skills for both technical and non-technical audiences. You’ll need to explain complex decisions clearly across different stakeholder groups.</p>
<p>And study how AI tools function to understand their limitations and strengths, allowing you to use them most effectively.</p>
<p>For senior developers, mentoring becomes increasingly important. New engineers need guidance on responsible AI usage – knowing when to accept suggestions and when to question them.</p>
<h2 id="heading-the-path-forward"><strong>The Path Forward</strong></h2>
<p>The software field is entering a significant transition. AI will generate more code more quickly, transforming development practices. This shift presents both opportunities and challenges.</p>
<p>The most valuable positions will go to those good at tasks machines cannot handle. These engineers will determine what to build, how to design it, and how to balance technical constraints with business objectives.</p>
<p>"Vibe coding" serves as a useful technique for specific needs – like quickly building standard components. But it fails as a comprehensive strategy for complex system development.</p>
<p>Skilled engineers will advance by delegating routine work to AI while addressing more challenging problems. Less skilled engineers will struggle as fundamental knowledge gaps become apparent.</p>
<p>With regards to learning how to use AI effectively, also use caution and judgement when following advice from people online. It’s still a fairly new field and changes constantly.</p>
<p>People online are giving away “free prompts” to generate code. These prompts may be great or may have problems. The prompts may have worked when they used them, but the AI models may have changed and maybe they’ll produce different results now. Be cautious and use your best judgement.</p>
<p>The future belongs to those who view AI as a collaborative tool rather than a replacement. Software development remains fundamentally human-driven, now supported by increasingly powerful assistance.</p>
<p><em>In his spare time, Ben writes his tech blog</em> <a target="_blank" href="https://justanothertechlead.com/"><em>Just Another Tech Lead</em></a> <em>and runs a site on SEO,</em> <a target="_blank" href="https://www.smoothseo.co"><em>SmoothSEO</em></a><em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Run a Sprint Retrospective Using the Start, Stop, Continue Method ]]>
                </title>
                <description>
                    <![CDATA[ I’ve been writing a lot of articles lately on Agile methodologies. And for this one, I wanted to cover how to get the most out of a Sprint Retrospective. I’ve been participating and running Sprint Retrospectives now for 15 years and I truly believe t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-run-a-sprint-retrospective-start-stop-continue-method/</link>
                <guid isPermaLink="false">67d1f7a9ed7b17e04fb90aa7</guid>
                
                    <category>
                        <![CDATA[ agile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ agile methodology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Agile Software Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ agile development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ agile methods ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ben ]]>
                </dc:creator>
                <pubDate>Wed, 12 Mar 2025 21:07:53 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1740494845460/a0181901-d715-49ce-881b-936b1143d341.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I’ve been writing a lot of articles lately on Agile methodologies. And for this one, I wanted to cover how to get the most out of a Sprint Retrospective.</p>
<p>I’ve been participating and running Sprint Retrospectives now for 15 years and I truly believe that when done well, they are the best way to make a team more effective and more closely bonded.</p>
<h2 id="heading-what-is-a-sprint-retrospective">What is a Sprint Retrospective?</h2>
<p>A sprint retrospective is one of the key events in an Agile Sprint. The retrospective occurs at the end of each sprint and it is the meeting where the scrum team gets together to talk openly and honestly about the sprint that has just finished.</p>
<p>The purpose of the Sprint Retrospective is to find out things that went well in the previous sprint and things that didn’t.</p>
<p>Agile promotes iteration and improvement. The retrospective is a way to continuously improve the team and the team’s practices by regularly (at the end of each sprint) dissecting your working practices and trying to improve upon them.</p>
<h2 id="heading-building-the-foundation-for-effective-retrospectives">Building the Foundation for Effective Retrospectives</h2>
<p>Before diving into methodology, let's address three critical factors that determine how successful your sprint retrospective might be:</p>
<ol>
<li><p><strong>Team size matters</strong>: I've discovered that scrum teams larger than 6-7 people struggle with meaningful retrospectives. The dynamics change, people speak less freely, and you lose the intimate environment needed for honest feedback. If your team has grown too large, consider splitting it.</p>
</li>
<li><p><strong>Trust is non-negotiable</strong>: I've seen brilliant retrospective frameworks fail in environments where team members don't feel safe sharing honest feedback. This foundation must be established first.</p>
</li>
<li><p><strong>Actions speak louder than words</strong>: Teams quickly recognize empty exercises. If retrospective outcomes aren't implemented, people will lose faith and stop participating. Make sure you follow through.</p>
</li>
</ol>
<h2 id="heading-the-mechanics-of-start-stop-continue">The Mechanics of Start, Stop, Continue</h2>
<p>The beauty of this approach is due to its simplicity.</p>
<p>Start, Stop, Continue is a framework that tries to get you and your team to categorize all of the aspects of work in the team (planning, execution, reviews, communication, and so on) into three simple categories:</p>
<ul>
<li><p>Things we should <strong>start</strong> doing (before starting a new code change, see if there are open pull requests to review),</p>
</li>
<li><p>Things we should <strong>stop</strong> doing (submitting pull requests that are longer than X lines), and</p>
</li>
<li><p>Things we should <strong>continue</strong> doing (keep the stand up to 15 minutes).</p>
</li>
</ul>
<p>Here's how I structure these sessions:</p>
<h3 id="heading-gathering-start-items">Gathering "Start" Items</h3>
<p>I ask: "<em>What practices should we begin implementing that we currently don't do?</em>"</p>
<p>Common themes I've seen across teams include:</p>
<ul>
<li><p>Earlier stakeholder demos</p>
</li>
<li><p>More rigorous code review practices</p>
</li>
<li><p>Better preparation before refinement meetings</p>
</li>
<li><p>Cross-functional pairing opportunities</p>
</li>
<li><p>More well-defined tasks</p>
</li>
</ul>
<h3 id="heading-finding-the-stop-items">Finding the "Stop" Items</h3>
<p>Next question: "<em>What's currently slowing down our productivity or quality?</em>"</p>
<p>Frequently mentioned items include:</p>
<ul>
<li><p>Context switching between multiple stories</p>
</li>
<li><p>Late-sprint testing bottlenecks</p>
</li>
<li><p>Inconsistent documentation practices</p>
</li>
<li><p>Meeting overload</p>
</li>
<li><p>Changing priorities mid sprint</p>
</li>
</ul>
<h3 id="heading-recognizing-continue-items">Recognizing "Continue" Items</h3>
<p>Finally: "<em>What positive practices have we recently adopted that require reinforcement?</em>"</p>
<p>This category functions as a temporary holding area. Once practices become second nature, they graduate from the list.</p>
<h2 id="heading-the-decision-framework">The Decision Framework</h2>
<p>After generating ideas, decision-making becomes critical.</p>
<p>You now need to decide which items on the board (across all categories) you want to talk about.</p>
<p>There may be some retrospectives where you decide as a team that the most important items to talk about are all In the “start” category, there may be some meetings where you talk about items from the Start, Stop, and Continue categories. It really depends on what is deemed by the team to be the most important items that need addressing.</p>
<p>Here’s my preferred approach to picking the most important topics to discuss:</p>
<ol>
<li><p>Group similar items for clarity. Are there three items on the board that are to do with different aspects of stability? Group them into one.</p>
</li>
<li><p>Allocate three votes per team member. Giving people limited options means that their votes truly matter. If you ask people to tag any items they see as important, you’ll more than likely get an overwhelming number of action items.</p>
</li>
<li><p>Select the top 2-3 items for action. It’s not possible to make too many changes in one go or in one sprint. Choosing 2-3 means that you are likely to be able to achieve them. Starting each retro by highlighting missed action items can be demoralizing. Limiting your action items hopefully mitigates this.</p>
</li>
<li><p>Assign clear ownership for each item. One person needs to lead each action item. Without clear ownership, the <a target="_blank" href="https://en.wikipedia.org/wiki/Bystander_effect">bystander effect</a> is likely to happen.</p>
</li>
</ol>
<p>The key insight: changing too many things simultaneously dilutes focus. A few well-implemented changes outperform numerous half-hearted attempts.</p>
<h2 id="heading-avoiding-retrospective-monotony">Avoiding Retrospective Monotony</h2>
<p>Repetitive formats lead to diminishing returns.</p>
<p>There are various ways that you can “spice up” the Start, Stop, Continue framework to make sure that people don’t get bored and just go through the motions.</p>
<p>Some of the processes below augment the Start, Stop, Continue process changing it slightly to keep it interesting.</p>
<p>I've developed several variations to keep the process engaging:</p>
<ul>
<li><p><strong>Silent brainstorming</strong>: Everyone writes ideas on sticky notes before sharing</p>
</li>
<li><p><strong>Theme-focused</strong>: Concentrate on specific areas (for example, "testing practices" or "collaboration"). Only do Start, Stop, and Continue on the chosen topic.</p>
</li>
<li><p><strong>Data-driven</strong>: Begin by examining sprint metrics, then discuss implications. Look at the sprint burndown, the velocity, the story breakdown and do Start, Stop Continue based on the data that you see. For instance, “Start breaking stories down to smaller chunks so that each story can be delivered quicker giving us a more smooth burndown”</p>
</li>
<li><p><strong>Rotating facilitation</strong>: Have different team members lead each retrospective. People engage more if they are actively leading a meeting. They will find ways to keep the others engages as well as they want to do a good job of running the meeting.</p>
</li>
<li><p><strong>Talking stick:</strong> Use a physical stick (yes, I’m serious) as a talking stick and only the person holding can talk. They are allowed to talk about whatever they want, good, bad, or indifferent. You can have one person taking the notes of what the person with the talking stick is saying. For instance, the person with the talking stick might say "I’d like to reduce the number of project meetings within the Sprint”. The meeting facilitator could then translate this to “Stop having so many project meetings in the sprint” and put it on the board.</p>
</li>
</ul>
<h2 id="heading-the-mathematics-of-team-improvement">The Mathematics of Team Improvement</h2>
<p>Here's something rarely discussed in Agile circles but frequently mentioned in finance: <a target="_blank" href="https://en.wikipedia.org/wiki/Compound_interest">the power of compounding</a>. Just as compound interest transforms modest savings into significant wealth, small team improvements compound over time.</p>
<p>Consider this: A team implementing just one meaningful improvement per sprint will see huge results after a year. If each improvement increases efficiency by just 2%, the compounding effect after 26 two-week sprints is remarkable.</p>
<p>Teams that understand this principle outperform those making sporadic large changes.</p>
<h2 id="heading-maintaining-continuity-between-retrospectives">Maintaining Continuity Between Retrospectives</h2>
<p>I maintain a living document tracking all retrospective outcomes.</p>
<p>Before each new session, I review:</p>
<ul>
<li><p>Which items were successfully implemented</p>
</li>
<li><p>Which items need continued attention</p>
</li>
<li><p>Which items were dropped and why</p>
</li>
</ul>
<p>This creates an improvement narrative that demonstrates the team's evolution.</p>
<h2 id="heading-why-this-framework-delivers-in-real-world-scenarios">Why This Framework Delivers in Real-World Scenarios</h2>
<p>Having implemented this across multiple organizations, from startups to established enterprises, I've found the Start, Stop, Continue model succeeds because:</p>
<ol>
<li><p>It creates immediate clarity on what requires action</p>
</li>
<li><p>It balances recognition of successes with acknowledgment of challenges</p>
</li>
<li><p>It creates a sustainable improvement cycle without overwhelming the team</p>
</li>
<li><p>It focuses on behavioral changes rather than vague aspirations</p>
</li>
</ol>
<p>The best retrospectives I've facilitated didn't just improve processes—they transformed team cultures by establishing continuous improvement as a fundamental value.</p>
<p><em>In his spare time, Ben writes his tech blog</em> <a target="_blank" href="https://justanothertechlead.com/"><em>Just Another Tech Lead</em></a> <em>and runs a site creating forever-free online calaculators at</em> <a target="_blank" href="https://calculatorlord.com/"><em>CalculatorLord.com</em></a><em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Run a Great Sprint Review – Actionable Tips for Developers and Teams ]]>
                </title>
                <description>
                    <![CDATA[ In my twenty years of being in the Software Engineer game, I’ve been through lots of Sprint Reviews. I’ve seen them done well, and I’ve seen them used as no more than a few hours every sprint for people to take a nice break in a meeting room. When do... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-run-a-great-sprint-review-actionable-insights/</link>
                <guid isPermaLink="false">679a5f09bd88c0851092079d</guid>
                
                    <category>
                        <![CDATA[ agile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Scrum ]]>
                    </category>
                
                    <category>
                        <![CDATA[ planning ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ben ]]>
                </dc:creator>
                <pubDate>Wed, 29 Jan 2025 17:02:01 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738170100236/fcc7407a-3b08-493f-a704-661eed12f369.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In my twenty years of being in the Software Engineer game, I’ve been through lots of Sprint Reviews. I’ve seen them done well, and I’ve seen them used as no more than a few hours every sprint for people to take a nice break in a meeting room.</p>
<p>When done right, the Sprint Review can be key to keeping your project on track. But badly run Sprint Reviews are worse than just the time they waste – they also reduce people’s trust in Scrum as a whole.</p>
<p>In this article, I’ll walk you through some clear, step-by-step ideas for making your Sprint Review more valuable.</p>
<h2 id="heading-what-is-a-sprint-review"><strong>What is a Sprint Review?</strong></h2>
<p>A <strong>Sprint Review</strong> is a short session held at the end of each sprint, usually once every couple of weeks.</p>
<p>It allows the team to show what they have completed via demos, get feedback, and decide what happens next.</p>
<p>When run well, the Sprint Review shows progress and builds trust with the people who have a stake in the product and project.</p>
<p>Sure, you can tell the stakeholders you are on track, but if they can see it with their own eyes in the Sprint Review, they’ll be much happier.</p>
<h2 id="heading-who-should-be-in-the-review">Who Should Be in the Review?</h2>
<p>In short, anyone who wants to be. Anyone who is a project stakeholder in any capacity can and should attend the meetings.</p>
<p>The scrum team themselves are the core of the meeting, but there can also be Sales, Senior Management, other scrum teams, and Project Managers.</p>
<p>In short, if someone could have good input on a project or could get something out of learning something about a project, they should attend.</p>
<h2 id="heading-what-to-do-before-the-review">What to Do Before the Review</h2>
<p>To ensure that the meeting itself runs as smoothly as possible, you need to make sure that everyone presenting is ready and has a demo ready to show.</p>
<p>In my experience, live demos don’t work. Well, sometimes they do, but mostly they don’t.</p>
<p>Get the people who have a demo to at least record themselves showing their workflow prior to the meeting. That way, if they insist on doing a live demo, they have a recorded video as a backup if it goes wrong.</p>
<p>You should also have a running order. Know who is presenting, in which order, and group them by similarity of topic. Who presents and when doesn’t really matter as long as the presentations are grouped together by topic.</p>
<p>For instance, if you have six engineers – two working on a Login Page, two working on new back-end service, and two working on database performance – make sure that your running order groups these three distinct areas together.</p>
<p>If two demos are fairly similar, you can explain the context once and then run through both demos back to back. Be efficient, as you have a lot of people in this meeting and everyone knows that <a target="_blank" href="https://calculatorlord.com/meeting-cost-calculator/">meetings are expensive</a>.</p>
<h2 id="heading-during-the-review">During the Review</h2>
<p>The Software Engineers who have completed a piece of work will present the work to the other members of the scrum team (Product, QA, and so on) as well as all stakeholders who have attended.</p>
<p>After each Engineer has presented, anyone in the room is free to either ask questions or make comments about the work/presentation.</p>
<p>These questions can simply be to fill in knowledge gaps for people who know less about the project, or they can be questions about why a particular solution was chosen.</p>
<p>Product or more business-focused members of the audience may now give feedback on whether what was demonstrated matches the business intent of what was asked to be delivered.</p>
<p>Once all questions and comments have been addressed, the next Engineer will present their work.</p>
<p>In a Sprint Review, everyone is encouraged to speak, but generally it’s only Engineers who present. So the Engineer will present what they have worked on, then Product, QA, BA, and so on can give feedback and ask questions specifically about what the engineer has presented.</p>
<h2 id="heading-example-review">Example Review</h2>
<p>Let’s take a look at an example review and what that may look like.</p>
<p>We’ll use the example above of having six engineers: two working on a Login Page, two working on a back-end service, and two working on database performance. In that case, you may have a running order like this:</p>
<p>Presentations:</p>
<ol>
<li><p>Larry: <em>User Exceeds Max login attempts and the user account gets locked after the fifth incorrect password. User has to reset password before they can login again.</em></p>
</li>
<li><p>David: <em>User clicks forgotten password link and a link is sent to their email address. The user follows this link and is able to reset their password.</em></p>
</li>
<li><p>Premilla: <em>Reporting Service consumes the “User Exceeded Max Login Attempts” event and publishes it to the reporting dashboard.</em></p>
</li>
<li><p>Akshat: <em>Reporting Service consumes the “User Clicked Forgotten Password” event and publishes this to the reporting dashboard</em></p>
</li>
<li><p>Olga: <em>An Admin User can view the reporting dashboard for a month and load the report within 3 seconds.</em></p>
</li>
<li><p>Trevor: <em>An Admin User can view the events from multiple users combined in to one dashboard and load the report within 2 seconds.</em></p>
</li>
</ol>
<p>As you can see here, the two login page user stories are demonstrated first, then the two reporting service stories, and then the two database speed stories. This requires less context switching for the members of the audience and means that context only needs to be given at the beginning of the first of the two grouped stories (that is, presentations 1, 3 and 5).</p>
<p>After presentation 1 (by Larry), Product may ask why he chose 5 retries as the maximum amount of retries before locking the account. Larry may have an answer, or he may not. Product can either ask to have a follow up on this later and find out what the industry standard is and apply that to Larry’s logic, or just leave it as it is.</p>
<p>After each of the six presentations, there could be questions, comments, and change requests by anyone in the audience. Typically this will then spark a conversation amongst the audience about the best approach.</p>
<p>For instance, in Larry’s example again, some may argue that they should not even be using a username and password, but instead should use an email address and <a target="_blank" href="https://www.pingidentity.com/en/resources/blog/post/what-is-magic-link-login.html">magic link</a>. This is the beauty of the review. You have a lot of smart people in a room bringing their own experience and expertise.</p>
<h2 id="heading-actionable-takeaways"><strong>Actionable Takeaways</strong></h2>
<p>Here are some tips for what to show, how to show it, and what actually matters during the meeting itself.</p>
<h3 id="heading-1-showcase-real-deliverables">1. Showcase Real Deliverables</h3>
<p>First, always present working software or completed work rather than static slides. For instance, if you built a new login feature, do a live demo. This makes the review more genuine and shows tangible progress.</p>
<h3 id="heading-2-encourage-open-feedback">2. Encourage Open Feedback</h3>
<p>Second, invite questions from everyone. Remind stakeholders that their ideas can help shape future work. Write down their suggestions, and confirm whether any changes should go straight into your backlog.</p>
<h3 id="heading-3-keep-it-clear-and-on-track">3. Keep It Clear and On Track</h3>
<p>Third, maintain a simple format. For example, start with a quick overview of the sprint goal, move to demos, and end with a short discussion of next steps.</p>
<p>Avoid going too deep into technical details. If a topic needs more time, set up a follow-up chat.</p>
<h3 id="heading-4-align-on-next-steps">4. Align on Next Steps</h3>
<p>After that, update your backlog based on what you learned. If a feature needs an extra tweak, add that task right away.</p>
<p>This helps the entire group stay informed about the plan for the upcoming sprint.</p>
<h3 id="heading-5-keep-it-short-and-end-on-time">5. Keep it short and end on Time</h3>
<p>You should be reviewing one scrum team’s work for one sprint (two or three weeks).</p>
<p>If your meetings are running on for too long, it either means that your scrum team is too large (in which case, you should think about splitting your scrum team into <a target="_blank" href="https://namegenerators.online/scrum-team-name-generator/">smaller teams</a>), or you are not efficient enough with your demos.</p>
<p>People’s time and attention is expensive and in short supply. Keep the meetings to no more than one <a target="_blank" href="https://en.wikipedia.org/wiki/Basic_rest%E2%80%93activity_cycle">ultradian cycle</a>. I personally try to limit all of the meetings I run to a max of 90 minutes.</p>
<p>Lastly, set a firm limit for the meeting so that participants feel confident bringing their feedback without dragging out the discussion.</p>
<p>Wrapping up on time respects everyone’s schedule and keeps the team fresh for the next sprint.</p>
<h2 id="heading-in-summary"><strong>In Summary</strong></h2>
<p>A Sprint Review gives stakeholders a real-time look at completed work, ensures alignment on what’s next, and gathers the feedback you need to grow your product effectively.</p>
<p>If you focus on showing real progress, inviting open dialogue, and keeping things concise, you’ll see a steady improvement in how your team delivers.</p>
<p><em>In his spare time, Ben writes his tech blog</em> <a target="_blank" href="https://justanothertechlead.com/"><em>Just Another Tech Lead</em></a> <em>and runs a site creating forever-free online calaculators at</em> <a target="_blank" href="https://calculatorlord.com/"><em>CalculatorLord.com</em></a><em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Run an Effective Daily Scrum – Tips for Team Members and Managers ]]>
                </title>
                <description>
                    <![CDATA[ Let’s start with a simple question: Why do we get together for a short meeting each day? If you work on a Scrum team, you’ve probably heard of a daily scrum, sometimes called a daily stand-up. It’s one of the key events in scrum. The “daily” usually ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-run-an-effective-daily-scrum/</link>
                <guid isPermaLink="false">678a7845720a1885d5f75ecd</guid>
                
                    <category>
                        <![CDATA[ Scrum ]]>
                    </category>
                
                    <category>
                        <![CDATA[ agile development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ agile methodology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ agil ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ben ]]>
                </dc:creator>
                <pubDate>Fri, 17 Jan 2025 15:33:25 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737127993830/ea473796-6a68-48f2-8643-f533561e12cf.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Let’s start with a simple question: Why do we get together for a short meeting each day?</p>
<p>If you work on a Scrum team, you’ve probably heard of a daily scrum, sometimes called a daily stand-up. It’s one of the key <a target="_blank" href="https://justanothertechlead.com/agile/scrum-events-a-tech-leads-guide-to-effective-scrum/">events in scrum</a>.</p>
<p>The “daily” usually takes place around the same time every day, and it should last around 15 minutes.</p>
<p>At first glance, it seems straightforward. When it’s your turn, you answer three basic questions. Job’s done, right?</p>
<p>Well, without a structure and someone to enforce that structure, a 15 minute daily meeting can turn in to a 45 minute chat.</p>
<h2 id="heading-what-is-the-daily-scrum"><strong>What Is the Daily Scrum?</strong></h2>
<p>Scrum teams use the daily scrum to align and share their efforts.</p>
<p>Each person usually answers three questions:</p>
<ol>
<li><p><strong>What did I do yesterday to help the team meet its goal?</strong></p>
</li>
<li><p><strong>What do I plan to do today to help the team meet its goal?</strong></p>
</li>
<li><p><strong>Are there any obstacles in my way?</strong></p>
</li>
</ol>
<p>I call these the “classic three.” Yesterday, Today, Blockers.</p>
<p>From this explanation, if you’ve never attended a daily scrum, you might assume it’s just a trivial and pretty pointless meeting. But it can highlight important issues in real time.</p>
<p>For instance, if someone says, “I’m stuck waiting for a database script to finish,” the rest of the team can suggest a workaround.</p>
<p>Or if the product owner says, “We need to shift a feature’s priority,” everyone learns about it immediately.</p>
<h2 id="heading-why-keep-the-scrum-short"><strong>Why Keep the Scrum Short?</strong></h2>
<p>In theory, the daily scrum lasts 15 minutes, give or take. Yet, many teams allow it to stretch to half an hour or more.</p>
<p>That’s risky.</p>
<p>When these meetings grow too long, people lose interest. Also, they might skip the next one, feeling like it’s a waste of time.</p>
<p>Beyond this, brevity encourages people to share only what matters most.</p>
<p>If someone dives into intricate details, it might derail the conversation.</p>
<p>This is not the space for describing every table in your database schema. It’s a moment to share your progress, highlight your plan, and let your teammates know if you’re blocked.</p>
<h2 id="heading-the-three-essential-questions"><strong>The Three Essential Questions</strong></h2>
<p>The daily scrum usually follows the same pattern. It’s predictable, and that’s a good thing.</p>
<p>Let’s expand on each question:</p>
<ol>
<li><p><strong>Yesterday’s Tasks</strong>: This is an update on what you finished. For instance, I might say, “I set up the new testing environment for our user login feature.” That helps the rest of the team see how tasks are progressing and whether I’m finishing my part of the sprint goal.</p>
</li>
<li><p><strong>Today’s Plans</strong>: Next, we share what we’re about to tackle. For example, “Today, I’m going to fix a bug in the payment service.” That piece of information helps everyone see how the day’s work lines up with the sprint backlog.</p>
</li>
<li><p><strong>Blockers</strong>: This is a crucial point. If something is stopping me from completing my tasks, I mention it here. Let’s say, “I need access to the staging environment, but I’m waiting on a permissions update to give me access.” This means if anyone on the team can fix that, we speed up progress.</p>
</li>
</ol>
<p>In my teams, we usually have the Jira board open and associate each person’s update with the related story. This gives people a little more context. You don’t have to do this though – my teams just find it helpful.</p>
<h2 id="heading-how-to-prevent-the-scrum-from-turning-into-a-status-meeting"><strong>How to Prevent the Scrum from Turning into a Status Meeting</strong></h2>
<p>A daily scrum is not just a status report. It’s a chance for the team to realign quickly.</p>
<p>But some managers treat it as a time to see who is on track. That can shift the focus away from cooperation. On the other hand, a team might treat it like a casual hangout without any structure. These extremes usually lead to frustration.</p>
<h3 id="heading-whats-the-sweet-spot"><strong>What’s the sweet spot?</strong></h3>
<p>It’s where the team focuses on tasks that lead to the sprint goal while also offering quick help when people get stuck.</p>
<p>The meeting should be about collaboration and the scrum team’s needs, not about pleasing a manager.</p>
<p>Also, if something requires a deeper talk, schedule a follow-up. For instance, you might say, “Let’s finish the stand-up, then we can chat about the modeling question after”.</p>
<p>If you find that your stand ups are getting too long, you as a team need to discuss why this is happening in the <a target="_blank" href="https://justanothertechlead.com/agile/sprint-review-vs-retrospective-a-real-world-guide-to-the-difference/">sprint retro</a> and adjust.</p>
<h2 id="heading-a-typical-example-of-a-smooth-daily-scrum"><strong>A Typical Example of a Smooth Daily Scrum</strong></h2>
<p>Let’s paint a quick picture.</p>
<p>The team is working on a feature that handles user registration and payment processing. Each day, the daily scrum goes like this:</p>
<ol>
<li><p><strong>Developer A:</strong></p>
<ul>
<li><p>Yesterday, I cleaned up the user registration form.</p>
</li>
<li><p>Today, I’ll add form validation for email.</p>
</li>
<li><p>I’m blocked by a missing API key, so if someone can share that, I can move forward.</p>
</li>
</ul>
</li>
<li><p><strong>Developer B:</strong></p>
<ul>
<li><p>Yesterday, I tested the payment integration.</p>
</li>
<li><p>Today, I’ll fix a bug I found during testing.</p>
</li>
<li><p>No blockers.</p>
</li>
</ul>
</li>
<li><p><strong>QA Engineer:</strong></p>
<ul>
<li><p>Yesterday, I automated tests for the cart service.</p>
</li>
<li><p>Today, I’ll check the new user registration form.</p>
</li>
<li><p>No blockers, but I want to set up a quick chat about test coverage soon.</p>
</li>
</ul>
</li>
</ol>
<p>The entire process finishes in around 10 minutes. After the scrum, Developer A and Developer B might stay behind to swap that missing API key. Everyone else dives into their day. That’s it—short, sweet, and useful.</p>
<h2 id="heading-common-problems-that-disrupt-the-daily-scrum"><strong>Common Problems That Disrupt the Daily Scrum</strong></h2>
<p>Let’s discuss a few pitfalls I’ve seen crop up over the years:</p>
<ol>
<li><p><strong>Going off on tangents</strong>: For instance, a developer might begin describing the entire architecture of a new microservice. The rest of the team is left wondering how that affects them.</p>
</li>
<li><p><strong>Trying to solve every issue in real time</strong>: The daily scrum is not the place to debug code or solve other issues as a group. If something complex needs discussion, note it and talk after the stand-up with the interested parties.</p>
</li>
<li><p><strong>Waiting for latecomers</strong>: Starting late can quickly become a habit. If people learn that the meeting really begins at 9:05, they start arriving at 9:10. The easiest fix is to start on time. People usually adapt once they see you’re serious.</p>
</li>
<li><p><strong>No one mentions blockers</strong>: Sometimes, folks feel uncomfortable admitting a problem in front of the team. If that happens, the daily scrum loses its value. This meeting is precisely where you should feel safe to say, “I’m stuck here.”</p>
</li>
<li><p><strong>Too many people in the meeting</strong>: In certain organizations, multiple teams join one daily scrum. That can lead to confusion. It’s better to keep each daily scrum small and focused. If you have a big project, you might break out into smaller Scrum teams.</p>
</li>
</ol>
<h2 id="heading-tips-for-keeping-the-meeting-on-track"><strong>Tips for Keeping the Meeting on Track</strong></h2>
<p>There are various ways you can help keep a daily scrum from devolving into a long, drawn-out meeting.</p>
<p>First, make sure you stick to 15 minutes (or shorter). A timer can really help. Some teams use an actual countdown on a screen, which can be fun. If you find that it’s consistently longer, it may be a sign that you have too many people, your team members need reminding about the format, and so on.</p>
<p>Second, make sure you have a capable leader who understands how to manage the scrum. Often, the scrum master or team lead can step in if the conversation strays. They might say, “Good point. Let’s park that for later.” This ensures the scrum doesn’t balloon into a brainstorming session.</p>
<p>You should also make sure the team is focusing on its sprint goals during the meeting. In addition to sharing tasks, remember why you’re doing them. For instance, if you know the sprint goal is to launch a new checkout flow, keep that in mind. This will help streamline everyone’s three questions.</p>
<p>Next, make sure you promote a culture of help. If someone mentions a blocker, invite the group to see who can help. This is a practical approach that fosters teamwork.</p>
<p>And finally, it can be helpful to use the scrum board. This board—whether physical or digital—helps people visualize progress. If your tasks are on sticky notes or in a tool like Jira, you can quickly show which tasks are done, in progress, or awaiting review.</p>
<h2 id="heading-practical-ways-managers-can-support-the-daily-scrum"><strong>Practical Ways Managers Can Support the Daily Scrum</strong></h2>
<p>Some folks ask if managers should attend the scrum every day. There’s no strict rule, but if you do join, here are some things to keep in mind to help your team stay on track.</p>
<p>First, make sure you let the team speak. The daily scrum is for the development team to share their plan and blockers. You as a manager should avoid turning it into a performance check.</p>
<p>Next, try to observe any ongoing or developing patterns. The manager can spot trends. For instance, if a certain issue keeps popping up, they might escalate it or allocate more resources toward solving it.</p>
<p>And try to offer help without dominating the meeting. The moment you sense a roadblock your position can solve—like a missing budget approval—step in. Otherwise, let the team own the meeting.</p>
<h2 id="heading-frequently-asked-questions"><strong>Frequently Asked Questions</strong></h2>
<ol>
<li><p><strong>How strict is the 15-minute rule?</strong></p>
<p> Pretty strict if you can help it. If your team is small, you may finish in even less time.</p>
</li>
<li><p><strong>Do we need to stand physically?</strong><br> Some say it keeps the meeting short. Others aren’t able to stand, or prefer to sit. In my teams, the goal is brevity, so sitting or standing doesn’t matter as much. We also usually have a hybrid stand up where some people are in the office and some aren’t. For this, we all attend virtually.</p>
</li>
<li><p><strong>What if we have nothing new to say?</strong><br> That’s fine. A quick “No updates, no blockers” is perfectly acceptable. The meeting might take only five minutes. Great—everyone can get back to work sooner.</p>
</li>
<li><p><strong>Do we ever skip the daily scrum?</strong><br> Some teams do skip if everything is stable. I never do though, because it confirms that no new blockers have emerged. It’s like a brief pulse check. If there’s nothing to share, the meeting won’t last long anyway.</p>
</li>
<li><p><strong>Who speaks first?</strong><br> Some teams pass a “talking stick” around in a circle. Others follow the order of tasks on the board. I’ve even seen teams do it alphabetically. I also like to mix it up by playing the “nomination game” where the person speaking nominates the next person. The method doesn’t matter, as long as everyone gets a turn. I do like to mix the ordering up though as it keeps the meeting a little “fresh”.</p>
</li>
</ol>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>The daily scrum can be one of the most helpful parts of Scrum if it’s done right. It helps with open communication, early detection of blockers, and a sense of shared ownership.</p>
<p>Also, it reminds us what we’re aiming to achieve as a team (the sprint goal), which is easy to forget when everyone’s heads are down coding or testing.</p>
<p>Above all, keep it simple. Focus on yesterday’s progress, today’s plan, and any obstacles in your path.</p>
<p>If you need deeper conversations, schedule them right after the scrum with the people who care most about the topic. That way, you respect everyone else’s time.</p>
<p><em>In his spare time, Ben writes his tech blog</em> <a target="_blank" href="https://justanothertechlead.com/"><em>Just Another Tech Lead</em></a> <em>and runs a site creating forever-free online calaculators at</em> <a target="_blank" href="https://calculatorlord.com/"><em>CalculatorLord.com</em></a><em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write User Stories for Beginners: Agile in Practice ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, you’ll learn about an important part of the Agile approach to software development: user stories. I’ll take you through what user stories are, common pitfalls that I’ve seen with creating user stories, and the frameworks that exist ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-user-stories-for-beginners/</link>
                <guid isPermaLink="false">676081a802767316a74098de</guid>
                
                    <category>
                        <![CDATA[ agile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ agile development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ user stories ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ben ]]>
                </dc:creator>
                <pubDate>Mon, 16 Dec 2024 19:38:16 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1734447615195/2b7c6025-bce2-447e-a685-19f785dcd402.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, you’ll learn about an important part of the Agile approach to software development: user stories.</p>
<p>I’ll take you through what user stories are, common pitfalls that I’ve seen with creating user stories, and the frameworks that exist to validate if your user story is “good”.</p>
<h3 id="heading-heres-what-well-cover">Here’s what we’ll cover:</h3>
<ul>
<li><p><a class="post-section-overview" href="#the-beginnings-of-agile">The beginnings of Agile</a></p>
</li>
<li><p><a class="post-section-overview" href="#what-is-agile">What is Agile?</a></p>
</li>
<li><p><a class="post-section-overview" href="#what-is-a-user-story">What is a User Story?</a></p>
<ul>
<li><p><a class="post-section-overview" href="#structure-of-a-user-story">Structure of a User Story</a></p>
</li>
<li><p><a class="post-section-overview" href="#example-of-user-stories">Example of User Stories</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#how-to-make-good-user-stories">How to make good User Stories</a></p>
</li>
<li><p><a class="post-section-overview" href="#common-pitfalls-in-user-story-creation">Common pitfalls in User Story creation</a></p>
<ul>
<li><p><a class="post-section-overview" href="#focusing-on-the-technical-aspects">Focusing on the technical aspects</a></p>
</li>
<li><p><a class="post-section-overview" href="#stakeholder-collaboration">Stakeholder Collaboration</a></p>
</li>
<li><p><a class="post-section-overview" href="#vague-user-stories">Vague User Stories</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#how-to-begin-with-user-stories">How to begin with User Stories</a></p>
</li>
<li><p><a class="post-section-overview" href="#conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-the-beginnings-of-agile">The Beginnings of Agile</h2>
<p>Chances are that you’ve heard of Agile Development and User Stories. But if you haven’t, let’s have a brief history lesson:</p>
<p>User Stories are part of a larger concept called Agile methodologies.</p>
<p>Agile methodologies have been around since 2001 when 17 well-respected software engineers met at a Ski resort in Utah and created the now infamous <a target="_blank" href="https://agilemanifesto.org/">Agile Manifesto</a>.</p>
<p>If names such as Robert Martin, Martin Fowler and Kent Beck don’t mean anything to you, once you’ve finished this article, go and search them out. They have a wealth of knowledge and between them gave the world of software a more fluid way of delivering projects, called Agiile.</p>
<h2 id="heading-what-is-agile">What is Agile?</h2>
<p>Agile is more of a way of thinking than a prescribed method. Prescribed methods exist, such as Scrum and Kanban, but Agile is a concept.</p>
<p>Agile promotes collaboration, fast feedback, and delivering value often to the user.</p>
<p>The Agile way of thinking encourages flexibility in project planning, which is in stark contrast to its competitor at the time, Waterfall project planning, which was very rigid with what was being delivered and when.</p>
<p>Agile methodologies promote doing “just enough” research at the beginning to get the project started, and then learning, iterating, and changing the design and deliverable as needed throughout the project until the final code is delivered. This “change and learn as you go” approach is called “adaptive planning”.</p>
<p>Agile promotes delivering something of value quickly and often, usually in the form of delivering code to production at the end of every two week “sprint”. This, again, is very different from traditional waterfall planning which would often require months of development before any user-visible change could be delivered to production.</p>
<p>Another key part of Agile is the focus it puts on stakeholders working together closely and often. Product, QA, Engineering, and Sales all have a large input and constant feedback on the project through the project lifecycle.</p>
<p>Now that you know a bit more about how Agile works, let’s dive deeper into how we validate value to the user.</p>
<p>Enter the User Story.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733997119683/6002c66a-b11c-4607-a37f-36480a970099.jpeg" alt="Photo by Mikhail Nilov: https://www.pexels.com/photo/a-hand-pointing-the-sticky-note-on-the-wall-6592358/" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-what-is-a-user-story">What is a User Story?</h2>
<p>A user story is way in plain English to connect the engineer to the end goal of the software.</p>
<p>It’s designed so that a non-techy can read it and understand what is being delivered, and so that an engineer can look at it and see the value and how to validate that you’ve delivered that value.</p>
<h3 id="heading-structure-of-a-user-story">Structure of a User Story</h3>
<blockquote>
<p>As a [type of user], when I [perform action], [expected outcome]</p>
</blockquote>
<p>At its most basic, that is it.</p>
<p>You are putting the emphasis on the end user and the “value” that you will deliver.</p>
<p>Let’s dig into the inputs:</p>
<ul>
<li><p><strong>Type of user</strong>: There is no one size fits all “user”. You have “admin users”, you have “logged-in users”, you have “users with permission X” or “users in role Y”. This is being specific about who is performing the action</p>
</li>
<li><p><strong>Perform action</strong>: What is the user doing? Clicking the “login” button? Deleting a record? Submitting a form?</p>
</li>
<li><p><strong>Expected outcome</strong>: Once your user has performed the action, what should happen? If they’ve clicked “login” with the correct email address and password, where should they be directed? If they’ve clicked “login” with an incorrect email address and password, what should happen?</p>
</li>
</ul>
<h3 id="heading-example-of-user-stories">Example of User Stories</h3>
<p>Let’s look at examples of user stories for a login page.</p>
<p>There’s nothing better than examples.</p>
<p>Let’s set the scene. You have a login page with an entry text box for an email address and an entry text box for a password. You have a submit button. That’s it.</p>
<p>What are the different permutations that can happen on this page from the user’s perspective?</p>
<blockquote>
<p>As a logged in user, when the page loads, I am redirected to the logged in home page</p>
</blockquote>
<p>If I’m already logged in, I don’t want to have to reenter my details, just redirect me to the logged-in home page.</p>
<blockquote>
<p>As a non logged in user, when I enter the correct email address but incorrect password and click Login, an error message appears</p>
</blockquote>
<p>I’m a user who’s not already logged in, and I entered the incorrect details. I should not be logged in.</p>
<blockquote>
<p>As a non logged in user, when I enter an incorrect email address and password and click login, an error message appears.</p>
</blockquote>
<p>Again. I’m not a logged-in user. I’ve entered incorrect details, I should not be logged in.</p>
<blockquote>
<p>As a non logged in user, when I enter the correct email address and password and click login, I am rediected to the logged in home page.</p>
</blockquote>
<p>This time, I’m not already logged in, I enter the correct details and click login. I’m logged in to the system.</p>
<p>Can you see how all of these are focused on the user?</p>
<p>You may notice that some of the “expected behaviour” in the above is not fully defined. We’ll address that later in the acceptance criteria.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733997173211/1946f2a3-eee3-497e-960b-a6aeac9bd48d.jpeg" alt="Photo by cottonbro studio: https://www.pexels.com/photo/manager-considering-project-strategy-by-the-task-board-6804077/" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-make-good-user-stories">How to make good User Stories</h2>
<p>There’s a good model called the INVEST model that really simply shows how to know if your user stories are good.</p>
<p><strong>INVEST Model</strong>:</p>
<ul>
<li><p><strong>I</strong>ndependent: Can be developed separately.</p>
</li>
<li><p><strong>N</strong>egotiable: Open to discussion and change.</p>
</li>
<li><p><strong>V</strong>aluable: Delivers value to the user.</p>
</li>
<li><p><strong>E</strong>stimable: Can be estimated for effort.</p>
</li>
<li><p><strong>S</strong>mall: Fits within a sprint.</p>
</li>
<li><p><strong>T</strong>estable: Has clear acceptance criteria.</p>
</li>
</ul>
<p>Let’s apply this INVEST model to one of the user stories examples from above:</p>
<blockquote>
<p>As a non logged in user, when I enter the correct email address and password and click login, I am rediected to the logged in home page.</p>
</blockquote>
<p><em>(I’m going to make some assumptions here, as this is a theoretical code base and theoretical project)</em></p>
<p>Is this story <strong>Independent</strong>? I would say so, yes. It’s a small story that involves only a few components that probably already exist. If the database hasn’t been created yet though for the project, that would give us a dependency. This would no longer be independent.</p>
<p>Is it <strong>Negotiable</strong>? Well again, yes. This story could easily be changed to redirect to the users profile page rather than their home page.</p>
<p>This story is definitely <strong>valuable.</strong> Once implemented, the user can log in. If the story was:</p>
<blockquote>
<p>As a non logged in user, when I enter the correct email address and password and click login, nothing happens</p>
</blockquote>
<p>This would not be valuable. The user would get nothing out of this.</p>
<p>Is the story <strong>estimable</strong>? Again, we have to take some assumptions in this made up scenario, but I would certainly hope that this would be easily estimated. It’s a concise story, involving few components, in a domain that everyone is familiar with and has clear acceptance criteria.</p>
<p>The story is certainly <strong>small.</strong> There is little ambiguity in what needs to be done, there is one user path only and clear outcomes. Let’s take a look at a story that would be too large:</p>
<blockquote>
<p>As a non logged in user, the login page should work as expected.</p>
</blockquote>
<p>As discussed further up in this article, there are many ways that the login page can and should work. “Should work as expected” seems to cover all of those permutations. This would be too large to effectively size as a story, and probably too large to be completed in one sprint.</p>
<p>The story is definitely <strong>Testable.</strong> There are clear user actions to take that has a clear outcome. This user story can be covered by Unit Tests, Integration Tests, and Manual Tests.</p>
<p>It looks like we’ve created a good user story!</p>
<p>If you use the structure I’ve defined above, and the story meets the criteria of the INVEST model, it’s probably a good story.</p>
<h2 id="heading-common-pitfalls-in-user-story-creation">Common pitfalls in User Story creation</h2>
<p>I’ve seen User stories go wrong in the past where people have missed a few crucial aspects to the user story:</p>
<h3 id="heading-focusing-on-the-technical-aspects">Focusing on the technical aspects</h3>
<p>As my examples show above, the user story is non-technical.</p>
<p>There should be no reference to a service name, a database name, or validation based on anything that the user can’t see.</p>
<p>As soon as your story is no longer able to be understood by the end user, you’ve gone wrong.</p>
<p>Focus on what the user is going to do, and what the user is going to see.</p>
<p>Let’s look at an example of a technically focused story:</p>
<blockquote>
<p>As a non logged in user, when I click the forgotten password link with a correct email address, a record is logged in a database table stating that the password reset link has been sent.</p>
</blockquote>
<p>This story can not be verified by a user and non technical users may not understand what it means.</p>
<p>Let’s fix it:</p>
<blockquote>
<p>As a non logged in user, when I click the forgotten password link with a correct email address, an email is sent to the email address provided with a forgotten password reset link</p>
</blockquote>
<p>Non technical users can understand this and it puts the focus on the user, not the product.</p>
<h3 id="heading-stakeholder-collaboration">Stakeholder Collaboration</h3>
<p>Agile is collaborative.</p>
<p>User stories need input from Product, BA, QA, Engineers, and most importantly, Users.</p>
<p>This is how you will ensure that you are delivering what the user wants. Many hands make light work.</p>
<p>If, for instance, just an engineering team came up with user stories, they may look something like this:</p>
<blockquote>
<p>As a logged in user, when the page loads, I am redirected to the logged in home page</p>
<p>As a non logged in user, when I enter the correct email address but incorrect password and click Login, an error message appears</p>
<p>As a non logged in user, when I enter an incorrect email address and password and click login, an error message appears.</p>
</blockquote>
<p>And that’s great. But now let’s get QA involved, who are coming from a different perspective as they’ve different experiences with software:</p>
<blockquote>
<p>As a non logged in user, when I enter a correct email address in Hebrew and a correct password, I am redirected to the home page</p>
<p>As a non logged in user, when I enter a correct email address and password and repeatedly click login, I am redirected to the home page</p>
</blockquote>
<p>Great. We’re getting a more rounded set of user stories now that cover more situations. But what happens if we get Product involved?</p>
<blockquote>
<p>As a non logged in user, when the page loads, my password manager should pre-load my username and password, when I click login, I am redirected to the home page</p>
</blockquote>
<p>The Product team know the users. They know that people really use password managers. We should make sure that when the user doesn’t actually type anything (as the text is loaded by the password manager), the login still works correctly.</p>
<h3 id="heading-vague-user-stories">Vague User Stories</h3>
<p>The idea behind a good user story is that everyone, regardless of expertise, can understand it.</p>
<p>If you’ve written a User Story that. can be interpreted 10 different ways by 10 different people, you’ve gone a bit wrong.</p>
<p>I mentioned above that I would touch on acceptance criteria, and now is the time to do that.</p>
<p>Let’s re-examine the following User Story:</p>
<blockquote>
<p>As a non logged in user, when I enter an incorrect email address and password and click login, an error message appears.</p>
</blockquote>
<p>There’s vagueness in there.</p>
<p>What message should appear? When the page reloads after an invalid login attempt, should the username text box be set back to empty, or prepopulated with the previously entered value? What does “incorrect email address” mean? An email address that has never been seen before, or an email address that is not valid at the moment (not paid the subscription, canceled subscription etc.)</p>
<p>So as you can see, details matter.</p>
<p>This User Story is a fairly contrived simple example and I’ve managed to find a lot of questions about it.</p>
<p>Let’s fix the problem:</p>
<blockquote>
<p>As a non logged in user, when I enter an email address that it not registered with the system, when I click login, an error message appears</p>
</blockquote>
<p>That removed the questions around the user action but has not resolved the issue about the expected error message.</p>
<p>Enter the acceptance criteria.</p>
<p>Within the user story, you need to have a set of acceptance criteria that defines if the implementation of the user story is as expected.</p>
<p>Things like:</p>
<ul>
<li><p>Error message: “Invalid email address or password”</p>
</li>
<li><p>Email Address and Password text box reset to empty on reload</p>
</li>
<li><p>User unable to access pages where login is required</p>
</li>
<li><p>User is presented with a “forgotten password” suggested.</p>
</li>
</ul>
<p>Acceptance criteria states what is expected from the implementation.</p>
<h2 id="heading-how-to-begin-with-user-stories">How to Begin with User Stories</h2>
<p>Start small.</p>
<p>You will not be perfect at refining and creating user stories to start with.</p>
<p>Creating user stories is as much an art as a science. Practice makes perfect.</p>
<p>The creation of User Stories should be done as a group. Often, this is done with the “3 Amigoes” approach, where you will have an engineer, a product person and a QA all sit together and brain storm different permutations that you need to support.</p>
<p>Once you have delivered your project, retrospect. Take a look back and see what gaps you have in your user stories. There will be bugs that the users find, that QA and UAT find, and these are either due to gaps in your user stories or gaps in your testing. Either way, you should learn from them for next time.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Agile is collaborative. Scrum is collaborative. Creating User Stories is collaborative. Remember that.</p>
<p>The more people from different areas of expertise you have brainstorming user story creation, the more likely you are to cover the full set of workflows.</p>
<p>The user is the focus. If you are ever including terminology that your user doesn’t understand, rethink the user story.</p>
<p>You won’t be perfect at this from the start, but as you do more and more, the quicker and more effective you become. Take this from someone who has been doing this for over 10 years. The difference in speed and quality of my User Story creation today vs 10 years ago is a world apart.</p>
<p><em>In his spare time, Ben writes his tech blog</em> <a target="_blank" href="https://justanothertechlead.com/"><em>Just Another Tech Lead</em></a> <em>and runs a site creating forever-free online calaculators at</em> <a target="_blank" href="https://calculatorlord.com/"><em>CalculatorLord.com</em></a><em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
