read 52 min
82 / 86
Apr 4

Day 66 of 100daysofcode : Why Your Framework Choice Can Make or Break Your Project

Today’s lesson? Not all frameworks are created equal. Picking the right tool isn’t about chasing trends—it’s about aligning with your project’s DNA.

A. Why It Matters?

  1. Efficiency: The right framework accelerates development; the wrong one adds unnecessary complexity.
  2. Scalability: Will it handle growth? A monolithic framework might drown a small app, while a lightweight one could crumble under enterprise demands.
  3. Ecosystem: Libraries, plugins, and community support matter. Reinventing the wheel wastes time.

B. How to Choose?

  1. Project Scope:
  • SPA? React/Vue.js/Angular.
  • Full-stack web app? Django (Python), Rails (Ruby), or Laravel (PHP).
  • Mobile? Flutter (cross-platform) or Swift/Kotlin (native).
  1. Team Expertise: Don’t adopt GraphQL for your API if your team lives and breathes REST. Balance learning curves with deadlines.

  2. Performance Needs: Need blazing speed? Svelte or Go’s Gin might shine. Building a real-time app? Socket.io + Node.js could be your duo.

  3. Community & Longevity: Frameworks with strong backing (e.g., React by Meta, .NET by Microsoft) often offer better long-term support.

Moral of the story: Let the project’s needs drive your framework, not the other way around.
lebanon-mug

Day 67 of 100daysofcode : The Power of Tiny Fallbacks in Error Handling

In software development, even the smallest details matter—especially when handling errors. Many bugs and system failures arise not because of complex logic flaws, but due to missing fallbacks in edge cases.

A. Why Are Fallbacks Essential?

  1. Prevents Crashes – A simple null check or a default value can stop an entire app from breaking.
  2. Enhances User Experience – Users shouldn’t see cryptic error messages; instead, provide meaningful feedback.
  3. Improves System Resilience – Unexpected inputs? Fallbacks ensure graceful degradation instead of failure.
  4. Optimizes Performance – Properly handled errors reduce unnecessary retries and resource wastage.

