├── .gitignore ├── Architecture.md ├── Asynchrony_and_Concurrency_Python.md ├── NoSQL.md ├── OOP.md ├── Python_General.md ├── Queues.md ├── README.md ├── SQL.md └── Testing.md /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode 2 | ./.idea 3 | **/.DS_Store 4 | ./.gitignore 5 | 6 | **/__pycache__ 7 | **/.pytest_cache 8 | **/.idea 9 | 10 | .env 11 | .env.prod 12 | .env.dev 13 | 14 | /venv -------------------------------------------------------------------------------- /Architecture.md: -------------------------------------------------------------------------------- 1 | # Architecture 2 | 3 | During interviews with senior developers, a separate interview is allocated to test the skill of an architect. In the case of a middle developer, this block may not exist. 4 | 5 | If it does get included in the interview program, it might be limited to a couple of questions about your experience and case studies, such as why you chose that particular architecture in a particular case. It may seem that the interviewer thinks your solution is not the best, but it is not. The interviewer needs to understand how you made the decision. If the choice of architecture and solution was not made by you, feel free to say so. 6 | 7 | It is equally important to understand the basic postulates of the architecture: extensibility, scalability, fault tolerance. Look at sample questions: 8 | 9 | - You have your own online cinema. How to implement the functionality of email-sending to users? 10 | - How can a service or database be scaled? 11 | - Tell me what is balancing? What balancing algorithms do you know? 12 | - If you were making an online movie theater, how would you implement video uploads? How would a video player work? -------------------------------------------------------------------------------- /Asynchrony_and_Concurrency_Python.md: -------------------------------------------------------------------------------- 1 | # Asynchrony and Concurrency in Python 2 | 3 | ### 🔶 1. What is GIL? What is it for? 4 | 5 | --- 6 | #### Answer: 7 | GIL (Global Interpreter Lock) is a mechanism used in the CPython implementation of Python to prevent multiple native threads from executing Python bytecodes at once. This lock is necessary because CPython's memory management is not thread-safe. GIL ensures that only one thread executes Python bytecode at a time, avoiding conflicts between threads over the Python interpreter's memory. 8 | 9 | ### Example: 10 | ```python 11 | import threading 12 | 13 | def my_func(): 14 | x = 0 15 | for i in range(1000000): 16 | x += 1 17 | 18 | # create 2 threads 19 | t1 = threading.Thread(target=my_func) 20 | t2 = threading.Thread(target=my_func) 21 | 22 | # start the threads 23 | t1.start() 24 | t2.start() 25 | ``` 26 | In this example, even though we have two threads running the same function, GIL will not allow them to run simultaneously, so the overall execution time will be similar to running the function only once on a single thread. 27 | ### 🔶 2. How is a thread different from a process? 28 | 29 | --- 30 | #### Answer: 31 | A thread is a lightweight, independent unit of execution that can run within a process. Threads within a process share the same memory space, making it easy for them to share data and communicate with each other. A process, on the other hand, is a self-contained execution environment that has its own memory space and resources. 32 | 33 | ### 🔶 3. Tell us about the race condition and thread safety. 34 | 35 | --- 36 | #### Answer: 37 | A race condition occurs when multiple threads access shared data or resources simultaneously, and the outcome of the program depends on the order in which the threads execute. Thread safety is the property of an application or library that it can handle multiple threads accessing shared data or resources without introducing race conditions. 38 | 39 | #### Example: 40 | ```python 41 | import threading 42 | 43 | x = 0 44 | 45 | def increment(): 46 | global x 47 | for i in range(1000000): 48 | x += 1 49 | 50 | def decrement(): 51 | global x 52 | for i in range(1000000): 53 | x -= 1 54 | 55 | # create 2 threads 56 | t1 = threading.Thread(target=increment) 57 | t2 = threading.Thread(target=decrement) 58 | 59 | # start the threads 60 | t1.start() 61 | t2.start() 62 | 63 | # wait for the threads to finish 64 | t1.join() 65 | t2.join() 66 | 67 | print(x) 68 | ``` 69 | In this example, we have two threads running simultaneously that increment and decrement a shared variable x. The final value of x will depend on the order in which the threads execute, which can lead to race conditions. 70 | 71 | ### 🔶 4. What mechanisms for synchronizing access to shared resources do you know? 72 | 73 | --- 74 | #### Answer: 75 | Some mechanisms for synchronizing access to shared resources include: 76 | 77 | - Locks: a mechanism that allows only one thread to execute a critical section of code at a time. 78 | - Semaphores: a mechanism that allows multiple threads to access a shared resource, but with a limit on the number of threads that can access the resource at the same time. 79 | - Monitors: a mechanism that allows only one thread to execute a critical section of code at a time, and also provides a mechanism for threads to wait for specific conditions to be met before continuing execution. 80 | 81 | #### Example: 82 | ```python 83 | import threading 84 | 85 | # Using locks 86 | x = 0 87 | lock = threading.Lock() 88 | 89 | def increment(): 90 | global x 91 | with lock: 92 | for i in range(1000000): 93 | x += 1 94 | 95 | def decrement(): 96 | global x 97 | with lock: 98 | for i in range(1000000): 99 | x -= 1 100 | 101 | # Using semaphores 102 | semaphore = threading.Semaphore(1) 103 | 104 | def increment(): 105 | global x 106 | semaphore.acquire() 107 | for i in range(1000000): 108 | x += 1 109 | semaphore.release() 110 | 111 | def decrement(): 112 | global x 113 | semaphore.acquire() 114 | for i in range(1000000): 115 | x -= 1 116 | semaphore.release() 117 | ``` 118 | In this example, we use locks and semaphores to synchronize access to the shared variable x, making sure that only one thread can access the variable at a time, avoiding race conditions. 119 | 120 | ### 🔶 5. What mechanisms of interaction of processes do you know? 121 | 122 | --- 123 | #### Answer: 124 | Some mechanisms of interaction of processes include: 125 | - Inter-process communication (IPC) mechanisms such as pipes, sockets, and message queues 126 | - Signals, which are used to send simple notifications between processes 127 | - Shared memory, which allows processes to directly access the same memory space. 128 | 129 | ### 🔶 6. What is asynchronous I/O? 130 | 131 | --- 132 | #### Answer: 133 | Asynchronous I/O is a method of input/output operations in which the process does not wait for the I/O operation to complete before continuing execution. This allows for more efficient use of system resources, as the process can perform other tasks while the I/O operation is in progress. 134 | 135 | #### Example: 136 | ```python 137 | import asyncio 138 | 139 | async def read_file(): 140 | # Open the file in non-blocking mode 141 | file = open("file.txt", "r", buffering=0) 142 | # Read the first line of the file 143 | line = await file.readline() 144 | print(line) 145 | file.close() 146 | 147 | async def main(): 148 | await read_file() 149 | 150 | asyncio.run(main()) 151 | ``` 152 | In this example, the await file.readline() is an asynchronous I/O operation that reads the first line of the file, the program does not wait for the operation to finish, it can execute the next line while it is reading the file. 153 | 154 | ### 🔶 7. What are coroutines? How do they work? 155 | 156 | --- 157 | #### Answer: 158 | Coroutines are a type of lightweight, cooperative threads that allow for concurrency without the need for multiple threads. Coroutines can yield control to other coroutines, allowing them to execute, and then resume execution later. They are implemented using the "yield" keyword and are similar to generators, but with more features for concurrency. 159 | 160 | #### Example: 161 | ```python 162 | import asyncio 163 | 164 | async def my_coroutine(): 165 | print("Starting coroutine") 166 | await asyncio.sleep(1) 167 | print("Ending coroutine") 168 | 169 | async def main(): 170 | await my_coroutine() 171 | 172 | asyncio.run(main()) 173 | ``` 174 | In this example, my_coroutine() is a coroutine that uses the await asyncio.sleep(1) to simulate a delay of one second. The await keyword is used to allow other coroutines to run while this coroutine is paused. 175 | 176 | ### 🔶 8. What is the use of the async/await construct in Python? 177 | 178 | --- 179 | #### Answer: 180 | The async/await construct in Python is used to write asynchronous code in a synchronous-like fashion. The "async" keyword is used to define an asynchronous function and the "await" keyword is used to call other asynchronous functions from within an asynchronous function. 181 | 182 | ### 🔶 9. How is the EventLoop arranged? 183 | 184 | --- 185 | #### Answer: 186 | An EventLoop is a mechanism that allows for the scheduling and execution of asynchronous code. It runs in a single thread and manages the execution of tasks, such as I/O operations, by scheduling them to be executed as soon as their resources become available. EventLoop is an essential part of asyncio library which provides an abstract event-driven asynchronous I/O framework. 187 | 188 | #### Example: 189 | ```python 190 | import asyncio 191 | 192 | async def my_task(): 193 | print("Starting task") 194 | await asyncio.sleep(1) 195 | print("Ending task") 196 | 197 | async def main(): 198 | # Create an event loop 199 | loop = asyncio.get_event_loop() 200 | # Schedule the task using the loop 201 | loop.create_task(my_task()) 202 | # Run the loop 203 | loop.run_forever() 204 | 205 | asyncio.run(main()) 206 | ``` 207 | In this example, we create an event loop using asyncio.get_event_loop() and schedule a task using loop.create_task(my_task()). The event loop is then run using loop.run_forever() which schedules and runs the task as soon as resources become available. 208 | 209 | ### 🔶 10. What is the purpose of the async with statement in Python? Provide an example? 210 | 211 | --- 212 | #### Answer 213 | The async with statement is used for managing resources in an asynchronous context, similar to the regular with statement for synchronous code. It's commonly used for working with asynchronous I/O resources that need to be acquired and released safely. 214 | 215 | #### Example: 216 | ```python 217 | import asyncio 218 | 219 | class AsyncResource: 220 | async def __aenter__(self): 221 | print("Acquiring resource asynchronously") 222 | await asyncio.sleep(1) 223 | return self 224 | 225 | async def __aexit__(self, exc_type, exc_val, exc_tb): 226 | print("Releasing resource asynchronously") 227 | 228 | async def main(): 229 | async with AsyncResource() as resource: 230 | print("Using async resource") 231 | 232 | if __name__ == "__main__": 233 | asyncio.run(main()) 234 | ``` 235 | 236 | ### Back to top ⬆️ 237 | -------------------------------------------------------------------------------- /NoSQL.md: -------------------------------------------------------------------------------- 1 | # NoSQL 2 | 3 | ### 🔶 1. What is NoSQL? 4 | 5 | --- 6 | #### Answer: 7 | NoSQL stands for "Not Only SQL" and refers to a type of database management system that is designed to handle large amounts of unstructured or semi-structured data. It does not rely on the traditional table-based relational model and typically does not use SQL as the query language. 8 | ### 🔶 2. What are some examples of NoSQL databases? 9 | 10 | --- 11 | #### Answer: 12 | MongoDB, Cassandra, Redis, and Couchbase are some examples of popular NoSQL databases. 13 | ### 🔶 3. What is the main difference between NoSQL and SQL databases? 14 | 15 | --- 16 | #### Answer: 17 | SQL databases are based on the relational model and rely on a fixed schema, while NoSQL databases are more flexible and do not have a fixed schema. SQL databases use SQL as the query language, while NoSQL databases may use different query languages. SQL databases are better suited for structured data, while NoSQL databases are better suited for unstructured or semi-structured data. 18 | ### 🔶 4. What is a document-based NoSQL database? 19 | 20 | --- 21 | #### Answer: 22 | A document-based NoSQL database stores data in the form of documents, such as JSON or BSON, instead of tables. Each document contains a set of fields, similar to columns in a table, and can have a nested structure. MongoDB is an example of a document-based NoSQL database. 23 | ### 🔶 5. What are the advantages of using a NoSQL database? 24 | 25 | --- 26 | #### Answer: 27 | NoSQL databases are highly scalable and can handle large amounts of data. They are also designed to be highly available and can be distributed across multiple servers. NoSQL databases also have a more flexible schema, which allows for easier data modeling and faster development. 28 | ### 🔶 6. What are the disadvantages of using a NoSQL database? 29 | 30 | --- 31 | #### Answer: 32 | NoSQL databases may lack some of the advanced features of SQL databases, such as support for complex queries and transactions. They may also have less mature ecosystem and tooling. 33 | ### 🔶 7. How would you design a NoSQL database for a social media application? 34 | 35 | --- 36 | #### Answer: 37 | For a social media application, a NoSQL database such as MongoDB would be suitable because it can handle large amounts of unstructured data, such as user profiles and posts. The data model would likely include collections for users, posts, comments, and likes. Indexes could be created on fields such as the user's name, the post's timestamp, and the comment's timestamp to improve the performance of queries 38 | 39 | ### Back to top ⬆️ 40 | -------------------------------------------------------------------------------- /OOP.md: -------------------------------------------------------------------------------- 1 | # OOP 2 | 3 | ### 🔶 1. Explain the basic principles of OOP. 4 | 5 | --- 6 | #### Answer: 7 | Object-oriented programming (OOP) is a programming paradigm that uses objects, which are instances of classes, to represent and manipulate data. The basic principles of OOP include encapsulation, inheritance, and polymorphism. 8 | ### 🔶 2. Are you familiar with SOLID? Look at the code, are there any SOLID principles violated here? How can this be fixed? 9 | 10 | --- 11 | #### Answer: 12 | SOLID is a set of five principles for object-oriented software design, which stands for Single responsibility, Open-closed, Liskov substitution, Interface segregation, and Dependency Inversion. 13 | 14 | ### Example: 15 | ```python 16 | class Dog: 17 | def __init__(self, name, breed): 18 | self.name = name 19 | self.breed = breed 20 | def bark(self): 21 | print("Woof!") 22 | def fetch(self): 23 | print("Fetching...") 24 | def playDead(self): 25 | print("Playing dead...") 26 | def rollOver(self): 27 | print("Rolling over...") 28 | def chaseTail(self): 29 | print("Chasing tail...") 30 | 31 | # This class violates the Single Responsibility Principle as it has too many methods which are doing different tasks. 32 | ``` 33 | It can be fixed by splitting the class into multiple classes each with a single responsibility 34 | 35 | ```python 36 | class Dog: 37 | def __init__(self, name, breed): 38 | self.name = name 39 | self.breed = breed 40 | def bark(self): 41 | print("Woof!") 42 | 43 | class Tricks: 44 | def fetch(self): 45 | print("Fetching...") 46 | def playDead(self): 47 | print("Playing dead...") 48 | def rollOver(self): 49 | print("Rolling over...") 50 | def chaseTail(self): 51 | print("Chasing tail...") 52 | 53 | ``` 54 | ### 🔶 3. What OOP patterns are you familiar with? 55 | 56 | --- 57 | #### Answer: 58 | 59 | Some common OOP patterns include: 60 | - Singleton pattern: which ensures that a class has only one instance 61 | - Factory pattern: which creates objects without specifying the exact class of object that will be created 62 | - Decorator pattern: which allows behavior to be added to an individual object, either statically or dynamically 63 | - Observer pattern: which allows objects to be notified of changes to other objects 64 | ### 🔶 4. How is an interface different from an abstract class? 65 | 66 | --- 67 | #### Answer: 68 | An interface is a collection of abstract methods (methods with no implementation) that a class must implement. An abstract class is a class that contains one or more abstract methods, but may also have implemented methods. An interface defines a contract, but an abstract class can provide a partial implementation. 69 | ### 🔶 5. What are class methods defined through the @classmethod decorator? What are they needed for? 70 | 71 | --- 72 | #### Answer: 73 | Class methods are methods that are bound to the class and not the instance of the object. They are defined using the @classmethod decorator and take the class as the first argument instead of self. They are useful for creating alternative constructors for a class. 74 | 75 | ### Example: 76 | ```python 77 | class Dog: 78 | def __init__(self, name, breed): 79 | self.name = name 80 | self.breed = breed 81 | 82 | @classmethod 83 | def create_from_tuple(cls, name_breed_tuple): 84 | return cls(*name_breed_tuple) 85 | 86 | dog = Dog.create_from_tuple(("Fido", "Golden Retriever")) 87 | print(dog.name) 88 | ``` 89 | ### 🔶 6. How are private attributes declared in Python? 90 | 91 | --- 92 | #### Answer: 93 | In Python, private attributes are denoted by a double leading underscore. This is a convention indicating that the attribute should not be accessed directly from outside the class, although it can still be accessed if necessary. 94 | 95 | ### Example: 96 | ```python 97 | class Dog: 98 | def __init__(self, name, breed): 99 | self.__name = name 100 | self.__breed = breed 101 | def get_name(self): 102 | return self.__name 103 | def get_breed(self): 104 | return self.__breed 105 | 106 | dog = Dog("Fido", "Golden Retriever") 107 | print(dog.__name) # This will raise an AttributeError 108 | print(dog.get_name()) # This will return "Fido" 109 | ``` 110 | ### 🔶 7. What is MRO in Python? 111 | 112 | --- 113 | #### Answer: 114 | The Method Resolution Order (MRO) is the order in which the interpreter looks for methods in a class hierarchy. In Python, the MRO is determined by C3, which is a linearization algorithm that finds the order of methods that avoids diamond problem and provide a consistent method resolution order. It works by first determining the depth of the class, and then the order of classes by checking the left-most class first, and then moving to the right. 115 | 116 | ### Example: 117 | ```python 118 | class A: 119 | def method(self): 120 | print("Class A method") 121 | 122 | class B(A): 123 | pass 124 | 125 | class C(A): 126 | def method(self): 127 | print("Class C method") 128 | 129 | class D(B, C): 130 | pass 131 | 132 | d = D() 133 | d.method() # Output: "Class C method" 134 | ``` 135 | in the above example, python interpreter first look for the method in class D, it's not present then it looks in class B which also not present then it looks in class C and it found the method there so it will use this method. 136 | 137 | You can use the built-in help function to check the MRO of a class, it prints the order of classes that Python will look through when searching for a method. 138 | ```python 139 | help(D) 140 | ``` 141 | This will output something like 142 | ```python 143 | class D(B, C) 144 | | Method resolution order: 145 | | D 146 | | B 147 | | C 148 | | A 149 | ``` 150 | It lists the classes in the order that Python will look for methods in them. 151 | 152 | ### Back to top ⬆️ 153 | 154 | -------------------------------------------------------------------------------- /Python_General.md: -------------------------------------------------------------------------------- 1 | # Python general questions 2 | 3 | ### 🔶 1. What is the complexity in O-notation of the len operation of list? 4 | 5 | --- 6 | #### Answer: 7 | The complexity of the len operation of a list in Python is O(1). This is because the length of a list is stored as a separate attribute, making it a constant-time operation to retrieve the length. 8 | 9 | ### 🔶 2. And in the O-notation, the difficulty of obtaining an element by index in a list? 10 | 11 | --- 12 | #### Answer: 13 | The complexity of obtaining an element by index in a list in Python is O(1). This is because lists in Python are implemented as arrays, which allow for constant-time access to elements by index. 14 | 15 | ### 🔶 3. What is the structure of the implementation of dictionaries? How is the fight against key collisions implemented? 16 | 17 | --- 18 | #### Answer: 19 | Dictionaries in Python are implemented as a hash table. The fight against key collisions is implemented by using a technique called open addressing, which involves finding the next open slot in the table for a key-value pair that would have otherwise collided with an existing key. 20 | 21 | ### 🔶 4. How does the Garbage Collector work in Python? 22 | 23 | --- 24 | #### Answer: 25 | The Garbage Collector in Python works by periodically checking for objects in memory that are no longer being used by the program. Once such objects are identified, they are deallocated and their memory is freed up. 26 | 27 | ### 🔶 5. With what data structure is set implemented? 28 | 29 | --- 30 | #### Answer: 31 | A set in Python is implemented as a hash table. This allows for fast insertion, deletion and membership tests. 32 | 33 | ### 🔶 6. What are decorators and how do they work? 34 | 35 | --- 36 | #### Answer: 37 | Decorators in Python are a way to modify or extend the functionality of a function or class. They are implemented as functions that take another function as an argument and return a new function that usually includes the functionality of the original function. 38 | ```python 39 | def my_decorator(func): 40 | def wrapper(): 41 | print("Something is happening before the function is called.") 42 | func() 43 | print("Something is happening after the function is called.") 44 | return wrapper 45 | 46 | @my_decorator 47 | def say_hello(): 48 | print("hello!") 49 | 50 | say_hello() 51 | # Output: 52 | # Something is happening before the function is called. 53 | # hello! 54 | # Something is happening after the function is called. 55 | 56 | ``` 57 | ### 🔶 7. What are generators and how do they work? 58 | 59 | --- 60 | #### Answer: 61 | Generators in Python are a special type of iterator that allow a programmer to iterate over a sequence of items, without the need to keep the entire sequence in memory. They are implemented as functions that use the "yield" keyword to return an iterator, instead of a list. When a generator function is called, it returns a generator object, which can be used in a for loop or with the next() function to iterate through the generated sequence. 62 | ```python 63 | def my_gen(): 64 | yield 1 65 | yield 2 66 | yield 3 67 | 68 | for i in my_gen(): 69 | print(i) 70 | # Output: 71 | # 1 72 | # 2 73 | # 3 74 | ``` 75 | ### 🔶 8. What are context managers and how do they work? 76 | 77 | --- 78 | #### Answer: 79 | Context managers in Python are used to set up and tear down a context around a block of code. They are implemented using the "with" statement and a context manager object, which has methods such as "enter" and "exit" that are called when the context is entered and exited. This is useful for managing resources such as file and network connections, where it's important to ensure that the resources are properly closed and cleaned up after use. The "with" statement automatically handles the calls to the "enter" and "exit" methods, making it easy to ensure that the resources are properly managed, even in the presence of exceptions. 80 | 81 | ### Back to top ⬆️ 82 | -------------------------------------------------------------------------------- /Queues.md: -------------------------------------------------------------------------------- 1 | # Queues 2 | 3 | Modern architecture is hard to imagine without the use of queues. When preparing for an interview, do not lose sight of this block. The questions will focus on understanding the general ideas, the applicability of queues to tasks, and your experience with them. 4 | 5 | ### 🔶 1. What is a queue? 6 | 7 | --- 8 | #### Answer: 9 | A queue is a data structure that follows the First-In-First-Out (FIFO) principle, where the first element added to the queue is the first one to be removed. 10 | ### 🔶 2. What are some use cases for queues? 11 | 12 | --- 13 | #### Answer: 14 | Queues are often used for task management, such as scheduling background jobs, handling messages and events, and managing traffic in networks. They can also be used for buffering, load balancing, and rate limiting. 15 | ### 🔶 3. What are the main operations of a queue? 16 | 17 | --- 18 | #### Answer: 19 | The main operations of a queue are enqueue (adding an element to the queue), dequeue (removing an element from the queue), and peek (accessing the front element of the queue without removing it). 20 | ### 🔶 4. What is the difference between a queue and a stack? 21 | 22 | --- 23 | #### Answer: 24 | A queue follows the First-In-First-Out (FIFO) principle, where the first element added to the queue is the first one to be removed. A stack follows the Last-In-First-Out (LIFO) principle, where the last element added to the stack is the first one to be removed. 25 | ### 🔶 5. How would you implement a queue in Python? 26 | 27 | --- 28 | #### Answer: 29 | A queue can be implemented in Python using a list with the append() method for enqueue and the pop(0) method for dequeue. 30 | 31 | #### Example: 32 | ```python 33 | queue = [] 34 | queue.append(1) # enqueue 1 35 | queue.append(2) # enqueue 2 36 | 37 | print(queue.pop(0)) # dequeue 1 38 | print(queue) # [2] 39 | ``` 40 | 41 | ### 🔶 6. How would you implement a priority queue in Python? 42 | 43 | --- 44 | #### Answer: 45 | A priority queue can be implemented in Python using the heapq library. Elements are added to the queue with a priority value, and the element with the highest priority is always at the front of the queue. 46 | 47 | #### Example: 48 | ```python 49 | import heapq 50 | 51 | priority_queue = [] 52 | 53 | heapq.heappush(priority_queue, (2, 'task2')) 54 | heapq.heappush(priority_queue, (3, 'task3')) 55 | heapq.heappush(priority_queue, (1, 'task1')) 56 | 57 | print(heapq.heappop(priority_queue)) # (1, 'task1') 58 | ``` 59 | 60 | ### 🔶 7. What are some common use cases for message queues? 61 | 62 | --- 63 | #### Answer: 64 | Common use cases for message queues include: 65 | 66 | - Decoupling systems by allowing them to communicate asynchronously 67 | - Buffering and load leveling 68 | - Enabling the communication between microservices in a distributed system 69 | - Allowing for the reliable communication between systems with different performance characteristics 70 | - Facilitating the communication between event-driven systems 71 | - Enabling communication between processes, applications, and devices. 72 | ### 🔶 8. What are the benefits of using a message queue? 73 | 74 | --- 75 | #### Answer: 76 | Some benefits of using a message queue include: Decoupling systems, load balancing, buffering, and rate limiting. It also allows for asynchronous processing and can help prevent message loss in case of system failure. 77 | 78 | ### Back to top ⬆️ 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stack Questions 2 | Technical questions may be different, but they will all be aimed at revealing your knowledge and your level. If you don't know the correct answer to a question, feel free to say so. This will save time for both you and the interviewers. 3 | 4 | Interviewers often choose a strategy where the complexity and depth of questions grows until you hit the ceiling of your current knowledge. This allows interviewers to understand your current level and whether it is enough to solve the company's problems. 5 | 6 | Remember, the more detailed the answer, the more profound knowledge the interviewer will note for himself. 7 | 8 | --- 9 | ## Consider the main topics for questions you may encounter: 10 | - ### [Python.](/Python_General.md) 11 | Here are some general questions about Python and data types 12 | - ### [Asynchrony and concurrency in Python.](Asynchrony_and_Concurrency_Python.md) 13 | For answers, you need to remember everything you know about asynchrony from the GIL to coroutines and generators 14 | - ### [OOP.](OOP.md) 15 | OOP is often asked general questions, but you may come across questions related specifically to Python. Also, we can talk about different patterns 16 | - ### [SQL.](SQL.md) 17 | Questions aimed at knowledge of SQL databases and SQL dialect. The questions can be adapted for example to PostgreSQL or MySQL 18 | - ### [NoSQL.](NoSQL.md) 19 | This block of questions may arise if you have worked with NoSQL databases 20 | - ### [Architecture.](Architecture.md) 21 | During interviews for senior developers, a separate interview is allocated to check the skills of an architect 22 | - ### [Queues](Queues.md) 23 | When preparing for an interview, do not lose sight of this block. 24 | - ### [Testing.](Testing.md) 25 | It can be about your testing experience when you write tests, and about different hacks in the tests themselves. 26 | 27 | --- 28 | ## How to prepare to interview? 29 | Repeat everything on the topics from the “Questions about the stack” block - the more thoroughly, the better. Here is the finished checklist: 30 | - [ ] [Python](/Python_General.md) 31 | - [ ] [Asynchrony and concurrency in Python](Asynchrony_and_Concurrency_Python.md) 32 | - [ ] [OOP](OOP.md) 33 | - [ ] [SQL](SQL.md) 34 | - [ ] [NoSQL](NoSQL.md) 35 | - [ ] [Queues](Queues.md) 36 | - [ ] [Architecture](Architecture.md) 37 | - [ ] [Testing](Testing.md) 38 | 39 | --- 40 | ## Signs of the Middle+ level in these blocks: 41 | - You have experience with microservice architecture, as well as experience in splitting a monolithic application into microservices. 42 | - You worked with a company-relevant stack. This is not only about Python, but about all technologies, storages, queues and CI / CD. 43 | - You talk about the disadvantages of blindly following the requirements in response to the question about good / bad practice. 44 | - If you do not know ready-made solutions, you can come up with them based on your experience and knowledge. 45 | 46 | ### Back to top ⬆️ 47 | -------------------------------------------------------------------------------- /SQL.md: -------------------------------------------------------------------------------- 1 | # SQL 2 | 3 | ### 🔶 1. What types of relationships between tables do you know? 4 | 5 | --- 6 | #### Answer: 7 | Types of relationships between tables are: 8 | - One-to-One: where one record in table A corresponds to one record in table B 9 | - One-to-Many: where one record in table A corresponds to multiple records in table B 10 | - Many-to-Many: where multiple records in table A correspond to multiple records in table B 11 | ### 🔶 2. What types of JOIN do you know? What is the difference? 12 | 13 | --- 14 | #### Answer: 15 | - INNER JOIN: only returns records where there is a match in both tables 16 | - LEFT JOIN: returns all records from the left table and any matching records from the right table 17 | - RIGHT JOIN: returns all records from the right table and any matching records from the left table 18 | - FULL OUTER JOIN: returns all records from both tables 19 | ### 🔶 3. What is selectivity? 20 | 21 | --- 22 | #### Answer: 23 | Selectivity is the degree to which the values of a column in a table are unique. A column with high selectivity has unique values, while a column with low selectivity has many repeating values. This is important when creating indexes, because an index on a column with high selectivity will be more efficient than an index on a column with low selectivity. 24 | ### 🔶 4. Have you ever profiled requests? 25 | 26 | --- 27 | #### Answer: 28 | Profiling requests is the process of measuring the performance of a database query and identifying bottlenecks. This can be done using tools such as the EXPLAIN command in SQL or a database profiler. 29 | 30 | #### Example: 31 | ```postgresql 32 | EXPLAIN SELECT * FROM users_table WHERE name = 'Alice'; 33 | ``` 34 | ### 🔶 5. What is the difference between explain and explain analyze? 35 | 36 | --- 37 | #### Answer: 38 | The difference between EXPLAIN and EXPLAIN ANALYZE is that EXPLAIN shows the execution plan of the query without actually running it, while EXPLAIN ANALYZE not only shows the execution plan but also runs the query and provides statistics on its performance. 39 | 40 | ### 🔶 6. In what order is the SELECT query evaluated? 41 | 42 | --- 43 | #### Answer: 44 | SELECT query is evaluated in the following order: 45 | - FROM clause 46 | - JOIN clause 47 | - WHERE clause 48 | - GROUP BY clause 49 | - HAVING clause 50 | - SELECT clause 51 | - ORDER BY clause 52 | ### 🔶 7. What is an index? 53 | 54 | --- 55 | #### Answer: 56 | An index is a database feature that allows for faster searching and sorting of data. Indexes can be created on one or more columns of a table, and are used to quickly locate specific rows in the table. 57 | ### 🔶 8. What indexes do you know? 58 | 59 | --- 60 | #### Answer: 61 | Types of indexes: 62 | - B-Tree index 63 | - Bitmap index 64 | - Hash index 65 | - Full-text index 66 | - Spatial index 67 | 68 | ### 🔶 9. What is B-Tree? 69 | 70 | --- 71 | #### Answer: 72 | B-Tree index is a balanced tree data structure that stores data in a sorted order and allows for efficient insertion, deletion and search operations. It is commonly used in databases to improve the performance of SELECT, INSERT and UPDATE operations. In a B-Tree, the data is stored in a balanced tree, so the height of the tree is always 73 | 74 | --- 75 | 76 | ## Here is a list of features that correspond to the Middle+ level: 77 | - You quickly answer simple questions about indexes. 78 | - You are answering a question about transaction isolation levels. 79 | - You have experience in query profiling and optimization. 80 | - You can write complex queries such as window functions and CTEs. 81 | - You understand when not to write complex queries. 82 | 83 | ### Back to top ⬆️ 84 | -------------------------------------------------------------------------------- /Testing.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | ### 🔶 1. Do you write tests? What are the types of tests? 4 | 5 | --- 6 | #### Answer: 7 | Yes, I am familiar with writing tests. There are several types of tests, including: 8 | Unit tests: tests individual units of code, such as a specific function or method, in isolation. 9 | Integration tests: tests how different units of code work together. 10 | Functional tests: tests the functionality of a system as a whole by simulating user interactions. 11 | Performance tests: tests how a system performs under a certain load or stress. 12 | Acceptance tests: tests whether a system meets the requirements of the stakeholders. 13 | 14 | ### 🔶 2. What is mock? How to use it? 15 | 16 | --- 17 | #### Answer: 18 | A mock is a replacement for an object or a function that allows you to control its behavior during a test. This is useful when you have a dependency on an external service or a resource that is not available during the test. In Python, the unittest.mock library provides the MagicMock class for creating mocks. 19 | 20 | #### Example: 21 | ```python 22 | from unittest.mock import MagicMock 23 | 24 | def my_function(dependency): 25 | return dependency.do_something() 26 | 27 | # Create a mock object 28 | mock_dependency = MagicMock() 29 | 30 | # Test the function 31 | my_function(mock_dependency) 32 | 33 | # Assert that the mock's method was called 34 | mock_dependency.do_something.assert_called() 35 | ``` 36 | ### 🔶 3. How to test a function that depends on system time? 37 | 38 | --- 39 | #### Answer: 40 | To test a function that depends on system time, you can use the unittest.mock library to replace the datetime module with a mock. You can then control the current time returned by the mock. 41 | 42 | ```python 43 | from unittest.mock import MagicMock, patch 44 | 45 | def my_function(): 46 | from datetime import datetime 47 | return datetime.now().hour 48 | 49 | # Test the function 50 | with patch('datetime.datetime') as mock_datetime: 51 | mock_datetime.now.return_value = datetime(year=2020, month=1, day=1, hour=10) 52 | assert my_function() == 10 53 | ``` 54 | 55 | ### 🔶 4. How to check that mock was called once and with the right set of parameters? 56 | 57 | --- 58 | #### Answer: 59 | You can use the assert_called_once() and assert_called_with() methods provided by the MagicMock class to check if a mock was called with the expected parameters. 60 | 61 | #### Example: 62 | ```python 63 | mock_dependency.do_something.assert_called_once() 64 | mock_dependency.do_something.assert_called_with('arg1', 'arg2') 65 | ``` 66 | 67 | ### 🔶 5. How to test an async function? 68 | 69 | --- 70 | #### Answer: 71 | To test an async function, you can use the asyncio.run() method to run the function as a coroutine, or use the unittest.TestCase.loop context manager provided by the asynctest library. 72 | #### Example: 73 | ```python 74 | import asyncio 75 | 76 | async def my_async_function(): 77 | await asyncio.sleep(1) 78 | return 'Hello World' 79 | 80 | # Using asyncio.run 81 | assert asyncio.run(my_async_function()) == 'Hello World' 82 | 83 | # Using unittest.TestCase.loop 84 | import unittest 85 | from asynctest import TestCase 86 | 87 | class MyTestCase(TestCase): 88 | async def test_my_async_function(self): 89 | result = await my_async_function() 90 | self.assertEqual(result, 'Hello World') 91 | ``` 92 | 93 | ### 🔶 6. How to test code that runs in a thread or process? 94 | 95 | --- 96 | #### Answer: 97 | To test code that runs in a thread or process, you can use the unittest.TestCase.run_in_executor() method to run the function in a thread or process, and use the concurrent.futures library to create a thread or process pool. 98 | 99 | #### Example: 100 | ```python 101 | import concurrent.futures 102 | import unittest 103 | 104 | def my_function(): 105 | return 'Hello World' 106 | 107 | class MyTestCase(unittest.TestCase): 108 | def test_my_function(self): 109 | with concurrent.futures.ThreadPoolExecutor() as executor: 110 | future = executor.submit(my_function) 111 | self.assertEqual(future.result(), 'Hello World') 112 | 113 | with concurrent.futures.ProcessPoolExecutor() as executor: 114 | future = executor.submit(my_function) 115 | self.assertEqual(future.result(), 'Hello World') 116 | ``` 117 | 118 | ### 🔶 7. How to test a web application? 119 | 120 | --- 121 | #### Answer: 122 | To test a web application in Python, there are several popular libraries and frameworks that can be used. Some of the common options include: 123 | - unittest and requests: The built-in unittest library along with the requests library can be used to send HTTP requests to the application and test the responses. 124 | - pytest and pytest-flask: pytest is a popular testing framework that can be used to write test cases for a web application built with the Flask framework. 125 | - Django test client: The built-in django.test.Client class can be used to simulate client interactions and test the views, forms, and templates for an application built using the Django framework. 126 | - WebTest, Selenium: these are other libraries that can be used for testing web applications in python. 127 | - It's important to use the right tools and libraries depending on the framework, platform and the complexity of the application. 128 | 129 | 130 | ### Back to top ⬆️ 131 | --------------------------------------------------------------------------------