Friday, November 29, 2024

Micro Services - Backward compatibility design

Microservice Backward Compatibility

In a microservices architecture, ensuring backward compatibility is crucial for maintaining system stability and allowing independent deployment of services without breaking upstream dependencies.

One of the primary goals in a microservices architecture is to enable independent deployment of services. This means that changes to one service should not break or disrupt the functionality of other services that depend on it. To achieve this, backward compatibility must be maintained, ensuring that new changes do not affect existing contracts or interfaces. 

Here are some key approaches to achieve backward compatibility: 

Approach: Contract Models – Enhance Instead of Change

When evolving a microservice, it is important to enhance the contract models rather than changing them. This means adding new fields or endpoints instead of modifying or removing existing ones. By doing so, existing clients can continue to function without any changes, while new clients can take advantage of the enhanced features. This approach ensures that the service remains backward compatible and does not break any upstream dependencies. 

Approach: Create Adaptor

Another effective approach is to create an adaptor. Instead of changing the contract model directly, an adaptor can be introduced to handle the differences between the internal business model and the contract model. This allows the internal business model to evolve independently of the contract model. The adaptor translates between the two models, ensuring that the contract remains stable and backward compatible. This approach provides flexibility to change the internal business logic without impacting the external contract. 

Version Strategy to Communicate Major Changes

When major changes are necessary, a versioning strategy should be employed. Versioning the API allows clear communication of the contract version that the API is working with. By using version numbers in the API endpoints (e.g., /api/v1/resource), clients can explicitly specify which version of the contract they are using. This ensures that clients are aware of the changes and can migrate to the new version at their own pace, while still maintaining backward compatibility with the older versions.

 


Micro Services - Resiliency

In modern software systems, resiliency is a critical aspect that ensures the system remains functional and responsive even in the face of failures or unexpected conditions. Several design patterns can be employed to enhance the resiliency of a system. Below are some key patterns: 

Timeout Pattern

The Timeout pattern is used to configure a timeout for all downstream calls. This pattern helps in failing fast by setting a maximum time limit for a call to complete. If the call does not complete within the specified time, it is aborted. This prevents the system from waiting indefinitely for a response, which can lead to resource exhaustion and degraded performance.  However, if there are a lot of calls within this timeout period, it can still lead to issues. This is where the Circuit Breaker pattern comes into play. 

Circuit Breaker Pattern

The Circuit Breaker pattern is often used in conjunction with the Timeout pattern. It involves implementing a circuit breaker component that tracks all outgoing calls from the service. If the component observes a high number of failures (above a certain threshold), it transitions to an "open" state. In this state, the circuit breaker immediately responds with an error message or a default response, without attempting to make the call. This prevents the system from being overwhelmed by repeated failures and helps maintain overall system health by avoiding cascading failures.  The circuit breaker also has a "half-open" state, where it allows a few calls to pass through to check if the downstream services have recovered. If the calls succeed, the circuit breaker transitions back to the "closed" state, allowing normal operation to resume. 

Retry Pattern

The Retry pattern is useful for handling transient issues. It involves retrying a failed operation a certain number of times before giving up. This pattern helps in self-correcting the services and is particularly effective when used with the Circuit Breaker and Timeout patterns. By retrying operations, the system can recover from temporary issues without manual intervention. 

Bulkhead Pattern

The Bulkhead pattern involves separating services by their criticality and functionality. High-criticality services are allocated more resources to ensure their availability. This separation makes it easier to manage and segregate execution. Additionally, workload balancing can be used to distribute the load across multiple instances of a service. Load shedding can also be employed, where the load balancer redirects requests from overloaded instances to less busy ones. This ensures that retries are more likely to succeed by avoiding overloaded instances. 

Caching Pattern

The Caching pattern involves storing responses for repeated data to reduce the load on the system. By caching frequently requested data, the system can serve responses faster and reduce the number of calls to downstream services. This not only improves performance but also enhances resiliency by reducing the dependency on external services.

 

Micro Services - Database Design Pattern

In a microservices architecture, each microservice typically manages its own database. This approach offers several benefits, such as improved scalability and independence. However, it also introduces challenges, particularly around data sharing and consistency. To address these challenges, several complementary patterns can be employed: 

Event-Driven Pattern

In an event-driven architecture, each microservice saves data in its own database. The limitation of this approach is the difficulty in sharing data between microservices. To overcome this, microservices can connect with each other and create a copy of data from other microservices, storing it as a local cache. This allows microservices to access the necessary data without directly querying another service's database, thus reducing inter-service dependencies and improving performance. 

Event Sourcing Pattern

Event sourcing involves storing data as a series of events. This pattern is straightforward to implement in a monolithic database but is also feasible with microdatabases. Instead of storing the current state of an entity, all changes (events) to the entity are stored. To determine the latest state of the data, all events must be replayed and evaluated. While this approach can impact performance and increase storage requirements, it offers the advantage of easy data rollback by replaying events up to a certain point. Event sourcing provides a detailed audit trail and can be useful for debugging and compliance purposes. 

CQRS (Command and Query Responsibility Segregation) Pattern

CQRS separates the reading and writing of data into different models. In this pattern, there are distinct services for handling commands (writes) and queries (reads). The write and read databases are different, and a synchronization mechanism is required to keep them in sync. This separation allows for optimized read and write operations, as each can be scaled and optimized independently. However, ensuring data consistency between the write and read databases is critical and can add complexity to the system.

Micro Services - Asynchronous design

Asynchronous communication is a key aspect of modern microservices architecture, providing several benefits that enhance the overall system performance and scalability :

De-coupling Across Components - Asynchronous communication decouples components, allowing them to operate independently without waiting for each other. This reduces dependencies and improves system resilience. 

Fire-and-Forget Interaction- In a fire-and-forget interaction, the sender sends a message and does not wait for a response. This is useful for tasks that do not require immediate feedback, reducing the load on the system and improving responsiveness. 

Support Long-Running Jobs - Asynchronous communication supports long-running jobs by allowing tasks to be processed in the background. This prevents blocking resources and ensures that the system remains responsive to other requests. 

 

Microservice Functional Requirements

To build effective microservices, certain functional requirements must be met: 

Loosely Coupled Service  - Microservices should be loosely coupled, meaning changes in one service should not impact others. This enhances maintainability and scalability. 

Backward Compatibility - Independently Changeable - Services should be independently changeable without breaking existing functionality. This ensures that updates can be made without disrupting the system. 

Backward Compatibility - Independently Deployable - Microservices should be independently deployable, allowing for updates and deployments without affecting other services. 

Support and Honor Contracts - Microservices must support and honor contracts, ensuring consistent and reliable communication between services. 

Technology Agnostic API - APIs should be technology agnostic, allowing different technologies to interact seamlessly. 

Stateless - Microservices should be stateless, meaning they do not retain client state between requests. This simplifies scaling and improves reliability. 

Lightweight Communication - Communication between microservices should be lightweight to reduce overhead and improve performance. 

Cache-able Communication - Communication should be cache-able to improve efficiency and reduce redundant processing. 

UsabilityAPI Consistency, Predictable, Readable - APIs should be consistent, predictable, and readable to enhance usability and developer experience. 

