# AI Open Source Capstone class ## Unit 5: Software Architecture Design A key human role in software development is the ability to take a feature or a product, and design the software architecture. For example, last week, we added a voice AI feature to the ChatBox project. We created a system design document, but we didn't discuss how to evaluate if AI did a good job. - Note: the classic "system design" interview tends to focus on how to scale systems using techniques like load balancers, caching, sharding, etc. - Software architecture design is part of the code review process In this session, we will introduce a workflow for designing the architecture of a feature, and a framework for evaluating the architecture. ## Case Study: A voice AI for student support System and architectural design can be done in two phases: functionality and performance at scale. ## Functionality ### Step 1: Explore functional requirements A typical idea can start as high-level as a "Voice AI for student support". Our first mission is to explore the functional requirements, and unpack more about what we mean about this idea. This is the first step in both system design as well as architectural design. **Try it out**: > I want to build a Voice AI for student support. Each student is working on a different open source projects, with pre-assigned issues. The Voice AI can consult a bank of answers or common issues, and help gather information for a human expert. > > I'm creating the system and architectural design, and I want to start by fleshing out the functional requirements. Help guide me through that. ### Step 2: Map out user scenarios Now that you have a high level understanding of the functional requirements, it's useful to be more specific and concrete about user scenarios. A user scenario poses a more concrete sequence of events. An example user scenario might be: 1. A user starts a voice chat with the AI 2. User reports the problem that they are struggling with 3. AI fetches relevant student context (their GitHub username, their current project, and current FAQs) 4. AI asks clarifying questions 5. Student gives more details about their situation 6. AI leverages the current FAQs to respond to the student **Try it out**: Copy the example to AI above, and ask it: > Use the functional requirements, and build a set of representative user scenarios, similar to the one above. ### Step 3: Mapping components / services Once we have a few user scenarios, we're ready to start dividing it up into components and services. A component is a primary logical actor in the system, whereas a service is a re-usable and supporting role that, as the name implies, provides a service. Start by looking at the user scenarios, and looking at how where we should draw the dividing lines between different components. **Try it out**: > Based on the functional requirements and user scenarios, propose components and services. **Evaluation**: Evaluate the design of components and services using the following principles. 1. **Separation of Concerns** is perhaps the most fundamental principle. Each component should handle one specific aspect of functionality. Your data access layer shouldn't know about UI rendering, your business logic shouldn't be mixed with HTTP handling, and your authentication code shouldn't be scattered throughout the application. This separation makes code easier to understand, test, and modify. 2. **Single Responsibility Principle (SRP)** applies at every level - classes, modules, and services should have one reason to change. A UserService should handle user operations, not also send emails and generate reports. When responsibilities are mixed, changes become risky and testing becomes complex. ### Step 4: Designing interfaces for components / services In order to accomplish the user scenario, there's usually some entry point that instantiates the required components. Components interact with other components and services via an interface (i.e., a set of functions). **Try it out:** > For the components and services above, map out the interfaces. **Evaluation**: Evaluate the interfaces using the following principles. 1. **Encapsulation/Information Hiding** conceals implementation details behind stable interfaces. Other components shouldn't know whether you're using a list or a tree internally, just that they can add and retrieve items. This freedom to change internals without affecting clients is crucial for system evolution. 2. **Principle of Least Astonishment** means components should behave as developers expect. A method called saveUser should save a user, not also send an email. Consistent naming, predictable behavior, and following established conventions reduce cognitive load. ### Step 5: Diagram data and control flow Bring it all together by confirming that your components and interfaces can accomplish your user scenarios. **Try it out**: > Anchor on the user scenarios and create a data and control flow mermaid diagram that shows the interactions of the components, services, and interfaces ### Step 6: Define schema Most products/features will require storing into a database. In order to design your schema, it's useful to look at: 1. What are the views in your app? That view generally corresponds to a table or set of tables. 2. What are your API calls? That usually reads and writes to a schema. **Try it out**: > Define the schema of this architecture. ## Performance ### Step 1: Explore non-functional requirements Some people will explore the non-functional requirements earlier, but this often relates to measurements like: latency, reliability, throughput and scalability. **Try it out**: > Help me explore the non-functional requirements of this feature ### Step 2: Identify bottlenecks to latency or scale In order to make things faster, or work for a million users, there's always a resource that runs out first (network, disk, memory, etc). **Try it out**: > Identify the bottlenecks to latency or scale for the non-funtional requirements. For each bottleneck, review options for relieving the bottleneck. ### Step 3: Plan for redundancy or failures For production systems, you have to plan for failure and redundancy. **Try it out**: > Explore the plan for redundancy or failures