Spring Boot Multi-Tenancy සිංහලෙන් | Schema-Based Implementation Guide

Spring Boot Multi-Tenancy සිංහලෙන් | Schema-Based Implementation Guide

අද කාලේ software ලෝකයේ, එකම Application එකක් හරහා Customersලා ගොඩකට සේවය සපයන එක සාමාන්‍ය දෙයක් වෙලා. SaaS (Software as a Service) Application ගැන ඔයාලා අහල ඇතිනේ. ඒ වගේ වෙලාවට, එක Customer කෙනෙක්ගේ data, තව Customer කෙනෙක්ට පේන්නේ නැති විදිහට maintain කරන එක හරිම වැදගත්.

මේ වගේ situation එකකදී, අපිට තියෙන ප්‍රධානම විසඳුම තමයි Multi-Tenancy Architecture. මේක හරිම වැදගත් concepts එකක්. මොකද මේකෙන් අපේ Application එකේ scalability එක, maintainability එක වගේම cost efficiency එකත් වැඩි කරගන්න පුළුවන්. Spring Boot developersලා විදිහට අපිට මේ ගැන හොඳ අවබෝධයක් තියෙන්න ඕනේ. ඉතින් අද අපි කතා කරමු Spring Boot application එකක් ඇතුළේ multi-tenancy කොහොමද ක්‍රියාත්මක කරන්නේ කියලා, ඒකත් අපේම භාෂාවෙන්!

Multi-Tenancy කියන්නේ මොකක්ද?

සරලව කිව්වොත්, Multi-Tenancy කියන්නේ single instance of a software application එකක්, multiple distinct customer groups (tenants) වලට සේවය සපයන architecture එකක්. මෙතනදී, "tenant" කෙනෙක් කියන්නේ Organization එකක් වෙන්න පුළුවන්, User Group එකක් වෙන්න පුළුවන්, නැත්නම් වෙනත් client කෙනෙක් වෙන්නත් පුළුවන්.

සාමාන්‍යයෙන්, Application එකක Data වෙන වෙනම තියෙන්න ඕනේ. උදාහරණයක් විදිහට, Accounting software එකක් ගන්න. Company A එකේ data, Company B එකට පේන්න බැහැ නේ. ඒ වගේම, Company A එකේ අය Company B එකේ data වලට access කරන්නත් බැහැ. Multi-Tenancy වල ප්‍රධාන අරමුණ තමයි මේ data isolation එක හරියට maintain කරන එක.

Single-Tenancy එක්ක සසඳනකොට, Single-Tenancy වලදී එක customer කෙනෙක්ට වෙනම Application instance එකක් වගේම වෙනම Database එකකුත් අවශ්‍ය වෙනවා. ඒක හරිම වියදම් අධිකයි, වගේම manage කරන්නත් අමාරුයි. හැබැයි Multi-Tenancy වලදී එක Application එකක් සහ share කරන Database එකක් පාවිච්චි කරන නිසා cost එක අඩු කරගන්නත්, maintenance පහසු කරගන්නත් පුළුවන්.

ප්‍රධාන වාසි ටිකක් බලමු:

  • Cost Efficiency: Hardware, software licenses, maintenance වියදම් අඩුයි, මොකද resource sharing වෙන නිසා.
  • Simplified Maintenance & Updates: Updates කරන්න තියෙන්නේ එක Application instance එකක් විතරයි. හැම customer කෙනෙක්ටම වෙන වෙනම updates කරන්න ඕනේ නැහැ.
  • Scalability: නව tenantsලා එකතු කරන එක හරිම පහසුයි. Resource sharing නිසා, Application එකේ performance එකට ලොකු බලපෑමක් වෙන්නේ නැහැ.
  • Resource Utilization: Hardware resources වඩාත් කාර්‍යක්‍ෂම විදිහට භාවිතා කරන්න පුළුවන්.

Multi-Tenancy ක්‍රියාත්මක කරන ප්‍රධාන ක්‍රම