UsabilityQuery-able Data - APIs should allow for query-able data to enable flexible and efficient data retrieval. 


Pragmatic REST API - Pragmatic REST API refers to a more practical approach to REST, focusing on simplicity and usability rather than strictly adhering to CRUD operations. 

Example :

Use Verbs Instead of Nouns: Use verbs in the API to denote actions, e.g., /startProcess instead of /process.

Append Query Parameters: Use query parameters to pass constraints, e.g., /search?query=example.

HATEOAS: Implement Hypermedia as the Engine of Application State (HATEOAS) by including URLs in responses to guide the client on the next steps, e.g., the server responds with the next URL needed for the client to make a call.

By following these principles, microservices can achieve better performance, scalability, and maintainability, while providing a more practical and user-friendly API.

 

Facade Pattern

The Facade pattern is popular for keeping implementation separate from the contract. It provides flexibility in the implementation without impacting the integration. This pattern simplifies the interface for the client and hides the complexities of the underlying system. 

Proxy Pattern

The Proxy pattern is popular when connecting with other services. The proxy object helps in various scenarios such as caching and making the internal model extendable. It can also assist with authentication and authorization. Additionally, the proxy pattern is beneficial for unit testing, as mocking proxy data is straightforward.

Micro Services - synchronize data

 Data Consistency Across Microservices

In a distributed microservices architecture, ensuring data consistency is crucial. When a failure occurs in one step, other transactions must either be canceled or rolled back to maintain consistency. 

 

Traditional Approach - Traditionally, all updates are made as a single transaction, ensuring that either all operations succeed or fail together. This approach is feasible in monolithic architectures where a single database can be used to update all records simultaneously. However, this is not possible with microservices, which typically use distributed databases, each maintaining its own data. 

 

ACID Properties

Transactions in microservices should adhere to ACID properties: 

Atomicity: All or nothing when committing data changes.

Consistency: Data transitions from one valid state to another.

Isolation: Transactions run in isolation and are not affected by concurrency.

Durability: Committed data changes are durable and persist in the database.

 

2-Phase Commit Pattern

The 2-Phase Commit pattern focuses on data consistency rather than availability. It introduces a transaction manager (TxnMgr) to ensure data consistency. The process involves: 

Event Publication: The UI/BFF publishes an event to the bus.

Transaction Manager: TxnMgr subscribes to the event and creates a record in its database, detailing the components involved in the transaction.

Prepare Event: TxnMgr publishes a "prepare" event, which other microservices subscribe to and prepare for the task.

Vote Collection: Microservices publish their vote (success/fail) after preparation. TxnMgr records these votes.

Commit/Rollback: If all votes are successful, TxnMgr publishes a "commit" event, and microservices complete the task. If any service fails, TxnMgr publishes a "rollback" event, and microservices roll back their preparation steps.

Pros

    Guaranteed atomicity across services.

    ACID compliant.

Cons

    Performance bottleneck due to waiting for TxnMgr responses.

    Single point of failure with TxnMgr.

    Complexity in handling retries and failures.

 

Saga Pattern

The Saga pattern focuses on atomicity and is more popular than the 2-Phase Commit pattern. It uses a Saga Execution Coordinator (SEC) and saga logs to manage transactions. The process involves: 

Saga Entries: Incoming transactions are converted into saga entries, each representing a service task with a corresponding compensation request (rollback request).

Status Recording: SEC records the status of each microservice. If all responses are complete, the transaction is complete.

Communication: Requests can be sent to individual services together or one-by-one using HTTP or events.

 

Pros

    Ensures data integrity.

    Fault tolerance with compensation requests.

    Scalable and loosely coupled.

Cons

    Implementation complexity.

    Performance overhead due to asynchronous communication and compensating actions.


Eventual Consistency Pattern

The Eventual Consistency pattern prioritizes availability over strict ACID properties. Asynchronous messages are published, and microservices process them independently. Data may be temporarily out of sync, but it will eventually become consistent.  

Pros

    High availability.

    Simple implementation.

Cons

    Temporary data inconsistency.

    Requires careful handling to ensure eventual consistency.

Micro Services - Composition


Microservices architecture often requires composing multiple services to complete a single operation. Here are various composition patterns used in microservices: 

When an operation requires more than one service to complete, a composition pattern is used. This involves coordinating multiple microservices to achieve a single business goal. 

 

Broker Composition Pattern

In the Broker Composition pattern, a message is published to a message broker. All subscribers pick up this message and process their tasks. Once all the work is complete, the client gets a notification and can pull the relevant data back. This asynchronous communication provides flexibility, good performance, and reliability. 

 

Aggregate Composition Pattern

The Aggregate Composition pattern involves an aggregator component, often a Backend for Frontend (BFF), responsible for fetching data from multiple microservices. The aggregator connects with other microservices, aggregates the data, and returns it to the front end. However, synchronous calls between the aggregator and other microservices can lead to a poor client experience. 

 

Chained Composition Pattern

The Chained Composition pattern is considered an anti-pattern. In this pattern, the client calls Service 1, which calls Service 2, and so on, creating a chain of HTTP calls. This can lead to increased latency and complexity. 

 

Proxy Composition Pattern

In the Proxy Composition pattern, an API gateway connects with all downstream services and returns the information to the client. The gateway does not aggregate data; instead, the front end is responsible for making multiple gateway calls and aggregating the data. These endpoints are called passive endpoints because the proxy has minimal logic and acts as a pass-through. The API gateway can provide benefits such as a centralized layer for security checks and data caching. It can also handle API version mapping. However, the drawback is that the client has to make multiple calls, one for each service. 

 

Mixed Composition Pattern

The Mixed Composition pattern combines multiple composition patterns. It uses the Broker Composition pattern as the base and adds a BFF as an aggregator layer. Once a message is published to the broker and a notification indicates that the data is ready, the aggregator fetches the data points, aggregates them, and returns them to the client. The BFF can connect with individual services to get the data, avoiding a chain of calls. An API gateway (Proxy Composition pattern) can be introduced on top of the services to expose the data to more consumers.

 


Micro Services - Architect with context

Begin with Microservices

 

Traditionally, software development has often relied on monolithic architectures, where all functionalities are built as part of a single, large service. This approach can lead to significant issues, as making a change in one aspect of the system can impact the entire product. Microservices architecture addresses this problem by creating boundaries around different aspects of the product, known as contexts. Each context is implemented as an independent service, referred to as a bounded context. 

 

Bounded Context

A bounded context is a specific area of the application with a clear boundary and interface. Each microservice has a specific role centered around this context. Bounded contexts can have sub-contexts, which may be related to data/models or functions. There are two primary approaches to defining bounded contexts: 

 

Ubiquitous Language

This approach is suitable for smaller projects and teams. The bounded context is defined based on the language or context used within the team. During the definition process, if overlapping sub-contexts are identified, they are either renamed to match the bounded context or extracted to form a new bounded context. If cross-references between bounded contexts remain, these points become integration points.

 

Event Storming

Event storming is a planning, estimation, and design session where the team goes over the details of all the events that form the product. This includes the sequence of events, associated commands (which trigger events), and any issues related to the events. By aggregating all the notes around these events, the team can define the bounded context and the corresponding services.

 

Aggregation of Microservices