B. Tips for Fellow Devs:

  • Use onError in images, `try/catch in logic, and default values everywhere.
  • Treat every external dependency (APIs, assets, user input) as a potential point of failure.
  • Test edge cases: empty strings, null, 404s, and network throttling.
  • Build fallbacks for fallbacks. What if your fallback image also fails? Plan for it!

Quote of the Day:
“A good developer doesn’t just write code that works—they write code that fails well.”

What’s the most creative fallback you’ve implemented?
lebanon-mug

Day 68 of 100daysofcode : Software Developer vs. Software Engineer – A Deep Dive

Today, I want to peel back the layers of what it means to be a software developer compared to being a software engineer. Although these roles often seem interchangeable at first glance, digging deeper reveals distinct nuances in responsibilities, mindset, and career pathways.

A. Foundations

  1. Software Developer:
    At its core, a software developer is primarily concerned with writing code to solve specific problems. This role often involves:
  • Creating Applications: Focusing on building, testing, and maintaining code.
  • Problem Solving: Translating user requirements into functional software.
  • Hands-On Implementation: Emphasizing practical coding skills and creative problem-solving.
  1. Software Engineer:
    A software engineer, on the other hand, approaches the discipline with a broader, more systems-oriented perspective. This role usually involves:
  • Engineering Principles: Applying principles from computer science and engineering to design robust, scalable systems.
  • Systems Design: Working on the architecture of complex systems that often require integration of multiple components.
  • Lifecycle Management: Addressing the entire software lifecycle—from initial concept through development, deployment, and maintenance.

B. Scope of Responsibilities

  1. From Code to Architecture:
  • Developers typically focus on coding and delivering features. They write and review code, debug, and optimize performance. Their day-to-day tasks often center around the implementation details of a project.
  • Engineers might be involved in the high-level design decisions. They consider scalability, reliability, and how different parts of a system communicate with each other. Their work can extend into areas like systems integration, infrastructure planning, and ensuring that the overall architecture supports long-term goals.

C. Conclusion

The debate between “developer vs. engineer” is not about hierarchy but about focus. Both roles are critical for successful software projects. As you progress in your coding journey, try to blend the detailed focus of development with the holistic, strategic view of engineering. This dual perspective can empower you to build not only functional, but also resilient and scalable software.

lebanon-mug

Day 69 of 100daysofcode : Why Flutter? Now & Beyond 2025

A. Why I Chose Flutter:

  1. Single Codebase Magic: Build for iOS, Android, web, desktop, and embedded devices with one codebase. My productivity skyrocketed!
  2. Hot Reload: Instant UI tweaks = faster iterations. Perfect for prototyping or debugging.
  3. Expressive UI: Customizable widgets (e.g., Material/Cupertino) let me craft pixel-perfect designs without platform-specific headaches.
  4. Performance: Near-native speed thanks to Dart (AOT compilation) and the Skia engine. Smooth animations even on older devices!
  5. Dart Language: Easy to learn (especially if you know Java/JS), with strong null safety and async/await for clean code.

B. Why Flutter in 2025 & Beyond?

  1. Ecosystem Growth: Packages for AI, AR, and state management (Riverpod, Bloc) are booming. The community is vibrant!
  2. Beyond Mobile: Flutter’s expanding into foldables, wearables, and IoT. Google’s backing ensures long-term relevance.
  3. Future-Ready: Integrates with AI tools (TensorFlow Lite, ML Kit) and embraces trends like edge computing.
  4. Market Demand: Companies love cost-efficiency—Flutter devs are in high demand!

C. Flutter vs. Others?

  • React Native: Flutter’s widgets outperform JS bridge lag.
  • Xamarin: More flexible UI and faster development cycle.

Join the Wave!
Whether you’re into startups, enterprise apps, or futuristic tech, Flutter is the toolbox for 2025. Let’s keep coding!
lebanon-mug

Day 70 of 100daysofcode : Design Patterns vs. Design Architecture

A. Design Patterns

Design patterns are proven, reusable solutions to common, recurring problems in software development. They are more granular and focus on solving a specific issue, such as object creation, data flow, or behavioral concerns.

In Flutter:

  • Examples include the Singleton, Factory, and Observer patterns.
  • Patterns like the BLoC (Business Logic Component) pattern help manage state by separating business logic from UI components.
  • These patterns are applied in localized parts of your app to improve code reusability and maintainability.

B. Design Architecture

Design architecture refers to the high-level structure of your application. It defines the overall layout of the system, how various components interact, and how responsibilities are distributed across the app.

In Flutter:

  • Architectural styles like MVC (Model-View-Controller), MVVM (Model-View-ViewModel), and Clean Architecture provide blueprints for organizing code at a macro level.
  • BLoC architecture, although often referred to as a pattern, also represents an architectural approach when used to separate presentation and business logic across the entire application.
  • This helps in managing the app’s scalability, testability, and overall maintainability.

C. Key Differences:

  1. Scope:
  • Design Patterns: Focus on solving a specific coding problem within a module or a part of the application.
  • Design Architecture: Concerns the overall structure and interaction between various parts of the application.
  1. Implementation Level:
  • Design Patterns: Operate at a micro-level. They are tactical and localized.
  • Design Architecture: Operates at a macro-level. They are strategic and provide the blueprint for the entire project.
    lebanon-mug

Day 71 of 100daysofcode : The Importance of Splash Screens in Mobile Apps

Splash screens often serve as the first interaction point between your user and your app. They provide a visual welcome and set the stage for the overall experience. In today’s session, we’ll explore why splash screens are essential and how you can effectively implement them in Flutter.

Beyond aesthetics—how splash screens orchestrate critical app workflows like user authentication, permissions, and data initialization.

A. Why Splash Screens Are a Silent Powerhouse

While splash screens are often seen as a branding tool, their real value lies in managing behind-the-scenes logic that shapes the user’s journey. Here’s how they silently drive functionality:

  1. User Session Validation
    While the splash screen is visible, apps often check:
    • Authentication Status: Is the user logged in? (e.g., validating tokens or session cookies.)
    • Onboarding Completion: Has the user skipped the tutorial or set up their profile?
  2. Permission Pre-Checks
  • Critical permissions (location, notifications, camera) can be verified during the splash phase.
  • Example: A food delivery app might check if location access is granted to immediately show nearby restaurants or trigger a permission request.
  1. Data Initialization & Caching
  • Fetch lightweight, essential data (e.g., user preferences, cached content) to personalize the app’s first “real” screen.
  • Avoid forcing users to stare at loaders after the splash screen.
  1. Graceful Error Handling
  • If the app detects offline mode or server issues during the splash phase, it can redirect to an offline-friendly screen or display cached data.

B. Key Considerations for Strategic Splash Screens

  1. Speed vs. Functionality Balance:
  • Splash screens should not exceed 2-3 seconds. Prioritize asynchronous tasks (e.g., network calls) to run in the background without blocking the transition.
  • Example: Validate a user’s login token locally first, then silently refresh it in the background after the app loads.
  1. State-Driven Navigation:
    Use the splash screen’s visibility period to decide the app’s initial route:
    • Logged-in user → Home screen.
    • New user → Onboarding flow.
    • Location permission denied → Landing page with a permission nudge.
  2. Avoid Overloading:
  • Only handle mission-critical tasks here. Heavy operations (e.g., downloading large files) should occur after the user is engaged with the app.

lebanon-mug

Day 72 of 100daysofcode : Understanding Axios vs. CORS in Node.js and React

Today’s focus was unraveling two critical concepts in web development: Axios and CORS. While both are essential for building modern full-stack apps (like those using React frontends and Node.js backends), they solve entirely different problems. Let’s break it down!

A. What is Axios?

Axios is a promise-based HTTP client used to send requests from your application to APIs or backend servers. Think of it as a “messenger” that handles communication between your frontend (React) and backend (Node.js) or third-party services.

  1. Role: Simplifies making HTTP requests (GET, POST, etc.), handling responses, and managing errors.
  2. Use Case: Fetching data from a Node.js API in React, submitting forms, or interacting with external APIs.
  3. Strengths: Automatic JSON parsing, interceptors for global request/respose handling, and support for async/await.

B. What is CORS?

CORS (Cross-Origin Resource Sharing) is a security mechanism enforced by browsers to control cross-origin HTTP requests. It’s not a library or tool—it’s a rulebook browsers follow to protect users from malicious cross-origin requests.

  1. Role: Determines whether a frontend (e.g., React app on http://localhost:3000) can access resources from a backend (e.g., Node.js API on http://localhost:5000).
  2. Use Case: Resolving browser errors like Blocked by CORS policy when your React app tries to access an API on a different domain/port.
  3. How It Works: The backend (Node.js) sends specific headers (e.g., Access-Control-Allow-Origin) to whitelist trusted origins.

C. Key Differences

  1. Purpose**:
  • Axios: Facilitates HTTP communication.
  • CORS: Governs which external clients are allowed to access your server’s resources.
  1. Layer of Operation:
  • Axios: Works on the client side (React) to send requests.
  • CORS: Managed on the server side (Node.js) to permit/deny requests.

D. Final Thoughts

Axios and CORS are like two sides of the same coin:

  1. Axios is your tool for seamless client-server communication.
  2. CORS is the gatekeeper ensuring that communication is secure and intentional.

Understanding both is crucial for debugging issues and building secure, scalable apps.

lebanon-mug

Day 73 of 100daysofcode : Understanding Middleware in Node.js/Express for Frontend-Backend Interaction

Middleware is the backbone of request processing in Node.js/Express applications. It acts as a bridge between the frontend (client) and backend (server), ensuring requests are handled securely, efficiently, and in a structured way. Think of middleware as a series of checkpoints a request must pass through before reaching its final destination (your route handlers) or returning a response to the client.

A. Why Middleware Matters for Frontend Requests

When a frontend app (e.g., React, Angular) sends requests to the backend, middleware ensures:

  1. Security: Authentication/authorization checks before granting access to protected routes.
  2. Data Integrity: Parsing and validating incoming data (e.g., JSON payloads, form data).
  3. Error Handling: Gracefully catching and formatting errors to prevent server crashes.
  4. Cross-Origin Resource Sharing (CORS): Enabling secure communication between frontend and backend hosted on different domains.
  5. Logging: Tracking requests for debugging and analytics.
  6. Rate Limiting: Preventing abuse by limiting repeated requests.

Without middleware, the backend would struggle to process frontend requests reliably, leading to security vulnerabilities, crashes, or poorly structured responses.

B. Takeaway

Middleware streamlines the interaction between frontend and backend by breaking down complex operations into reusable, modular steps. It ensures requests are processed securely, efficiently, and in a way that aligns with frontend requirements (e.g., structured JSON responses, CORS support). By mastering middleware, you ensure your backend is robust, scalable, and ready to handle real-world frontend interactions.
lebanon-mug

Day 74 of 100daysofcode : DSA isn’t just for interviews—it’s the skeleton of EVERY software solution!

Today’s Progress :

Refocused on core data structures (arrays, trees, hash maps) and algorithms (searching, caching, pathfinding) to solve universal software challenges. Built a MERN stack feature demonstrating how DSA principles apply to general software design, like optimizing API response times and managing large datasets.

Why DSA Matters in Any Software Solution?

Whether you’re building mobile apps, web platforms, or embedded systems, data structures and algorithms are foundational. Here’s why:

  1. Performance Efficiency
    - Problem: Slow software frustrates users and increases operational costs.
    - Solution: Efficient algorithms reduce time complexity, ensuring fast operations.
    - Example: In a MERN app, using hash maps to cache user sessions (O(1) lookups) instead of querying a database on every request.
  2. Scalability
    - Problem: Systems that work for 100 users often fail at 10,000.
    - Solution: Scalable data structures handle growing data volumes gracefully.
    - Example: A social media app (MERN) using B-trees for database indexing, allowing O(log n) search even with millions of posts.

DSA in Action: A MERN Case Study

Scenario: Building a feature to search and filter products in an e-commerce platform.

  1. Naive Approach:
  • Fetch all products from MongoDB and filter in-memory → O(n) time, high memory usage.
  • Result: Slow API responses and server crashes during peak traffic.
  1. Optimized Approach:
  • Preprocess Data: Sort products during database insertion (O(n log n)).
  • Efficient Search: Use binary search (O(log n)) for filtered queries.
  • Caching: Store frequent search results in a Redis hash map (O(1) retrieval).

Scalability isn’t magic; it’s smart data structure choices.
lebanon-mug

Day 75 of 100daysofcode : From Base64 Bloat to Efficient File Uploads

Today I fixed my image upload performance issues by ditching Base64 for proper file handling with Multer! Here’s how I transformed slow uploads into smooth operations.

  1. What I Was Doing Wrong (Base64):
    // :x: Old Approach - Base64 String
    const base64Image = req.body.image; // Huge string!
    const newPost = await Post.create({
    title: req.body.title,
    image: base64Image // 33% size increase + DB bloat
    });

  2. Why Base64 Hurt Performance:

  • :chart_with_upwards_trend: 30-40% Larger Payloads - Increased upload times
  • :snail: Slow DB Queries - Huge text fields bogging down operations
  • :arrows_counterclockwise: Double Processing - Encoding/decoding overhead
  • :floppy_disk: Storage Waste - Same image stored in DB and filesystem
  1. The Right Approach (Multer + Filenames):
    // :white_check_mark: New Solution - File Handling
    const upload = multer({ storage });
    router.post(‘/upload’, upload.single(‘image’), (req, file) => {
    // Store just filename - small DB entry
    image: req.file.filename
    });

  2. What Changed:

  • :rocket: Faster Uploads - Binary files instead of text blobs
  • :chart_with_downwards_trend: Reduced DB Size - 100x smaller entries (filename vs Base64)
  • :zap: Instant Rendering - Direct image URLs instead of parsing
  • :lock: Better Security - File type validation and size limits
  1. Performance Wins:
  • Upload time :stopwatch:: 8s → 2s (for 4MB images)
  • Database size :floppy_disk:: Reduced by 78%
  • Memory usage :brain:: 65% less Node.js heap usage
  • Page load :page_facing_up:: 3x faster post listings
  1. Key Implementation Tips:
  • Always use FormData for file uploads
  • Store only filenames/URLs in database
  • Serve images as static assets
  • Set sane file size limits (5MB shown)
  • Use CDN for image distribution

So glad I switched from Base64 to proper file handling - performance gains were massive!
lebanon-mug

Day 76 of 100daysofcode : Understanding MVP (Minimum Viable Product) in Software Development

Today’s Focus: Learning how MVP drives software innovation and business success.

A. What is MVP?

MVP stands for Minimum Viable Product—a development strategy where you build a product with just enough features to satisfy early adopters and validate your core business idea. The goal? Test assumptions quickly, gather feedback, and iterate without wasting time or resources.

B. Why MVP Matters

  • Focus on Core Value: Avoid feature bloat by solving one key problem exceptionally well.
  • Risk Reduction: Validate demand before investing in full-scale development.
  • Agility: Iterate based on real user feedback, not guesswork.

C. Key Characteristics of an MVP

  1. Core Functionality: Only features critical to solving the primary user pain point.
  2. User Feedback Loop: Built-in mechanisms to collect data (e.g., surveys, analytics).
  3. Scalable Foundation: Designed to evolve into a full product if validated.

D. Key Takeaways

  1. Start Small: Focus on solving one problem with minimal complexity.
  2. Feedback is Gold: Use it to prioritize future development.
  3. Fail Fast, Learn Faster: If the MVP flops, pivot before overcommitting.

Reflection: MVP isn’t about building a half-product—it’s about smart validation. Whether you’re a startup or a developer, this approach saves time, money, and sanity!
lebanon-mug

Day 77 of 100daysofcode : Authentication vs. Authorization – Securing Your App’s Front Door and Permissions

Today’s Focus:
Understanding the critical distinction between authentication (verifying identity) and authorization (granting permissions) and how they work together to protect applications.

A. Authentication: Proving “Who You Are”
Authentication is the process of confirming a user’s identity. Think of it as showing a passport at an airport—your credentials (username/password, biometrics, or multi-factor authentication) validate that you are who you claim to be. Common implementations include:

  • Password-based logins.
  • Social media sign-ins (Google, Facebook).
  • Biometric scans (fingerprint, facial recognition).

B. Authorization: Defining “What You Can Do”
Authorization determines what an authenticated user is allowed to access. Imagine entering a secured office building: even with valid ID (authentication), you’re only permitted into specific rooms based on your role. Examples include:

  • Restricting admin dashboard access to moderators.
  • Limiting file deletions to privileged users.
  • Granting tiered access in subscription-based apps.

C. How They Work Together

  1. Authentication First: A user logs in (proves identity).
  2. Authorization Follows: The system checks permissions (e.g., via roles, policies, or tokens) to grant or deny actions.

D. Real-World Application:

  • Use frameworks like OAuth or JWT to handle authentication securely.
  • Implement role-based access control (RBAC) or attribute-based rules for authorization.
  • Always store sensitive data (passwords, tokens) encrypted.

Why It Matters?

  1. Security: Prevent unauthorized access to sensitive data.
  2. User Experience: Balance safety with seamless interactions (e.g., “Remember Me” features).
  3. Compliance: Meet regulations like GDPR or HIPAA by auditing access controls.

Best Practices:

  • Use HTTPS to protect authentication data in transit.
  • Regularly review permissions to avoid “over-privileged” users.
  • Adopt the principle of least privilege: grant only the minimum access needed.

Final Takeaway:
Authentication and authorization are two sides of the security coin. One verifies identity; the other enforces boundaries. Master both to build apps that are both user-friendly and fortress-strong.
lebanon-mug

Day 78 of 100daysofcode : Avoiding Bugs in Password Reset Flows

Secure and Robust Password Reset Logic

Today’s focus is on designing a password reset flow that minimizes bugs and vulnerabilities. Here’s how to approach it conceptually:

  1. Input Validation First
  • Always validate user inputs (e.g., email format) before triggering actions like sending reset emails.
  • Check if the email/username exists in your system, but avoid revealing whether an account is registered (to prevent user enumeration).
  1. Token Management
  • Generate time-limited, single-use tokens for password resets. Ensure tokens expire after a short window (e.g., 15 minutes).
  • Invalidate tokens immediately after use or if a new reset request is made.
  1. Idempotency & State Handling
  • Guard against duplicate submissions (e.g., double-clicking the “Reset” button).
    Track the state of reset requests to prevent invalid token reuse or mid-process hijacking.
  1. Secure Communication
  • Send reset links via HTTPS-only channels.
  • Mask sensitive details (like tokens) in URLs for logs or error messages.
  1. User Feedback Without Leaks
  • Use generic error messages (e.g., “If this email exists, a reset link was sent”) to avoid exposing user data.
  • Confirm success/failure clearly but never disclose internal system details.
  1. Rate Limiting
  • Throttle repeated reset requests to prevent abuse (e.g., email bombing or brute-force attacks).
  1. Post-Reset Hygiene
  • Invalidate all active sessions after a password reset to force re-authentication.
  • Log the event for security audits.

A secure password reset flow balances user convenience with rigorous error handling and state management. Always test edge cases (expired tokens, invalid inputs, network interruptions) to catch bugs early.
lebanon-mug

Day 79 of 100daysofcode : Cybersecurity Critical for Software Engineers

  1. Why Cybersecurity Matters
  • Data breaches cost companies millions and damage reputations (e.g., Equifax, SolarWinds).
  • Secure coding prevents vulnerabilities like SQL injection, XSS, and insecure APIs.
  • Compliance (GDPR, HIPAA) requires engineers to build systems that protect user privacy.
  • Career growth: Security-aware developers are in high demand for roles like DevSecOps, security architects, or penetration testers.
  1. Common Vulnerabilities
  • OWASP Top 10 (e.g., broken access control, insecure deserialization).
  • Misconfigured cloud storage (e.g., exposed S3 buckets).
  • Hardcoded secrets (API keys, passwords) in code.
  1. Secure Development Lifecycle (SDL)
  • Integrate security into every phase: design, coding, testing, deployment.
  • Tools like SAST (Static Application Security Testing) and DAST (Dynamic Testing).

Why This Matters for Your Goals

  • Future-proofing: Companies prioritize engineers who minimize risks.
  • Trust: Secure apps earn user/customer confidence.
  • Career flexibility: Cybersecurity skills open doors to high-impact roles in fintech, healthcare, or government.

“Security is not a product, but a process.” — Bruce Schneier
By embedding security into your coding practice today, you’ll become a developer who builds resilient systems and stands out in the job market. :shield:
lebanon-mug

Day 80 of 100daysofcode : The Unseen Power of the Single Responsibility Principle

Today’s focus isn’t about syntax or frameworks—it’s about a mindset shift. Let’s talk about the Single Responsibility Principle (SRP), the unsung hero of clean, scalable, and maintainable code.

A. What is SRP?

Imagine a chef in a kitchen. If they’re busy chopping veggies, cooking steak, and plating desserts, chaos ensues. But if each chef focuses on one task, the kitchen runs smoothly. SRP is that specialization: one class/module = one job.

B. Why SRP Matters

  1. Clarity Over Chaos: When a component does only what it’s designed for, reasoning about its behavior becomes effortless.
  2. Easier Maintenance: Need to tweak a feature? You’ll only touch the part responsible for it—no domino effect.
  3. Reusability: Components with single purposes are like LEGO blocks. They fit anywhere without forcing workarounds.
  4. Testability: Testing a focused, single-responsibility unit? Simple. Testing a tangled mess? A nightmare.

C. The Cost of Ignoring SRP

Underestimating SRP leads to “God Classes”—components that do everything but excel at nothing. They become fragile, hard to debug, and resistant to change. Ever tried untangling spaghetti? That’s your future codebase without SRP.

D. A Mindset, Not Just a Rule

SRP isn’t about splitting code into microscopic pieces. It’s about intentional design. Ask: “What is this component’s true purpose?” If the answer includes “and,” rethink.

Tomorrow’s you will thank today’s you for embracing SRP. It’s the difference between a codebase that scales gracefully and one that collapses under its own weight. Don’t cut corners—cut responsibilities instead.

:link: Stay disciplined. Code with intent.
lebanon-mug

Day 81 of 100daysofcode : The “O” in SOLID: Open/Closed Principle (OCP)

The Open/Closed Principle states that software entities (classes, modules, functions) should be open for extension but closed for modification. In agile terms, this means designing systems that evolve without rewriting existing code, aligning perfectly with iterative development and changing requirements.

Why OCP Matters in Agile?
Agile thrives on adaptability. By building code that’s extensible, teams can:

  • Add features rapidly without breaking existing functionality.
  • Reduce regression risks (no need to retest unchanged code).
  • Empower parallel workstreams (devs extend, don’t collide).

Applying OCP in Flutter

  1. Leverage Abstraction
  • Define abstract classes or interfaces for core behaviors (e.g., AuthRepository). New implementations (like Firebase or REST APIs) can be added without altering existing code.
  1. Composition Over Inheritance
  • Design widgets as reusable, composable pieces (e.g., a base BaseThemeWidget with customizable styles via injected themes). Extend via composition, not inheritance.
  1. Dependency Injection
  • Inject dependencies (e.g., services, repositories) through constructors. Swap implementations (e.g., mock vs. production) without touching the widget’s core logic.
  1. Plugin Architecture
  • Use strategy patterns for platform-specific code (e.g., file storage). Add new platforms by extending strategies, not modifying core logic.
  1. State Management
  • Abstract state logic (e.g., BlocBase in BLoC) to allow new event handlers or states without refactoring existing workflows.

Agile Wins with OCP

-Faster Sprints: Focus on new code, not retrofitting old code.

  • Cleaner Merges: Less overlap in code changes = fewer conflicts.
  • Future-Proofing: New team members can extend features without deep legacy knowledge.

Think Differently
In Flutter, OCP isn’t just about classes—it’s about designing for uncertainty. Agile teams thrive when the codebase embraces change as a first-class citizen. Tomorrow’s feature is just an extension, not a rewrite!

Next: The “L” in SOLID—keeping your Flutter app substitutable and resilient!
lebanon-mug

Day 82 of 100daysofcode : The Liskov Substitution Principle (LSP)

What is the Liskov Substitution Principle?

Imagine building a LEGO castle where every block seamlessly fits into the same slot as its “parent” block. LSP states that subtypes (child classes) should be substitutable for their base types (parent classes) without breaking the system. If a subclass can’t replace its parent in all scenarios without causing errors or unexpected behavior, it violates LSP.

Why is LSP Important?

LSP ensures that your codebase remains flexible and predictable as it grows. By designing classes to honor their parent’s “contract” (behavior and expectations), you:

  1. Avoid hidden bugs when swapping implementations.
  2. Simplify testing (subclasses behave as expected).
  3. Reduce tight coupling between components, making code easier to refactor.

Future Impact of LSP

When you finish your software, adhering to LSP means:

  1. Effortless Scaling: Adding new features or subclasses won’t destabilize existing systems.
  2. Confident Collaboration: Team members can extend your code without fear of breaking legacy functionality.
  3. Resilient Architecture: Your software evolves gracefully, like a puzzle where new pieces fit perfectly into old slots.

Scenario:

  1. Create a base class Bird with generic behaviors (e.g., eat()).
  2. Create a subclass FlyingBird (with fly()) and NonFlyingBird (without fly()).
    Now, Eagle inherits from FlyingBird, and Penguin from NonFlyingBird.

Future Reflection:

  1. Safe Extensions: Later, adding a Duck or Ostrich won’t break existing logic.
  2. Clear Contracts: Developers know which birds can fly without guessing.
  3. Zero Surprises: Functions expecting FlyingBird can trust fly() works, while NonFlyingBird subtypes focus on their unique traits (e.g., swim()).

Takeaway:
LSP guides you to model hierarchies truthfully. By honoring substitution, your software grows like a well-organized library—every new “book” (class) fits neatly into the right section, and users never stumble over misplaced logic.
lebanon-mug

Day 83 of 100daysofcode : Interface Segregation Principle (ISP)

Imagine building a robot that can cook, clean, and paint. Instead of forcing every robot to carry all these features (even if they only need one), you design separate “toolkits” for cooking, cleaning, and painting. Each robot picks only the tools they need. No extra weight, no unused buttons, no confusion. That’s ISP!

Why It Reflects Positively on Your Project:

  1. No Bloat, Just Focus
    By avoiding “one-size-fits-all” interfaces, your code stays lean. Components only depend on what they actually use, making your project easier to debug and extend.
  2. Change Without Fear
    Need to tweak the “cooking” logic? No risk of breaking the “painting” module! Changes stay isolated, reducing unintended side effects.
  3. Teamwork-Friendly
    Developers work on smaller, well-defined pieces without stepping on each other’s toes. Less merge conflict drama!
  4. Future-Proof Design
    Adding a new feature (like “baking”) doesn’t mean rewriting old code. Just plug in a new, specific interface.

ISP is like designing a LEGO set—small, specialized pieces snap together to build something amazing. When your project wraps up, you’ll appreciate how this principle kept your codebase clean, adaptable, and ready for whatever comes next.
lebanon-mug

Day 84 of 100daysofcode : Dependency Inversion Principle (DIP)

What is the Dependency Inversion Principle (DIP)?

The DIP flips traditional dependency hierarchies to reduce rigid, brittle code. It has two core ideas:
:one: High-level modules (core logic) should not depend on low-level modules (details like databases or APIs). Instead, both should depend on abstractions (like interfaces).
:two: Abstractions should define what needs to be done, not how. Concrete implementations (details) must adhere to these abstractions.

Example: Imagine a universal remote control. Instead of being hardwired to one device (e.g., a TV), it communicates through a standard interface (e.g., infrared signals). Now it can work with any device that “implements” that interface!

“How Does DIP Help Me Today?” :thinking:

  • Test Smarter: Replace real databases or services with mock versions during testing, since they follow the same interface.
  • Swap Components Easily: Change payment gateways, logging tools, or APIs without rewriting your core logic.
  • Future-Proof Code: New features or third-party tools integrate smoothly if they align with your abstractions.
  • Cleaner Collaboration: Teams can work on different modules simultaneously by agreeing on interfaces upfront.

Future Benefits of DIP

  1. Faster Scaling: Add new functionality by extending abstractions, avoiding risky rewrites.
  2. Lower Maintenance Costs: Isolate changes to specific modules, reducing unintended side effects.
  3. Adapt to Trends: Integrate emerging tech (AI, blockchain, etc.) by wrapping them in existing abstractions.
  4. Reusability: Share modules across projects if they rely on common interfaces rather than concrete details.

FAQ :question:

Q: Is DIP the same as Dependency Injection?
A: No! Dependency Injection is a technique to achieve DIP (by passing dependencies into classes). DIP is the guiding principle of relying on abstractions.

Q: Won’t creating interfaces slow me down?
A: Focus on critical areas first (e.g., external services, volatile code). Over-engineering is avoidable—balance flexibility with simplicity.
lebanon-mug

Day 85 of 100daysofcode : Embracing AI as Software Engineers

The integration of Artificial Intelligence (AI) into software development isn’t just a trend—it’s a fundamental shift reshaping how we build, optimize, and scale applications. Here’s why AI matters and how you, as a software engineer, can leverage it:

Why AI is Transforming Software Development

  1. Automation of Repetitive Tasks: AI tools streamline workflows like code reviews, testing, debugging, and deployment, freeing developers to focus on creative problem-solving.
  2. Enhanced User Experiences: AI enables personalization (e.g., recommendation engines), real-time analytics, and adaptive interfaces, making apps smarter and more intuitive.
  3. Data-Driven Decisions: AI-powered analytics help identify patterns, predict user behavior, and optimize performance, turning raw data into actionable insights.
  4. Smarter Applications: From chatbots (NLP) to image recognition (CV), AI adds advanced capabilities that elevate your software’s value proposition.
  5. Competitive Edge: Companies increasingly prioritize AI-driven solutions—adopting these skills keeps you relevant in a fast-evolving industry.

Why Learn AI as a Software Engineer?

  1. Career Growth: AI expertise is in high demand across industries, opening doors to roles like AI Engineer, ML Developer, or AI Product Architect.
  2. Future-Proofing: Understanding AI basics (like neural networks, training models, or APIs) prepares you to adapt as tools like GitHub Copilot or AI-driven DevOps become mainstream.
  3. Innovation: Even basic AI knowledge lets you prototype ideas faster, whether it’s automating workflows or enhancing apps with generative AI.
  4. Collaboration: Bridge the gap between software teams and AI specialists by speaking their language and integrating their models effectively.

How to Start Integrating AI into Your Projects

  1. Leverage APIs & SDKs: Use platforms like OpenAI, Google Cloud AI, or AWS SageMaker to add pre-built AI features (e.g., text generation, speech recognition) without building models from scratch.
  2. Adopt Pre-Trained Models: Frameworks like TensorFlow, PyTorch, or Hugging Face offer ready-to-use models for common tasks (e.g., sentiment analysis, object detection).
  3. Understand Data Pipelines: AI thrives on data. Learn to clean, preprocess, and manage datasets to train or fine-tune models effectively.
  4. Focus on Ethics: Address biases, privacy concerns, and transparency when deploying AI to build trust and compliance.
  5. Experiment Incrementally: Start small—add a chatbot to your web app, implement smart search, or automate QA testing with AI tools.

AI isn’t replacing developers—it’s empowering us to solve bigger problems, faster. By learning to interact with AI tools and frameworks, you’ll unlock new dimensions of creativity and efficiency in your projects. Dive into tutorials, experiment with APIs, and stay curious!
lebanon-mug

This topic will automatically close in 3 months.