Multi-tenancy ක්‍රියාත්මක කරන්න ප්‍රධාන විදි තුනක් තියෙනවා. මේ හැම ක්‍රමයකටම තමන්ටම ආවේණික වාසි වගේම අවාසිත් තියෙනවා. අපි එකින් එක බලමු.

1. Separate Database (වෙනම Database)

මේ ක්‍රමයේදී, හැම tenant කෙනෙක්ටම වෙනම Database එකක් භාවිතා කරනවා. මේක තමයි වැඩිම data isolation එකක් දෙන ක්‍රමය. එක tenant කෙනෙක්ගේ data වෙන tenant කෙනෙක්ට බලන්න පුළුවන් වෙන්නේ නැහැ කියන එක සියයට සියයක්ම වගේ සහතික කරන්න පුළුවන්.

  • වාසි:
    • ඉහළම data isolation එකක්.
    • Backup සහ Restore කරන්න පහසුයි, මොකද හැම tenant කෙනෙක්ටම වෙනම DB එකක් තියෙන නිසා.
    • ඕනෑම tenant කෙනෙක්ට වෙනම database schema එකක් තියාගන්න පුළුවන් (schema evolution).
  • අවාසි:
    • එක tenant කෙනෙක්ට වෙනම DB එකක් හදන නිසා, වැඩිම Database instances ප්‍රමාණයක් අවශ්‍ය වෙනවා. ඒ නිසා Infrastructure cost එක වැඩියි.
    • Manage කරන්න ටිකක් අමාරුයි. Database updates, patches වගේ දේවල් හැම DB එකකටම කරන්න ඕනේ.

2. Separate Schema (වෙනම Schema)

මේ ක්‍රමයේදී, හැම tenant කෙනෙක්ටම එකම Database එකක් තුළ වෙනම schema එකක් භාවිතා කරනවා. මේක Separate Database ක්‍රමයට වඩා පොඩ්ඩක් අඩු isolation එකක් දුන්නත්, සාමාන්‍යයෙන් සාධාරණ ආරක්ෂාවක් සපයනවා.

  • වාසි:
    • Separate Database වලට වඩා cost එක අඩුයි, මොකද එකම Database instance එකක් භාවිතා කරන නිසා.
    • Data isolation එක හොඳ මට්ටමක තියෙනවා.
    • Manage කරන්න Separate Database වලට වඩා පහසුයි.
  • අවාසි:
    • Database එකේ ප්‍රමාණය වැඩි වෙනකොට performance issues එන්න පුළුවන්.
    • සියලුම tenant schemas එකම database එකේ තිබීම නිසා, database-level disaster එකකදී සියලුම tenantsලාට බලපෑම් ඇති වෙන්න පුළුවන්.

3. Discriminator Column (Shared Schema)

මේක තමයි ගොඩක් Application වලදී පාවිච්චි කරන සාමාන්‍ය ක්‍රමය. මෙහිදී, හැම tenant කෙනෙක්ටම එකම Database එකක් සහ එකම schema එකක් භාවිතා කරනවා. Data isolation එක කරන්නේ හැම table එකකම tenant_id වගේ column එකක් එකතු කරලා.

  • වාසි:
    • වඩාත්ම cost effective ක්‍රමය, මොකද තියෙන්නේ එකම DB එකක් සහ එකම schema එකක් නිසා.
    • Manage කරන්න හරිම පහසුයි. Updates කරන්න තියෙන්නේ එක schema එකක් විතරයි.
    • Scalability එක හොඳයි.
  • අවාසි:
    • Data isolation එක ටිකක් දුර්වලයි, මොකද application code එකෙන් හැම query එකකටම tenant_id එක add කරන්න ඕනේ. මේක හරියට manage නොකළොත් data leaks වෙන්න ඉඩ තියෙනවා.
    • ලොකු database එකක් වෙන්න පුළුවන් නිසා performance issues එන්න පුළුවන්, queries වලට indexes හරියට නැත්නම්.
    • Backup/restore tenant-specific කරන්න අමාරුයි.