In some cases, the contexts of two services are so closely related that creating a single service is more efficient. In such scenarios, an aggregate service is created to encompass both contexts.

 

Understanding Architecture

In a microservices architecture, asynchronous communication is essential to ensure scalability, responsiveness, and efficient resource utilization. Here’s a detailed look at why asynchronous connections are needed and how to implement them effectively. 

 

Why We Need Asynchronous Connections

With microservices architecture, numerous components are connected over the network. To complete a particular action, multiple microservices may need to interact. Keeping synchronous calls between services can lead to a poor user experience and cause more network resources to be blocked while waiting for responses. Asynchronous connections decouple clients and services, eliminating direct dependencies and improving overall system performance. 

 

Asynchronous Architecture

 

Work Queue Pattern

In the Work Queue pattern, multiple workers are available to finish a given task. Once a task is provided, any available worker executes it. Each piece of work is independent and can be processed by separate workers. This pattern allows scaling up workers to handle the load without impacting the outcome. The caller/publisher gives the message to an individual broker, where multiple workers are waiting to act upon it. 

 

Publish and Subscribe Pattern

The Publish and Subscribe pattern differs from the Work Queue pattern. Here, the publisher publishes an event, and subscribers subscribe to it based on their responsibilities. This pattern is more event-driven rather than command-driven. Multiple tasks by multiple workers are performed when one event is raised. 

 

Asynchronous API Calls

Messaging is not the only way to achieve asynchronous communication. Asynchronous communication can also be implemented using HTTP APIs. In this pattern, the front end talks to the BFF and receives an immediate response. The BFF then communicates with downstream services and provides a callback. Once the downstream service completes its work, it uses the callback to notify the BFF, which in turn notifies the UI that the response is available.

 


Thursday, November 21, 2024

Understanding openAI

 Lets start our journey of understanding openai with some basic concepts around Machine learning.

Machine learning is subset of AI. ML is all about implement algo to make system learn. Deep learning is kind of ML, based on brain algos called Artificial neural network. GPT-4/chatGPT based on deep learning algorithm called as "Transformers".


AI - Any technique that allows a computer to mimic human behavior

ML - Ability to learn without explicit programming

Deep learning - Ability to extract patterns from data using Artificial neural networks

Transformers - is an algorithm, GPT and chatGPT are based on this

Transformer arch is based on "pays attention" model. It has 2 parts - Cross Attention and Self-Attention.


Cross Attention - > find relevance of different parts of input text to find next prediction. like I Love sunny weather -> Sunny and weather together are considered to find next word. An attention mechanism in Transformer architecture that mixes two different embedding sequences.

Self attention -> Give weightage to different words in the sentence and then figure out the meaning.The goal is to learn the dependencies between the words in the sentence and use that information to capture the internal structure of the sentence

Encoder -> process the input text, identify the valuable features and generate meaningful representations of that text (called embedding). encoders are designed to learn embeddings that can be used for various predictive modeling tasks such as classification.

Decoder -> use the embedding to produce output. To train our decoder model, we use a technique called “Teacher Forcing” in which we feed the true output/token (and not the predicted output/token) from the previous time-step as input to the current time-step.

Generative pre-trained transformers (GPT) are designed to use only decoder, and relies only on Self-Attention mechanism within decoder. There is no encoder in GPT, so no cross attention. 

GPT models, however, do not use an encoder. Instead, they are with a decoder-only architecture. This means that the input data is fed directly into the decoder without being transformed into a higher, more abstract representation by an encoder.

There is token mechanism to split the text into multiple chunks. In general 75 words is 100 tokens. These tokens are used to create context and that context is used to figure out or predict the next word. GPT-4 has context window of 8192 token and 32768 tokens. 

Based on context the new word is predicted with probability and then added into the text. The newly formed text becomes the new input to the algo again and keep repeating. 


Models - 

Models are different strategies by which the prompt will be processed. 

Instruct GPT - text-ada-001, text-babbage-001, text-curie-001 text-davinci-003 are different instruct models . Generally used for single turn task.

ChatGpt - gpt-3.5-turbo, gpt-3.5-turbo-16K. Used for chat.

GPT4 - gpt-1, gpt-4-32k.  Used for both chat and single-turn.


both chatGPT and GPT4 uses the same endpoint - openai.chatcompletion


while making the api call - 

OPENAI_API_KEY -> is api key, which is associated with your account. It is used to give you access and then charge you for the same.

Access the endpoint - 

response = openai.ChatCompletion.create(

    model="gpt-3.5-turbo",

    messages=[{"role": "user", "content": "Hello World!"}],

)

# Extract the response

print(response["choices"][0]["message"]["content"])


{

    "choices": [

        {

            "finish_reason": "stop", ---> Status of the response. stop means it got completed successfully.

            "index": 0,

            "message": {

                "content": "Hello there! How may I assist you today?", --> text generated by model. Instead of content node, there could be function_call also possible.

                "role": "assistant", --> role will always be assistant.

            },

        }

    ],

    "created": 1681134595,

    "id": "chatcmpl-73mC3tbOlMNHGci3gyy9nAxIP2vsU",   ---> technical identifier used internally by openAI

    "model": "gpt-3.5-turbo", --> model used

    "object": "chat.completion",  ---> always chat.completion

    "usage": {"completion_tokens": 10, "prompt_tokens": 11, "total_tokens": 21}, ---> token used in the call, gives yoiu idea of the cost

}


In the API 2 parameters are mandatory 

model

message  - It has role (system, user, assistant) and content (actual message)


How to use the function instead of content?

You can create a function call using openai apis, but openAI model doesnt call the function itself. It will give you the argumenst you can use to call the function.

function object has - 

name - name of the function

description - what is function is all about

parameters - parameters passed in the function


# Example function  -----> this is the function you want to call once openai respond.

def find_product(sql_query):

    # Execute query here

    results = [

        {"name": "pen", "color": "blue", "price": 1.99},

        {"name": "pen", "color": "red", "price": 1.78},

    ]

    return results

# Function definition  ----> this is the definition passed in the openai call

functions = [

    {

        "name": "find_product",

        "description": "Get a list of products from a sql query",

        "parameters": {

            "type": "object",

            "properties": {

                "sql_query": {

                    "type": "string",

                    "description": "A SQL query",

                }

            },

            "required": ["sql_query"],

        },

    }

]


# Example question

user_question = "I need the top 2 products where the price is less than 2.00"

messages = [{"role": "user", "content": user_question}]

# Call the openai.ChatCompletion endpoint with the function definition

response = openai.ChatCompletion.create(

        model="gpt-3.5-turbo-0613", messages=messages, functions=functions  -----------> you pass the function defintion here.

)

response_message = response["choices"][0]["message"]

messages.append(response_message)

the response has function_call, instead of content, which will look like this  - 

"function_call": {

        "name": "find_product",

        "arguments": '{\n  "sql_query": "SELECT * FROM products \

    WHERE price < 2.00 ORDER BY price ASC LIMIT 2"\n}',

    }


Now we can use this response and call the actual function as - 

# Call the function

function_args = json.loads(  ------> load the arguments

    response_message["function_call"]["arguments"]

)

products = find_product(function_args.get("sql_query"))   --> call the function. Please note the caller has to call the function them self, API can just return the arguments based on function definition passed.

# Append the function's response to the messages

messages.append(

    {

        "role": "function",

        "name": function_name,

        "content": json.dumps(products),       -------------> this is the output of our function call to DB.

    }

)

# Format the function's response into natural language

response = openai.ChatCompletion.create(

    model="gpt-3.5-turbo-0613",

    messages=messages,  ---> respond back to the user with the message. For this making another call to openai to get better user message

)


chat completion and text completion are 2 different things. Chat completion is more of the chat or conversation oriented response, but the text completion is more of completing the sentence, may not continue on conversation but just complete your sentence. 

In the response, insteado of getting content, we receive "text". In the request we send the prompt. 


Embedding - 

AI model is mathematical functions, and work with numeric inputs. embedding converts these words/tokens into numerical vectors. when you call the embedding api, you receive back vectors, which is array of floats.

result = openai.Embedding.create(

    model="text-embedding-ada-002", input="your text"

)

result['data']['embedding']  --> this is vector


embedding is like interpreter, that translates words and sentence into numbers. similar meaning words mapped closer together in numerical space. 


you can moderate the user input by calling the moderation api of openai. 

# Call the openai Moderation endpoint, with the text-moderation-latest model

response = openai.Moderation.create(

    model="text-moderation-latest",

    input="I want to kill my neighbor.",

)


{

    "id": "modr-7AftIJg7L5jqGIsbc7NutObH4j0Ig",

    "model": "text-moderation-004",

    "results": [

        {

            "categories": {

                "hate": false,

                "hate/threatening": false,

                "self-harm": false,

                "sexual": false,

                "sexual/minors": false,

                "violence": true,

                "violence/graphic": false,

            },

            "category_scores": {

                "hate": 0.0400671623647213,

                "hate/threatening": 3.671687863970874e-06,

                "self-harm": 1.3143378509994363e-06,

                "sexual": 5.508050548996835e-07,

                "sexual/minors": 1.1862029225540027e-07,

                "violence": 0.9461417198181152,

                "violence/graphic": 1.463699845771771e-06,

            },

            "flagged": true,

        }

    ],

}

=============================================

prompt engineering - 

Role 

Context

Task 



zero-shot-CoT strategy - 

CoT - chain of thoughts 

The term zero-shot means the model does not rely on task-specific examples to perform this reasoning; it is ready to handle new tasks based on its general training.

The few-shot learning technique gives examples of inputs with the desired outputs.

one-shot learning. As its name indicates, in this case you provide only one example to help the model execute the task.



==============


========================

Transcript - 

Slide 1- This presentation is to introduce you with the basic concepts of openai and generative ai. This covers few code examples to give you an idea of how the API is invoked. The content are created based on Oreilly book of "Deep dive into GPT-4 and chat GPT API".


Slide 2 -

Before we start on understanding openai and generative AI, lets get our terminology right. AI (Artificial intelligence) is a technique that allows computer to mimic human behaviour. It get powered by Machine learning, which is implementing the algorithm to make system learn. Within Machine learning, there is algorithm/sub-category which is called as "Deep Learning". One of the popular algorithm in Deep Learning is "Transformer". The transformer fundamental algo used to implement the GPT.


Slide 3 - Transformer works on the concept of "Pay Attention", which means focus on the different text element passed in the stream to figure out the context or meaning of the sentence. There are 2 categories in transformer to implement the pay attention-

1) Cross attention - where multiple stream or text elements are used to processed to figure out the meaning/context. 

2) Self attention - where single stream of words is used to figure out the meaning/context. In Self attention the different words in the text is given different weight-age and based on that it process the text and eventually define the meaning.

The reason we talk about this is to relate how GPT is connected with all these. 

AI -> ML -> Deep learning -> Transformer -> Self attention : GPT


Slide 4- 

Data processing is an important concept to understand when we discuss about how your text is getting interpreted by the system. System has 2 mechanism to convert data to process it well.

Encoder - The encoder is responsible to "understand" the data and create some meaningful result out of it. It can output the data after embedding. Embedding is different from encoder. Encoder is more of a brain, which understands the expectation based on our model and then give the data output which is meaningful summary of your input. 


Decoder - Decoder is a step where output is produced. This output could be produced based in pre generated encoded data combining with your input, or it could be 2 streams coming together and passed by encoder and then processed by decoder. GPT works with "decoder only" architecture. It doesn't have any concept of encoder. No wonder it is called as "Pre-Trained".

In GPT "Teacher-Forcing" technique is used to train the system. Which means in your prompt you give examples/conditions and corresponding output you would prefer. The system uses those examples to understand your expectation and then generate answer to your query. 


Slide 5- 

GPT aka Generative Pre-Trained Transformer is based on pre trained (i.e. no encoder) data transformer algorithm. Lets talk about tokens in GPT space. You will hear many times that this particular model of GPT has limit of x tokens. Tokens are used to calculate your cost. But what is the meaning of token exactly. The token is more of breaking the words/sentence into different smaller chunk and then then these chunks are fed into the processor to get the meaning out. The limit of model supporting certain number of token means - that is the window that model will have visibility to and process it. Example GPT4 is supporting almost 32K tokens, which means it will be able to understand roughly 20-25K words to figure out the meaning. If we pass anything beyond this limit, the model wont be able to process it. 

If you have bigger article/ text that you would like to process it, then you need to divide it and then make multiple trips to GPT and then process it.

Lets understand the model in GPT. Model is a kind of algorithm that will be used to process the text and respond. There are 3 categories of these models. 

1. Instruct GPT - All the models in this category are text based request/response. like text-davinci-003. These are meant for 1 ques and then 1 answer. You ask something, and it respond back with the answer, end of story. It is not meant to create context over multiple back and forth.

2. ChatGPT - This model is designed to handle conversations. It can consider your past history of conversations and derive context out of it and then generate the output. gpt-3.5-turbo is an example of chat/conversation based model.

3. GPT4 - This model is optimized and created to support both text and chat. It is advance and has better accuracy and less cost. example - gbt-4.32k. It is kind of combination of both the above models.


Slide 6 - 

Lets review the first API we have to make connection with GPT. Both chatGPT and GPT4 uses the same api endpoint, it is the model inside payload which determines what algorithm will be used to cater this request. Sample code to make a request- 

response = openai.ChatCompletion.create(

    model="gpt-3.5-turbo", --> model defines which algorithm to use to process the input.

    messages=[{"role": "user", "content": "Hello World!"}],  ---> This is where you can send the message to the api.

)

You can read the response provided by API like this - print(response["choices"][0]["message"]["content"])


However the actual response of the API looks like below - 

 "choices": [  ---> Observe the array data structure here. Which means there could be multiple choices. Why and how? I am yet to find out. But at this moment we will stick to reading the first object in this array,

        {

            "finish_reason": "stop", ---> Status of the response. stop means it got completed successfully.

            "index": 0,

            "message": {

                "content": "Hello there! How may I assist you today?", --> text generated by model. Instead of content node, there could be function_call also possible.

                "role": "assistant", --> role will always be assistant.

            },

        }

    ],

    "created": 1681134595,

    "id": "chatcmpl-73mC3tbOlMNHGci3gyy9nAxIP2vsU",   ---> technical identifier used internally by openAI

    "model": "gpt-3.5-turbo", --> model used

    "object": "chat.completion",  ---> always chat.completion

    "usage": {"completion_tokens": 10, "prompt_tokens": 11, "total_tokens": 21}, ---> token used in the call, gives you idea of the cost

}