මේ Article එකේදී අපි Separate Schema ක්‍රමය Spring Boot එක්ක Implement කරන විදිහ බලමු. මේක ගොඩක් projects වලට සුදුසු, balance එකක් තියෙන method එකක්.

Spring Boot වල Multi-Tenancy Schema-Based ක්‍රියාත්මක කරමු

Spring Boot Application එකක් ඇතුළේ Schema-based multi-tenancy ක්‍රියාත්මක කරනවා කියන්නේ අපි dynamically database schema එක switch කරන්න ඕනේ කියන එක. ඒ කියන්නේ, request එකක් එනකොට, ඒ request එක අයිති tenant කෙනා කවුද කියලා හඳුනගෙන, ඒ tenant ගේ schema එකට database connection එක redirect කරන්න ඕනේ.

මේක සාර්ථකව කරන්න අපිට ප්‍රධාන steps කීපයක් තියෙනවා:

  1. Request එකෙන් Tenant ID එක identify කරගන්න එක.
  2. Identify කරගත්තු Tenant ID එක, Application එක පුරාම access කරන්න පුළුවන් තැනක store කරන එක.
  3. Data Source එක dynamically switch කරන එක.
  4. Hibernate / JPA configure කරන එක.

හරි, දැන් අපි මේක ක්‍රියාත්මක කරමු. මේ උදාහරණය සඳහා, අපි PostgreSQL Database එකක් භාවිතා කරමු.

1. Tenant ID එක Manage කරමු

අපි Tenant ID එක HTTP Request Header එකක් විදිහට (X-Tenant-ID) ලබාගමු. මේක ThreadLocal එකක store කරගන්න පුලුවන්, මොකද ඒක request එකේ scope එකට අදාල වෙන නිසා.

TenantContext.java:


package com.scguide.multitenancy.context;

public class TenantContext {

    private static ThreadLocal<String> currentTenant = new ThreadLocal<>();

    public static void setCurrentTenant(String tenant) {
        currentTenant.set(tenant);
    }

    public static String getCurrentTenant() {
        return currentTenant.get();
    }

    public static void clear() {
        currentTenant.remove();
    }
}

මේක හරිම සරල class එකක්. ThreadLocal එකක් භාවිතා කරලා, දැනට active වෙලා තියෙන tenant ID එක store කරගන්නවා. Request එක ඉවර වුණාම clear() method එකෙන් මේක remove කරන්න ඕනේ, නැත්නම් memory leaks වෙන්න පුළුවන්.

2. Tenant Identifier Interceptor

දැන් අපිට ඕනේ හැම incoming request එකකින්ම X-Tenant-ID Header එක අරගෙන, ඒක TenantContext එකේ set කරන්න. ඒකට අපි Spring Interceptor එකක් භාවිතා කරමු.

TenantInterceptor.java:


package com.scguide.multitenancy.interceptor;

import com.scguide.multitenancy.context.TenantContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

@Component
public class TenantInterceptor implements HandlerInterceptor {

    private static final String TENANT_HEADER = "X-Tenant-ID";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String tenantId = request.getHeader(TENANT_HEADER);
        if (tenantId == null || tenantId.isEmpty()) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            response.getWriter().write("Tenant ID (X-Tenant-ID) header is required.");
            return false;
        }
        TenantContext.setCurrentTenant(tenantId);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        TenantContext.clear(); // Clear tenant ID after request is handled
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // You might want to clear here as well, depending on your application flow.
        // For simple cases, postHandle is sufficient.
        TenantContext.clear();
    }
}

WebConfig.java: (Interceptor එක register කරන්න)


package com.scguide.multitenancy.config;

import com.scguide.multitenancy.interceptor.TenantInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    private final TenantInterceptor tenantInterceptor;

    public WebConfig(TenantInterceptor tenantInterceptor) {
        this.tenantInterceptor = tenantInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tenantInterceptor);
    }
}