Slide 7 - 

ChatGPT api also support a integration mechanism by which you can connect with other data source to get the information. You can use the openAI to generate certain payload based on the user query and then use that payload to fetch the results from another data source. With this pattern you require 2 openAI call, first to create the query for data source and 2nd call to format the result well, so as to display to the user. 

user query -> openAI -> result as parameters/DB query -> Use this to call DB/Service -> result -> openAI to format it in user friendly manner -> User

Please note the API itself wont execute any function for you, it will help you create arguments for you function.


Slide 8 -

How do we call openAI for function call. There are steps to follow - 

1) Define the function in your code. 

def find_product(sql_query):

    # Execute query here

    results = [

        {"name": "pen", "color": "blue", "price": 1.99},

        {"name": "pen", "color": "red", "price": 1.78},

    ]

    return results


2) Define function definition for API, which is like educating openAI about your function.

functions = [

    {

        "name": "find_product",

        "description": "Get a list of products from a sql query",

        "parameters": {

            "type": "object",

            "properties": {

                "sql_query": {

                    "type": "string",

                    "description": "A SQL query",

                }

            },

            "required": ["sql_query"],

        },

    }

]


3) call the openAI API with the function definition. Along with the userinput you will also pass the function definition, so that openAI understand that your intention is to execution function as a response, so it will respond back with the format that is usable for your code.

user_question = "I need the top 2 products where the price is less than 2.00"

messages = [{"role": "user", "content": user_question}]

# Call the openai.ChatCompletion endpoint with the function definition

response = openai.ChatCompletion.create(

        model="gpt-3.5-turbo-0613", messages=messages, functions=functions  -----------> you pass the function definition here.

)



Slide 9 - 

Once openAI has processed your request, it will respond back in the same format as before, only difference is the format or structure of the response itself. The response has arguments node, which contain the actual argument you can use to call the function itself. Now this function you can use to make another HTTP call or make DB query, but openAI wont call those itself, it will just give right information to you, which you can use to call these downstreams.


Slide 10 - 

Embedding and encoding are 2 different things. Embedding is nothing but converting the input/text into number format. As we know the AI model is mathematical and it requires numbers to work with. Hence before we pass any text to these models, we need to convert them into numbers. Converting text into number is embedding. There are APIs that are available to create embedding.


result = openai.Embedding.create(

    model="text-embedding-ada-002", input="your text"

)

result['data']['embedding']  --> this is vector



Slide 11 - 

Its important to moderate your API to avoid misuse by consumer. openAI provides you to understand user input and figure out the intention of that text. Using the moderation API call before processing any further will protect you api.

response = openai.Moderation.create(

    model="text-moderation-latest",

    input="I want to hack my office security system.",

)

Response structure - 

{

    "id": "modr-7AftIJg7L5jqGIsbc7NutObH4j0Ig",

    "model": "text-moderation-004",

    "results": [

        {

            "categories": {

                "hate": false,

                "hate/threatening": true,

                "self-harm": false,

                "sexual": false,

                "sexual/minors": false,

                "violence": false,

                "violence/graphic": false,

            },

            "category_scores": {

                "hate": 0.0400671623647213,

                "hate/threatening": 3.671687863970874e-06,

                "self-harm": 1.3143378509994363e-06,

                "sexual": 5.508050548996835e-07,

                "sexual/minors": 1.1862029225540027e-07,

                "violence": 0.9461417198181152,

                "violence/graphic": 1.463699845771771e-06,

            },

            "flagged": true,

        }

    ],

}

As you can see there are different categoies and corresponding score of those category here. you can use the score to understand the violation and give user a response back.


Thursday, December 13, 2018

Agile- Understanding Scrum Part 4(Scrum Artifacts)

In this post i am going to talk about different artifacts involved in scrum. We will talk about what these artifacts are and how these are utilized practicing scrum.

Product backlog
1) What is it – It is list of features containing short description for all functionality desired in the product. It need not to be end to end long description, instead it can be short description sufficient to create a development task. The more detailed information will evolve sprint by sprint based on user feedback.
2) Content – it contains Features, Bugs, technical work(example- environment setup) and knowledge acquisition(example – evaluate a library for use).  In general the features are listed as user story, which is written from user perspective. It is more of language like “As a user I want to ….”, with this format its easier to understand the end goal of the story.  There is not difference in feature or bug, when it’s written in user story format.
Rules - It should be visible to all who cares to see it(value transparency) .  Work at the top of the product backlog should be sized and understood by the development team and product owner both. If the product backlog is not ready, then sprint planning is cancelled.

Sprint Backlog
1) What is it – during sprint planning meeting, scrum team picks up top priority item from product backlog and moves it to sprint backlog. 1 item from product backlog can have 1 or many corresponding items in sprint backlog.
2) Content – Sprint backlog is list of tasks identified by scrum master to be completed during sprint. While picking up these items it’s important to estimate the effort as well, so that you have clear idea on how many items can be addresses in given sprint.

Burndown chart
1) What is it – Each day, estimated work examining in the sprint is calculated and graphed by scrum master, resulting in sprint burndown chart.
2) Content – Burndown chart shows more of the progress over time for the team. Horizontal sprint show sprint and vertical axis shows amount of work remaining.  Work remaining can be in any unit like story points, days or anything else. The burndown chart also helps understanding the estimation accuracy. If the progress line is coming above ideal work line, which means your work is completing slower than expected, hence you underestimated the timeline. And if you overestimate the time required, the progress will appear ahead of schedule, means below the ideal work line.

Tuesday, December 11, 2018

Agile - Understanding Scrum part -3 (Scrum Ceremonies)

Today we are going to talk about Scrum Ceremonies. These are set of meetings. We will learn about who is primary audience, what is the agenda of these meetings, and how short or long these meetings should be.

Planning meeting -
1) Attendees – It has to be attended by entire team including product owner, scrum master and the scrum team. Stakeholders and users are optional attendees.
2) Agenda – Product owner will describe the high priority features to the team. The team can ask as many questions as they want to understand the user story, so that they can translate into dev tasks and can create sprint out of it.
3) Duration - it should be time boxed to at 2 hours per week of sprint.
4) Prerequisite - Before this meeting, product owner has to have ordered product backlog, out of which scrum team can create their sprint backlog.
5) Outcome - At the end of the meeting, sprint backlog and spring goal has to be finalized. Also the it should clearly define the forecast of work in the sprint.

Daily Scrum meeting –
Objective – Objective of this meeting is to understand what  everyone in the team is doing.  Team has to answer only 3 questions what did they do yesterday, what’s their plan for today and are there any blockers for them.
Attendees – scrum team. Scrum master can facilitate this meeting, but this meeting is mainly for developer team only.
Duration – it has to be very short meeting, around 10-15 mins. This is the reason that it should be stand up call so that everyone covers it quickly.