3. Dynamic Data Source Routing

Spring Framework එකේ AbstractRoutingDataSource කියන class එකක් තියෙනවා. මේකෙන් පුළුවන් runtime එකේදී database connections switch කරන්න. අපි මේක extend කරලා අපේම implementation එකක් හදමු.

TenantAwareRoutingDataSource.java:


package com.scguide.multitenancy.datasource;

import com.scguide.multitenancy.context.TenantContext;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class TenantAwareRoutingDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return TenantContext.getCurrentTenant();
    }
}

මේ class එකේ determineCurrentLookupKey() method එකෙන් අපි TenantContext එකේ තියෙන current tenant ID එක return කරනවා. Spring Framework එක මේ ID එක පාවිච්චි කරලා, අදාල Database/Schema එකට connection එක routing කරනවා.

4. Data Source Configuration

දැන් අපි විවිධ tenantsලා සඳහා DataSources configure කරන්න ඕනේ. මේක කරන්න අපිට පුළුවන් properties file එකකින්, නැත්නම් dynamically database එකකින්tenant details load කරගන්නත් පුළුවන්. සරලව, අපි properties file එකෙන් configure කරමු.

application.properties:


# Default Data Source (Optional, for public data or fallback)
spring.datasource.url=jdbc:postgresql://localhost:5432/default_db
spring.datasource.username=user
spring.datasource.password=password
spring.datasource.driver-class-name=org.postgresql.Driver

# Tenant-specific Data Sources (You would usually load these from a separate config or DB)
# For demonstration, we define them here. Keys "tenant1", "tenant2" must match Tenant ID headers.
tenant.datasource.tenant1.url=jdbc:postgresql://localhost:5432/main_db?currentSchema=tenant_one_schema
tenant.datasource.tenant1.username=user
tenant.datasource.tenant1.password=password

tenant.datasource.tenant2.url=jdbc:postgresql://localhost:5432/main_db?currentSchema=tenant_two_schema
tenant.datasource.tenant2.username=user
tenant.datasource.tenant2.password=password

මෙහිදී, main_db කියන්නේ එකම Database එකයි. ඒත් currentSchema parameter එකෙන් අපි විවිධ schemas specify කරනවා. tenant_one_schema සහ tenant_two_schema වගේ schemas database එකේ තිබිය යුතුයි.

MultiTenantDataSourceConfig.java:


package com.scguide.multitenancy.config;

import com.scguide.multitenancy.datasource.TenantAwareRoutingDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class MultiTenantDataSourceConfig {

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSourceProperties defaultDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @Primary
    public DataSource defaultDataSource() {
        return defaultDataSourceProperties()
                .initializeDataSourceBuilder()
                .build();
    }

    @Bean
    @ConfigurationProperties(prefix = "tenant.datasource")
    public Map<String, DataSourceProperties> tenantDataSourceProperties() {
        return new HashMap<>();
    }

    @Bean
    public DataSource multiTenantDataSource() {
        TenantAwareRoutingDataSource multiTenantDataSource = new TenantAwareRoutingDataSource();

        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("default", defaultDataSource()); // Default/Public tenant if needed

        tenantDataSourceProperties().forEach((tenantId, properties) ->
            targetDataSources.put(tenantId, properties.initializeDataSourceBuilder().build())
        );

        multiTenantDataSource.setTargetDataSources(targetDataSources);
        multiTenantDataSource.setDefaultTargetDataSource(defaultDataSource()); // Fallback if no tenant ID

        multiTenantDataSource.afterPropertiesSet(); // Important!
        return multiTenantDataSource;
    }
}