Sprint Review
Objective – At the end of every sprint, there has to be coded, tested and usable software available for client. The objective of sprint review meeting is to showcase team’s accomplishment.  In general it is more of a demo of new features.  During the meeting product is assessed against the sprint goal determined during planning meeting.
Audience – This meeting is attended by all members and can be attended by product customers and management as well. The developers from other products can also attend this meeting.

Sprint Retrospective
Objective – Main objective of meeting is to evaluate how we as team are doing and what are improvement areas.  Identify areas for - a) What should we start doing? b) what should we stop doing? C) what should we continue doing? The ideas are taken from everyone and are voted in the last to conclude the modified practices.
Attendees – Entire team, scrum master.  Scrum master will facilitate this meeting and go around the table to ask people their ideas.
Duration – This meeting can be an hour long, as this is more of self-evaluation. Sometimes it can take longer as well, because there can be some conflicts which requires more brainstorming.


Monday, December 10, 2018

Agile - Understanding Scrum part -2 (Scrum Roles)

Today i am going to start understanding the basic terms used in scrum. I will cover more detailed concepts in upcoming posts, but want to start with introducing terms used in scrum.

Product owner
1) Key stack holder – Product owner is key stack holder of project. It could be business analyst (working closely with business and users of product) or anyone someone from Marketing or anyone with solid understanding of users and marketplace, the competition and future trends for domain. Product owner should have a clear vision on what he/she wishes to build and convey that vision very clearly to the scrum team. Product owner is key to successfully starting any agile software development project.  Product owner maintains the product backlog.
2) Does not Dictate estimates – The product owner prioritizes he product backlog during sprint planning meeting, but it is development team that selects the amount of work they believe they can do in given sprint and how many sprint will be required. Product owner never tells development team how much work they should do in given sprint or how many sprints are required.  The estimation comes from development team only.
3) Changing requirements – Requirement can change within sprint, and product owner has every right to do so, but it will never impact current sprint. The change will be taken as new task in the next sprint planning meeting and will be prioritized.
4) Required Skill set and network – Product owner should have certain skills like business or domain knowledge, good communications and connection with the team. The product owner role requires working closely with the users, stockholders across organization and the development team; hence the communication is one of the most important skillset desired in product owner.

Scrum master
1) No authority over team, but authority over process – Scrum master do not have authority over team, but has authority over process. Scrum master can tell you at end of sprint that what went right and what needs to be improved, but he/she can never dictate “how to do it”. It is all up to the team on how to do it, Scrum master will help them coming up with proper process. Moreover the team can give some more authority to scrum master, if they feel so.
2) Works as guide or trainer - Scrum master is to help team understand the process and practices of scrum. Like any exercise trainer, who will help you understand the workout, but will not do workout for you. Also, trainer will make sure you don’t skip any hard workouts and all necessary tools are with you to achieve your goals. Similarly Scrum master will help you like trainer, will help you understand process, help you remove any impediments and help you establishing a proper process around to get quality product in timely manner.
3) Do not manage people – Scrum master does not work like project manager, hence do not have direct control over people. Project manager can dictate clearly what needs to be done, but a scrum master will never give you detail on how to complete a task.

Scrum Team
1) No roles – The scrum team does not have any roles like programmer, designer, tester etc. Everyone in the team works to complete a set of task within sprint.
2) Team size – in general scrum team is of size 5-9 people. Smaller team helps having scrum meeting shorter and discussions to be quick. We can have scrum of scrum meeting for larger team where 1 person from individual team can represent their work and coordinate with multiple other scrum teams. 

Thursday, December 6, 2018

Agile - Understanding Scrum part -1(Introduction)


Introduction

Scrum is a framework for developing complex products and systems. It is grounded in empirical processs control theory. Scrum employs an iterative, incremental approach to optimize predictability and control risk. - Ken Schwaber

What is framework? - A framework is an incomplete structure which accommodates other practices, techniques and tools while providing an overarching process.
What is methodology - A complete set of prescribed and interrelated principles, tools and practices working together to achieve a particular goal.

Scrum is a framework. This is the reason that scrum can co-exist cleanly and even support other development methodologies and techniques. Extreme programming, KANBAN work really well using conjunction with Scrum.

Scrum is Empirical. Which means it doesn't have predefined steps, instead it works on feedback loop, continuously improvising the process. It is absolutely needed when we don't know the exact expected outcome at the time we being. This kind of feedback loop help us taking shorter steps, and improvise with feedback. It tell you fail, and fail fast, so that you can take corrective measures and move ahead.

Scrum is iterative - These are the steps followed in any product delivery - Plan -> Analysis -> Develop -> Test -> Integrate -> Validate -> Deploy. Scrum says, instead of doing these steps once , do it many times with smaller deployment and releases and reiterate it over and over again.

Scrum is for Complex work - Scrum is not meant for simple or even complicated work, it is meant for complex work. Here is the complexity illustrated by professor Ralph Stacy -























Scrum talks about Product, instead of Project - Software development should align with product, which is more usable software. instead of delivering a big project, focus should be to deliver smaller patches of product, which can be used by the consumers.

Scrum is Iterative and incremental agile software development framework for managing product development. It defines “flexible, holistic product development strategy where dev team works together as single unit to achieve common objective”.

In scrum instead of providing complete detailed description, it is left up to dev team to figure out. Scrum relies on self-organizing(no leader), cross functional team.

Overview – 

Scrum is agile process used for product development. It is project management framework to achieve aggressive deadlines and complex requirements. In scrum projects move forward by series of iterations called sprints. Sprint is generally 2-4 weeks length.

The scrum is not just about changing development approach, it is also about behavior changes. It talks about certain key values that everyone in the team should respect. These values are -
Respect - Always respect everyone in the team. Respect their decision and their point of view.
Trust - The trust is something earned over time, trust your team and build trust with them.
Commitment - Always be committed to you tasks, because if you fail, the entire team fails.
Focus - Be focus on your items.
Openness - Always share your progress, thoughts and decision with all, nothing to hide from anyone.

These value can be understood with following practices in scrum -
Because we value respect we will keep chit-chat outside of daily Scrum meeting.
Because we value trust we will only show done Features at Sprint Review.
Because we value commitment we will turn up on time.
Because we value focus we will not interrupt someone with headphones on unless absolutely necessary.
Because we value openness we will post these decisions on the wall for all to read.

One of the very important concept in Scrum is Time Boxing. Scrum clearly says that every event and activity has to be time boxed. Hence we have a concept of Sprint, which gives us a container to keep all the artifacts of Scrum together and in time boxed manner. 

Time Boxing -
Any event should have maximum duration (not minimum) in scrum. This means if a meeting is supposed to be an hour, than we have to wrap it up in an hour, no extension.  It actually provides us a container to self-organize our self and collaborate more in the meeting, which helps individual to focus more on priority items and eliminate distraction.

Sprint -
Sprint is a time boxed event of scrum. It is limited to 30 days or less. Limiting duration help us reduce the risk because we get to know the feasibility of any given task within that amount of time. Also it help helps developers to be more focused.
It is container of all other events of scrum. Product owner can cancel the sprint if he/she wants. Sprint is inviolable, which means non planned work will never be included in current sprint. If there are more high priority items come up, product owner can list it for next sprint.