මේ Config class එකෙන් අපි application.properties එකෙන් tenant-specific data source properties load කරගෙන, ඒ හැම එකකටම DataSource object එකක් හදනවා. ඊට පස්සේ, ඒ හැම DataSource එකක්ම TenantAwareRoutingDataSource එකට map කරනවා. @Primary annotation එක දාන්නේ Spring Boot එකට මේ multiTenantDataSource එක තමයි default DataSource එක විදිහට පාවිච්චි කරන්න ඕනේ කියලා කියන්නයි.

5. Hibernate/JPA Configuration

Hibernate එකට කියන්න ඕනේ current schema එක select කරන්න කියලා. ඒකට org.hibernate.context.spi.CurrentTenantIdentifierResolver interface එක implement කරන්න වෙනවා.

CurrentTenantIdentifierResolverImpl.java:


package com.scguide.multitenancy.config;

import com.scguide.multitenancy.context.TenantContext;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.springframework.stereotype.Component;

@Component
public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {

    private final String defaultTenant = "default"; // Or a specific default schema like 'public'

    @Override
    public String resolveCurrentTenantIdentifier() {
        String tenantId = TenantContext.getCurrentTenant();
        return tenantId != null ? tenantId : defaultTenant;
    }

    @Override
    public boolean validateExistingCurrentSessions() {
        return true;
    }
}

මේ class එක TenantContext එකෙන් current tenant ID එක අරගෙන Hibernate එකට දෙනවා. Request එකේ Tenant ID එකක් නැත්නම්, defaultTenant එක භාවිතා කරනවා.

Hibernate Properties Configure කරන්න:

application.properties එකට මේ ටික add කරන්න:


spring.jpa.hibernate.ddl-auto=update # Or none, create etc.
spring.jpa.properties.hibernate.multi_tenant=SCHEMA # IMPORTANT for Schema-based multi-tenancy
spring.jpa.properties.hibernate.tenant_identifier_resolver=com.scguide.multitenancy.config.CurrentTenantIdentifierResolverImpl
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

hibernate.multi_tenant=SCHEMA කියන එක හරිම වැදගත්. ඒ වගේම hibernate.tenant_identifier_resolver එකට අපි හදපු resolver class එකේ full path එක දෙන්න ඕනේ.

6. Testing

දැන් ඔබට පුළුවන් controller එකක් හදලා, X-Tenant-ID header එක එක්ක requests යවලා test කරන්න. http://localhost:8080/api/your-entity වගේ request එකක් යවනකොට, X-Tenant-ID: tenant1 කියලා header එකක් දැම්මොත්, database operations tenant_one_schema එකෙන් සිද්ධ වෙයි. X-Tenant-ID: tenant2 දැම්මොත් tenant_two_schema එකෙන් සිද්ධ වෙයි.

මේ හැම schema එකකම එකම table structure එක තියෙන්න ඕනේ (උදා: users table එක). Migrations manage කරන්න Flyway හෝ Liquibase වගේ tools use කරන්න පුළුවන්.

Multi-Tenancy ක්‍රියාත්මක කරනකොට මතක තියාගන්න දේවල්