Let's try to understand different items kept in sprint-
1) Roles – Product owner, scrum master, team
2) Ceremonies – sprint planning meeting, sprint review, sprint retrospective meeting, Daily Scrum meeting
3) Artifacts – product backlog, sprint backlog, burndown chart

Roles
Product owner – project key stackholder and represents users for whom we are building this product. Product owner has to have a deep knowledge of business requirement. 
Scrum Master – SM is responsible for making sure the team is as productive as possible. SM is responsible to building the scrum process in the team by removing impediments to progress, protecting team from outside distractions. 
Scrum team – Typical scrum team is of size 5-9. There is no team lead, designer, tester etc. instead the entire team work towards the common goal as a whole.

Ceremonies -
Sprint planning meeting – At start of each sprint a sprint planning meeting is held, during which the product owner presents top items on the product backlog to the team, the Scrum team selects what they can complete during the coming sprint. Then that selected work is moved from product backlog to sprint backlog. 
Sprint review meeting – At the end of each sprint, the team demonstrates what they accomplished during sprint in the review meeting. This is more of demo to the business owner to showcase the product at end of sprint. This should not be very long for dev team.
Sprint Retrospective -  This is the meeting where scrum master, product owner and team meets and find what’s working and what’s not. They discuss and come up with the new approaches if the process requires any improvement. 
Daily Scrum Meeting- Each day during sprint, the entire team meets (at start of day) and cover 3 areas – what I did achieve yesterday, what do I plan to achieve today and if there is anything blocking me. It is more of stand up so that the updates and discussion are not lengthy.

Artifacts
Product backlog – product backlog is prioritized list of features, or changes in features. 
Sprint backlog – sprint backlog is list of features/task that team wants to complete within that sprint. 
Burndown chart – The team tracks its progress against release on burn down chart. The chart is updated at end of each sprint by scrum master. 

Scrum Flow - 



Thursday, October 12, 2017

Interface and Abstract class in c#

Interfaces is very general concept of object oriented programming. Here are few fundamentals rules associated with interfaces in c# -

- Interfaces can contain methods, properties, events, indexers, or any combination of those four member types.
- An interface can't contain constants, fields, operators, instance constructors, finalizers, or types.
- Interface members are automatically public, and they can't include any access modifiers. Members also can't be static.
- Interfaces can implement other interfaces.
- A class might include an interface multiple times through base classes that it inherits or through interfaces that other interfaces implement. However, the class can provide an implementation of an interface only one time and only if the class declares the interface as part of the definition of the class (class ClassName : InterfaceName). If the interface is inherited because you inherited a base class that implements the interface, the base class provides the implementation of the members of the interface. However, the derived class can reimplement the interface members instead of using the inherited implementation.

Abstract Class -
Abstract class is class which has atleast 1 abstract method. Abstract class can inherit from non abstract class. When an abstract class inherits a virtual method from a base class, the abstract class can override the virtual method with an abstract method.
public class D
{
    public virtual void DoWork(int i)
    {
        // Original implementation.
    }
}

public abstract class E : D
{
    public abstract override void DoWork(int i);
}

public class F : E
{
    public override void DoWork(int i)
    {
        // New implementation.
    }
}
If a virtual method is declared abstract, it is still virtual to any class inheriting from the abstract class. A class inheriting an abstract method cannot access the original implementation of the method—in the previous example, DoWork on class F cannot call DoWork on class D. In this way, an abstract class can force derived classes to provide new method implementations for virtual methods.

Sealed Class:-
A sealed class cannot be used as a base class. For this reason, it cannot also be an abstract class. Sealed classes prevent derivation. Because they can never be used as a base class, some run-time optimizations can make calling sealed class members slightly faster.
A method, indexer, property, or event, on a derived class that is overriding a virtual member of the base class can declare that member as sealed. This negates the virtual aspect of the member for any further derived class. This is accomplished by putting the sealed keyword before the override keyword in the class member declaration.
The sealed keyword enables you to prevent the inheritance of a class or certain class members that were previously marked virtual.

Multithreading concept in c#

Difference in keyword used -

Concurrent
several thhings going in parallel
several things happening at once
might or might not be mutithread

Mutithreading
uses OS capabuility to porcess multiple operations
Multiple execution context
more than 1 thread, might or might not be concurrent

Parallel
multi simultaneous computations
more on hardware level -
multi core CPU - multiple processing at once

Asynchronous
not having to wait

Context Switch -
It is OS level concept. When the thread/process are executing any code and CPU needs to execute some other instruction, then it stores the state of current thread like register state and all in memory and store the other thread.
Ref - http://www.linfo.org/context_switch.html

Process, Thread and Apartment
Ref - https://msdn.microsoft.com/library/windows/desktop/ms693344.aspx

An application domain forms an isolation boundary for security, versioning, reliability, and unloading of managed code. A thread is the operating system construct used by the common language runtime to execute code. At run time, all managed code is loaded into an application domain and is run by one or more managed threads.
There is not a one-to-one correlation between application domains and threads. Several threads can execute in a single application domain at any given time, and a particular thread is not confined to a single application domain. That is, threads are free to cross application domain boundaries; a new thread is not created for each application domain.

Understanding STA & MTA-
The COM threading model is called an "apartment" model, where the execution context of initialized COM objects is associated with either a single thread (Single Thread Apartment) or many threads (Multi Thread Apartment). In this model, a COM object, once initialized in an apartment, is part of that apartment for the duration of its runtime.

The STA model is used for COM objects that are not thread safe. That means they do not handle their own synchronization. A common use of this is a UI component. So if another thread needs to interact with the object (such as pushing a button in a form) then the message is marshalled onto the STA thread. The windows forms message pumping system is an example of this.

If the COM object can handle its own synchronization then the MTA model can be used where multiple threads are allowed to interact with the object without marshalled calls.

"var" keyword in c#

REF - https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/var

"var" keyword is given by c# to declare a variable. It can help us avoid writing "type" on LHS of the expression. even though we are not writing type before the variable name, but it does not mean that it doesnt have a type. compiler defines the type by evaluating the RHS of the expression. It is more a implicit type definition.

"var" can not be used at class level to define the fields. if you refer this article -
 https://blogs.msdn.microsoft.com/ericlippert/2009/01/26/why-no-var-on-fields/
It states about compilation process of c# compiler.
First we run through every source file and do a "top level only" parse. That is, we identify every namespace, class, struct, enum, interface, and delegate type declaration at all levels of nesting. We parse all field declarations, method declarations, and so on. In fact, we parse everything except method bodies; those, we skip and come back to them later.
Once we've done that first pass we have enough information to do a full static analysis to determine the type of everything that is not in a method body. We make sure that inheritance hierarchies are acyclic and whatnot. Only once everything is known to be in a consistent, valid state do we then attempt to parse and analyze method bodies. We can then do so with confidence because we know that the type of everything the method might access is well known.
There's a subtlety there. The field declarations have two parts: the type declaration and the initializer. The type declaration that associates a type with the name of the field is analyzed during the initial top-level analysis so that we know the type of every field before method bodies are analyzed. But the initialization is actually treated as part of the constructor; we pretend that the initializations are lines that come before the first line of the appropriate constructor.
So immediately we have one problem; if we have "var" fields then the type of the field cannot be determined until the expression is analyzed, and that happens after we already need to know the type of the field.

Here are the rules with "var" keyword -
- "var" can only be used when a local variable is declared and initialized in the same statement; the variable cannot be initialized to null, or to a method group or an anonymous function.
- "var" cannot be used on fields at class scope.
- Variables declared by using "var" cannot be used in the initialization expression. In other words, this expression is legal: int i = (i = 20); but this expression produces a compile-time error: var i = (i = 20);
- Multiple implicitly-typed variables cannot be initialized in the same statement.
- If a type named "var" is in scope, then the var keyword will resolve to that type name and will not be treated as part of an implicitly typed local variable declaration.

Extension Methods in C#

Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type.
The most common extension methods are the LINQ standard query operators that add query functionality to the existing System.Collections.IEnumerable and System.Collections.Generic.IEnumerable types

Example -
namespace ExtensionMethods
{
    public static class MyExtensions
    {
        public static int WordCount(this String str)
        {
            return str.Split(new char[] { ' ', '.', '?' },
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }
}

In above code we invoke the extension method with instance method syntax. However, the intermediate language (IL) generated by the compiler translates our code into a call on the static method.Extension methods cannot access private variables in the type they are extending.

You can use extension methods to extend a class or interface, but not to override them. An extension method with the same name and signature as an interface or class method will never be called. At compile time, extension methods always have lower priority than instance methods defined in the type itself. In other words, if a type has a method named Process(int i), and you have an extension method with the same signature, the compiler will always bind to the instance method. When the compiler encounters a method invocation, it first looks for a match in the type's instance methods. If no match is found, it will search for any extension methods that are defined for the type, and bind to the first extension method that it finds.

ref: -https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

Saturday, April 22, 2017

Angular 2 - Fundamentals

This is very first post in the series of Angular 2 learning. In this post i am going to cover the basic concept of Angular 2. We will start with very basic fundamentals and will evolve Angular 2 slowly.

TYPE SCRIPT -
Angular 2 is written in Typescript, but it is not mandatory to use typescript if you want to build application in Angular 2. The biggest benefit of using Typescript is "Type".
As we know javascript is not type safe, hence refactoring/managing an application is pretty tedious. with Typescript we get type safety. There is typescript compiler(or transpiler) available which will convert your typescript into a javascript file.
So Typescript is only for compile time. Once your code is transpile, you get javascript as a output which is used by the application.

Please note every javascript is a typescript, hence Typescript is a superset of javascript. you can always copy your entire javascript code into typescript file and compile it.
Typescript also support "Interface" and we all know importance of interfaces in java/c#.

Components -
I am sure from various resource you must have seen that Angular 2 is component based framework. let's understand what does it mean.

Angular 2 components are evolved from the idea of webcomponent. The concept of webcomponent is to create resuable UI widgets. Using web-component you can visualize the app as a chunk of DOM elements, rather than a one single large page. The idea here is to compose the unit of functionality in a component, and reuse it across. This also means the CSS of this element will be limited to the component only.
In the webcomponent the HTML is hidden in form of Shadow DOM.

Shadow DOM -
Shadow DOM concept came while implementing web components. Shadow DOM is the part of the DOM, in hidden state.which means you are creating an HTML element, and innerHTML of that element is hidden( of course chrome gives you option by which you can see it). but as webcomponent talks about composition, the HTML and CSS are composed in the component and are understood by browser in form of shadow DOM.
With this architecture, all the css and functionality is very much encapsulated from the rest of the DOM. Ofcourse, javascript is not part of the shadow.

It is not actually directly part of the DOM, but its subtree which is connected with the DOM via rootNode. This also give an opportunity to browser to optimize the DOM manipulation. Because once there are changes in the Shadow DOM, browser need not to refresh the entire DOM.

Does it means the Angular component are drawn in shadow DOM? Nope.  Web component and shadow DOM are new concepts and not all browser supports it, so Angular 2 gives us a chance to configure our app according to our need.


Component in Angular 2 -
For every component in Angular 2 you can define the state as -
None - All elements are draws normally, no shadow DOM concept.
Emulated - its in between of None and Native, Of course the DOM will be visible, but CSS will be scoped within the component and the root node will get some kind of proxy id associted. This is default.
Native - Shadow DOM is completly enabled.
Example - screenshot below compares these 3 scenarios -



How do we use API -
@Component({
  selector: '..',
  templateUrl: '..',
  styleUrls: ['..'],
  encapsulation: ViewEncapsulation.None
})

Components vs Directives -
Directive add behavior to the DOM element, whereas component creates its own view with its behavior.
Component is generally used to create UI widgets, it is a directive with a view..

Thursday, August 18, 2016

ReactJS - Getting Started -2

In my previous post we discussed on creating a todo app and we have creates a list of todo where we passed data. Now let’s enhance the same todo app and see if we can add “edit” button. So we are going to make the list of todo as read only and once user click on edit button, the list should be editable.
By this example we will cover on how we can make different communicate with each other.
Initialization of app will not have any changes as such –
var _todos = [{id: 1, text: "This is one comment"},{id: 2, text: "This is *another* comment"}];
ReactDOM.render(,document.getElementById('todo'));
As there are 2 modes, editable and non editable, we will maintain a state to begin with.
Also we need to have a click handler for our edit button. In React, the data flows unidirectional and it is recommended to implement on the same line. In our code, todolist and edit button are 2 components loaded at same level(there is no parent child relation) so if we want to make communication between these components. We need to pass a handler from parent to child button. Once button is pressed, it will notify parent about this, and then parent can communicate this to child components via state change.
Edit button –
var EditButton = React.createClass({
    render:function(){
        return();
    }});
We created a html button and we have a prop associated with it – “onClick”. If you see carefully we have passed the handler in props from parent.so on click of the button we will be executing the handler passed.
TodoApp –
In toDoApp component, we modified the render function and have introduced “EditButton”. Also we introduced 2 functions – getInitialState and handleEdit.
getInitialState is function which sets the initial state of the component. We are require to put the default value of state that we are planning to use (else component will throw error).
handleEdit – this is the function we introduced so that we can handle the click of edit button in the parent. In this function we just modify the state of the component. Once the component’s state is modified, react will call the render function of component with new state. If we see that any child component need not to refresh, then we will have to explicitly stop its rendering.
var TodoApp = React.createClass({
    getInitialState: function() {
        return {
            editview: false            //by default read only view
        };
    },
    handleEdit:function(){
        this.setState({
            editview: true    // on click of edit, change state to editable.
        });      
    },
    render: function () {
        return (
           
                           

               
               
           
        );
}});
If you see above, we passed another prop as “editable” to ToDoList, which will make use this prop to set todo as editable or not.
There is not much change in the ToDoList, we are just passing new prop to Todo component.
var TodoList = React.createClass({  
    render: function(){
        var todos  = this.props.todos;
        var editable = this.props.editable;
        var todoNodes = todos.map(function(todo){return ();}            
    );
    return (
{todoNodes}
);
    }
});
In Todo component, we are just consuming this new field from prop and making the input as disable/enable.
var Todo = React.createClass({
    render: function(){
        var todo = this.props.current;
        var edit = this.props.edit === true;              
        if(!edit){
            return();      
        }
        return();      
    }});