Multi-tenancy කියන්නේ powerful concept එකක් වුණත්, ඒක implement කරනකොට අනිවාර්යයෙන්ම සැලකිලිමත් වෙන්න ඕන කරුණු කීපයක් තියෙනවා:

  • Data Security සහ Isolation:මේක තමයි multi-tenancy වල වැදගත්ම අංගය. එක tenant කෙනෙක්ගේ data කිසිම විදිහකින් තව tenant කෙනෙක්ට access කරන්න බැරි වෙන්න ඕනේ. අපේ architecture එකේ TenantContext, TenantAwareRoutingDataSource, සහ Hibernate configuration එක හරියට තිබුණොත් මේක ensure කරන්න පුළුවන්. හැබැයි, custom queries, native SQL queries, සහ database backups/restores වගේ දේවල් වලදීත් මේ data isolation එක ensure වෙනවාද කියලා double-check කරන්න ඕනේ.
  • Performance සහ Scalability:Tenantsලා ගණන වැඩි වෙනකොට Application එකේ performance එකට බලපෑමක් වෙන්න පුළුවන්. ખાસ કરીને Shared Schema (Discriminator) model එකේදී එකම table එකේ records මිලියන ගණන් තියෙනකොට queries optimize කරන්න වෙයි. Schema-based ක්‍රමයේදී ඒ ප්‍රශ්නය පොඩ්ඩක් අඩුයි, මොකද data set එක schemas වලට බෙදිලා තියෙන නිසා. Database connection pooling, caching, සහ proper indexing වගේ දේවල් ගැන සැලකිලිමත් වෙන්න.
  • Schema Migrations සහ Updates:Application එක update කරනකොට, database schema එකත් update කරන්න සිද්ධ වෙන්න පුළුවන්. Multi-tenant environment එකකදී මේක ටිකක් අභියෝගාත්මකයි. මොකද හැම tenant schema එකක්ම update කරන්න ඕන වෙන නිසා. Flyway හෝ Liquibase වගේ tools පාවිච්චි කරලා automate කරගන්න පුළුවන්.
  • Common Data Handling:තවත් වැදගත් කාරණයක් තමයි "common data" manage කරන එක. සමහර data හැම tenant කෙනෙක්ටම පොදුයි. උදාහරණයක් විදිහට, රටවල් ලැයිස්තුවක්, මුදල් වර්ග, හෝ පොදු කාණ්ඩ. මේවා වෙනම "public" හෝ "master" schema එකක තියලා, හැම tenant schema එකෙන්ම ඒකට read-only access දෙන්න පුළුවන්.
  • Tenant Provisioning සහ De-provisioning:අලුත් tenant කෙනෙක් add කරනකොට (provisioning) සහ tenant කෙනෙක් remove කරනකොට (de-provisioning) database schema එකක් හදන, remove කරන, data migrate කරන වගේ process automate කරන්න වෙනවා. මේකට වෙනම management microservice එකක් වගේ දෙයක් භාවිතා කරන්න පුළුවන්.
  • Backup සහ Restore:Tenant-specific backups සහ restores කරන්න වෙනවා. Separate database ක්‍රමයේදී මේක පහසුයි. හැබැයි Shared Schema හෝ Separate Schema ක්‍රමවලදී ටිකක් සංකීර්ණයි. ඒ නිසා backup strategy එක ගැන කලින්ම සැලසුම් කරන්න.

Conclusion

Multi-Tenancy architecture එකක් Spring Boot application එකකට implement කරන එක ලොකු වාසි ගොඩක් දෙනවා, විශේෂයෙන්ම SaaS applications වලදී. Cost එක අඩු කරගෙන, maintenance පහසු කරගෙන, Application එකේ scalability එක වැඩි කරගන්න මේක හරිම වැදගත්.

අපි මේ Article එකෙන් කතා කරපු Schema-based multi-tenancy ක්‍රමය, හොඳ data isolation එකක් සහ සාධාරණ cost එකක් අතර හොඳ සමබරතාවයක් ඇති කරගන්න පුළුවන් ක්‍රමයක්. හැබැයි, ඔයාගේ Project එකේ requirements අනුව, Separate Database, Separate Schema, නැත්නම් Discriminator Column වගේ ක්‍රම අතරින් වඩාත් සුදුසු එක තෝරාගන්න එක අනිවාර්යයෙන්ම ඔයාට බාරයි.

මේ වගේ system එකක් build කරනකොට security, performance, සහ maintainability ගැන හොඳට හිතලා බලන්න. මේ concepts ටික පාවිච්චි කරලා ඔයාගේම multi-tenant Spring Boot Application එකක් හදලා බලන්න! ඒක හරිම satisfying experience එකක් වෙයි.

ඔයා මේ ගැන මොකද හිතන්නේ? ඔයාට ප්‍රශ්න තියෙනවනම් comment එකක් දාන්න. අපි මේ වගේ තවත් technical Article එකකින් හම්බවෙමු! ඈ… සුබ දවසක්!