Blame
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 1 | # **Scala** |
| 2 | ||||
| 3 | ### **1. General Principles** |
|||
| 4 | #### **1.1 Purpose** |
|||
| 5 | This document describes Scala coding standards to ensure code consistency, readability, and maintainability. Following these standards helps reduce errors. |
|||
| 6 | #### **1.2 Consistency** |
|||
| 7 | - In case of discrepancies between this standard and client standards, client standards take priority |
|||
| 8 | - Any deviation from the standard must be documented in comments with justification |
|||
| 9 | ||||
| 10 | ### **2. Coding Style** |
|||
| 11 | #### **2.1 Line Length** |
|||
| 12 | **Rule**: Line length should not exceed 120 characters |
|||
| 13 | - Break long expressions across multiple lines |
|||
| 14 | - Use appropriate break points (after operators, commas) |
|||
| 15 | **Example**: |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 16 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 17 | // Good |
| 18 | val result = longMethodName(parameter1, parameter2, parameter3) + |
|||
| 19 | anotherMethodCall() + |
|||
| 20 | yetAnotherCall() |
|||
| 21 | ||||
| 22 | // Bad |
|||
| 23 | val result = longMethodName(parameter1, parameter2, parameter3) + anotherMethodCall() + yetAnotherCall() |
|||
| 24 | ``` |
|||
| 25 | #### **2.2 Indentation** |
|||
| 26 | **Rule**: |
|||
| 27 | - Use 2 spaces for indentation. Tabs are prohibited. |
|||
| 28 | - Configure your editor accordingly |
|||
| 29 | ||||
| 30 | #### **2.3 Braces** |
|||
| 31 | **Rule**: |
|||
| 32 | - Opening brace stays on the same line as the expression |
|||
| 33 | - Closing brace on a separate line |
|||
| 34 | **Examples:** |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 35 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 36 | // Good |
| 37 | if (condition) { |
|||
| 38 | doSomething() |
|||
| 39 | } |
|||
| 40 | ||||
| 41 | try { |
|||
| 42 | operation() |
|||
| 43 | } catch { |
|||
| 44 | case e: Exception => handleError(e) |
|||
| 45 | } finally { |
|||
| 46 | cleanup() |
|||
| 47 | } |
|||
| 48 | ||||
| 49 | // For single-line expressions without side effects, braces can be omitted |
|||
| 50 | if (condition) doSomething() |
|||
| 51 | ||||
| 52 | // For multi-line or complex expressions - always use braces |
|||
| 53 | if (condition) { |
|||
| 54 | val result = calculate() |
|||
| 55 | process(result) |
|||
| 56 | } |
|||
| 57 | ``` |
|||
| 58 | #### **2.4 Whitespace** |
|||
| 59 | **Rule**: |
|||
| 60 | - Operators are surrounded by spaces |
|||
| 61 | - Space after commas |
|||
| 62 | - No space before colon in type ascription |
|||
| 63 | ||||
| 64 | **Example**: |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 65 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 66 | // Good |
| 67 | val sum = a + b |
|||
| 68 | val list = List(1, 2, 3) |
|||
| 69 | val x: Int = 42 |
|||
| 70 | ||||
| 71 | // Bad |
|||
| 72 | val sum=a+b |
|||
| 73 | val list = List(1,2,3) |
|||
| 74 | val x : Int = 42 |
|||
| 75 | ``` |
|||
| 76 | ||||
| 77 | ### **3. Naming** |
|||
| 78 | #### **3.1 Naming Styles** |
|||
| 79 | **Rules**: |
|||
| 80 | - `camelCase` for variables, methods, parameters |
|||
| 81 | - `PascalCase` (UpperCamelCase) for classes, traits, objects |
|||
| 82 | - `CONSTANT_CASE` for constants (final val) |
|||
| 83 | - `snake_case` for filenames and configuration keys |
|||
| 84 | ||||
| 85 | **Examples**: |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 86 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 87 | // Classes and traits |
| 88 | class UserRepository |
|||
| 89 | trait DatabaseService |
|||
| 90 | ||||
| 91 | // Methods and variables |
|||
| 92 | def getUserById(id: Long): Future[Option[User]] |
|||
| 93 | val maxRetryCount = 3 |
|||
| 94 | ||||
| 95 | // Constants |
|||
| 96 | final val DEFAULT_TIMEOUT = 30.seconds |
|||
| 97 | final val DATABASE_URL = "jdbc:postgresql://localhost/db" |
|||
| 98 | ||||
| 99 | // Packages |
|||
| 100 | package com.company.project.module |
|||
| 101 | ``` |
|||
| 102 | #### **3.2 Method Names** |
|||
| 103 | **Recommendations**: |
|||
| 104 | - Use verbs for methods that perform actions |
|||
| 105 | - Use nouns for methods that return values |
|||
| 106 | - Getter methods start with `get` only if there is a corresponding setter |
|||
| 107 | - Avoid single-letter names except for conventional ones (`i`, `j`, `k` for indexes) |
|||
| 108 | **Examples**: |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 109 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 110 | // Good |
| 111 | def calculateTotal(): BigDecimal |
|||
| 112 | def save(user: User): Future[User] |
|||
| 113 | def isValid: Boolean |
|||
| 114 | def user: User // instead of getUser |
|||
| 115 | ||||
| 116 | // Bad |
|||
| 117 | def totalCalculator(): BigDecimal |
|||
| 118 | def userSaver(user: User): Future[User] |
|||
| 119 | def checkIfValid: Boolean |
|||
| 120 | ``` |
|||
| 121 | ||||
| 122 | ### **4. Code Organization** |
|||
| 123 | #### **4.1 File Structure** |
|||
| 124 | **Rules**: |
|||
| 125 | - One main class/trait/object per file |
|||
| 126 | - Filename should match the main class name (PascalCase) |
|||
| 127 | - Try to keep file size within 500-1000 lines |
|||
| 128 | ||||
| 129 | #### **4.2 Declaration Order** |
|||
| 130 | **Recommendations**: |
|||
| 131 | 1. package declaration |
|||
| 132 | 2. Imports |
|||
| 133 | 3. Class/trait/object |
|||
| 134 | 4. Companion objects |
|||
| 135 | 5. Nested classes |
|||
| 136 | **Example**: |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 137 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 138 | package com.company.service |
| 139 | ||||
| 140 | import scala.concurrent.{Future, ExecutionContext} |
|||
| 141 | import java.time.LocalDateTime |
|||
| 142 | ||||
| 143 | class UserService { |
|||
| 144 | // fields |
|||
| 145 | // methods |
|||
| 146 | } |
|||
| 147 | ||||
| 148 | object UserService { |
|||
| 149 | // static methods |
|||
| 150 | } |
|||
| 151 | ``` |
|||
| 152 | ||||
| 153 | #### **4.3 Imports** |
|||
| 154 | **Rules**: |
|||
| 155 | - Group imports: first Scala standard library, then Java, then third-party libraries, then own packages |
|||
| 156 | - Use curly braces for importing multiple elements from the same package |
|||
| 157 | - Avoid wildcard imports (`import package._`) except in tests |
|||
| 158 | ||||
| 159 | **Example:** |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 160 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 161 | import scala.concurrent.{Future, ExecutionContext} |
| 162 | import scala.util.{Try, Success, Failure} |
|||
| 163 | ||||
| 164 | import java.time.LocalDateTime |
|||
| 165 | import java.util.concurrent.TimeUnit |
|||
| 166 | ||||
| 167 | import akka.actor.ActorSystem |
|||
| 168 | import com.typesafe.scalalogging.LazyLogging |
|||
| 169 | ||||
| 170 | import model.User |
|||
| 171 | import repository.UserRepository |
|||
| 172 | ``` |
|||
| 173 | ||||
| 174 | ### **5. Types and Variables** |
|||
| 175 | #### **5.1 Variable Declaration** |
|||
| 176 | **Rules**: |
|||
| 177 | - Use `val` by default, `var` only when necessary |
|||
| 178 | - Explicitly specify types for public API |
|||
| 179 | - Local variables can use type inference |
|||
| 180 | ||||
| 181 | **Examples:** |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 182 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 183 | // Good |
| 184 | val userName: String = "John" |
|||
| 185 | val count = calculateCount() // type inference acceptable for local variables |
|||
| 186 | ||||
| 187 | // Only when necessary |
|||
| 188 | var retryCount = 0 |
|||
| 189 | ||||
| 190 | // Bad |
|||
| 191 | var temporaryValue = compute() |
|||
| 192 | ``` |
|||
| 193 | ||||
| 194 | #### **5.2 Null Safety** |
|||
| 195 | **Rule**: |
|||
| 196 | - Avoid using `null`. Use `Option` for nullable values. |
|||
| 197 | ||||
| 198 | **Example**: |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 199 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 200 | // Good |
| 201 | def findUser(id: Long): Option[User] |
|||
| 202 | val maybeUser: Option[User] = findUser(123) |
|||
| 203 | ||||
| 204 | // Bad |
|||
| 205 | def findUser(id: Long): User = { |
|||
| 206 | // may return null |
|||
| 207 | } |
|||
| 208 | ``` |
|||
| 209 | ||||
| 210 | ### **6. Functions and Methods** |
|||
| 211 | #### **6.1 Method Signatures** |
|||
| 212 | **Recommendations**: |
|||
| 213 | - Limit number of parameters (maximum 5-7) |
|||
| 214 | - Use case classes for grouping related parameters |
|||
| 215 | - Explicitly specify return types for public methods |
|||
| 216 | ||||
| 217 | **Example**: |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 218 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 219 | // Good |
| 220 | case class SearchCriteria(query: String, limit: Int, offset: Int) |
|||
| 221 | ||||
| 222 | def searchUsers(criteria: SearchCriteria): Future[Seq[User]] |
|||
| 223 | ||||
| 224 | // Bad |
|||
| 225 | def searchUsers(query: String, limit: Int, offset: Int, |
|||
| 226 | sortBy: String, ascending: Boolean, |
|||
| 227 | includeInactive: Boolean): Future[Seq[User]] |
|||
| 228 | ``` |
|||
| 229 | ||||
| 230 | #### **6.2 Functional Style** |
|||
| 231 | **Rules**: |
|||
| 232 | - Prefer immutable collections |
|||
| 233 | - Use `map`, `flatMap`, `filter` instead of loops |
|||
| 234 | - Avoid side effects in pure functions |
|||
| 235 | ||||
| 236 | **Example**: |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 237 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 238 | // Good |
| 239 | val activeUsers = users.filter(_.isActive).map(_.toDto) |
|||
| 240 | ||||
| 241 | // Bad |
|||
| 242 | var activeUsers = List.empty[UserDto] |
|||
| 243 | for (user <- users) { |
|||
| 244 | if (user.isActive) { |
|||
| 245 | activeUsers = activeUsers :+ user.toDto |
|||
| 246 | } |
|||
| 247 | } |
|||
| 248 | ``` |
|||
| 249 | ||||
| 250 | ### **7. Error Handling** |
|||
| 251 | #### **7.1 Using Try/Either/Future** |
|||
| 252 | **Rules**: |
|||
| 253 | - Use `Try` for synchronous operations that may throw exceptions |
|||
| 254 | - Use `Either` for operations with domain-specific errors |
|||
| 255 | - Use `Future` for asynchronous operations |
|||
| 256 | ||||
| 257 | **Example**: |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 258 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 259 | // With Try |
| 260 | def parseNumber(s: String): Try[Int] = Try(s.toInt) |
|||
| 261 | ||||
| 262 | // With Either |
|||
| 263 | def validateUser(user: User): Either[String, User] = { |
|||
| 264 | if (user.name.isEmpty) Left("Name cannot be empty") |
|||
| 265 | else Right(user) |
|||
| 266 | } |
|||
| 267 | ||||
| 268 | // With Future |
|||
| 269 | def fetchUser(id: Long): Future[User] = { |
|||
| 270 | // asynchronous operation |
|||
| 271 | } |
|||
| 272 | ``` |
|||
| 273 | ||||
| 274 | #### **7.2 Exceptions** |
|||
| 275 | **Rules**: |
|||
| 276 | - Use specific exception types for domain errors |
|||
| 277 | - Log exceptions only at the level where they are handled |
|||
| 278 | - Preserve stack trace when wrapping exceptions |
|||
| 279 | ||||
| 280 | **Example**: |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 281 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 282 | class UserNotFoundException(id: Long) |
| 283 | extends RuntimeException(s"User with id $id not found") |
|||
| 284 | ||||
| 285 | try { |
|||
| 286 | userRepository.findById(userId) |
|||
| 287 | } catch { |
|||
| 288 | case e: UserNotFoundException => |
|||
| 289 | logger.error(s"User not found: $userId", e) |
|||
| 290 | Left(ResponseStatus.UserNotFound) |
|||
| 291 | case NonFatal(e) => |
|||
| 292 | logger.error("Unexpected error", e) |
|||
| 293 | Left(ResponseStatus.InternalServerError) |
|||
| 294 | } |
|||
| 295 | ``` |
|||
| 296 | ||||
| 297 | ### **8. Comments** |
|||
| 298 | #### **8.1 Documentation Comments** |
|||
| 299 | **Rules**: |
|||
| 300 | - Use Scaladoc for public API |
|||
| 301 | - Comment complex business logic |
|||
| 302 | - Avoid comments that duplicate code |
|||
| 303 | ||||
| 304 | **Example**: |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 305 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 306 | /** |
| 307 | * Repository for working with users. |
|||
| 308 | * |
|||
| 309 | * @param db database connection |
|||
| 310 | * @param ec execution context |
|||
| 311 | */ |
|||
| 312 | class UserRepository(db: Database)(implicit ec: ExecutionContext) { |
|||
| 313 | ||||
| 314 | /** |
|||
| 315 | * Finds user by identifier. |
|||
| 316 | * |
|||
| 317 | * @param id user identifier |
|||
| 318 | * @return Future with optional user |
|||
| 319 | */ |
|||
| 320 | def findById(id: Long): Future[Option[User]] = { |
|||
| 321 | // implementation |
|||
| 322 | } |
|||
| 323 | } |
|||
| 324 | ``` |
|||
| 325 | #### **8.2 TODO and FIXME** |
|||
| 326 | **Recommendations**: |
|||
| 327 | - Use standard tags: `TODO`, `FIXME`, `NOTE` |
|||
| 328 | - Include context and date |
|||
| 329 | ||||
| 330 | **Example**: |
|||
| 331 | ``` |
|||
| 332 | // TODO: Optimize query for large number of users (2024-01-15) |
|||
| 333 | // FIXME: Handle edge case with empty search string |
|||
| 334 | // NOTE: This method is used in reports, change with caution |
|||
| 335 | ``` |
|||
| 336 | ||||
| 337 | ### **9. Testing** |
|||
| 338 | #### **9.1 Test Structure** |
|||
| 339 | **Rules**: |
|||
| 340 | - Test classes are named as `ClassNameSpec` or `ClassNameTest` |
|||
| 341 | - Use readable test names |
|||
| 342 | - Group related tests using `describe`/`it` |
|||
| 343 | ||||
| 344 | **Example**: |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 345 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 346 | class UserServiceSpec extends AnyFlatSpec with Matchers { |
| 347 | ||||
| 348 | "UserService" should "return user by id" in { |
|||
| 349 | // test |
|||
| 350 | } |
|||
| 351 | ||||
| 352 | it should "return None for non-existent user" in { |
|||
| 353 | // test |
|||
| 354 | } |
|||
| 355 | ||||
| 356 | "save method" should "persist user to database" in { |
|||
| 357 | // test |
|||
| 358 | } |
|||
| 359 | } |
|||
| 360 | ``` |
|||
| 361 | #### **9.2 Mocking** |
|||
| 362 | **Recommendations**: |
|||
| 363 | - Use mocks only for external dependencies |
|||
| 364 | - Prefer real implementations where possible |
|||
| 365 | - Use dependency injection for testability |
|||
| 366 | ||||
| 367 | ### **10. Performance and Optimization** |
|||
| 368 | #### **10.1 Principles** |
|||
| 369 | **Rule**: |
|||
| 370 | - First write readable and correct code, optimize only when performance issues are proven. |
|||
| 371 | ||||
| 372 | #### **10.2 Common Pitfalls** |
|||
| 373 | **Avoid**: |
|||
| 374 | - Excessive copying of large structures |
|||
| 375 | - N+1 database queries |
|||
| 376 | - Blocking operations in asynchronous context |
|||
| 377 | ||||
| 378 | ### **11. Tools and Automation** |
|||
| 379 | #### **11.1 Formatting** |
|||
| 380 | Use Scalafmt for automatic code formatting. Configuration `.scalafmt.conf`: |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 381 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 382 | version = "3.7.14" |
| 383 | maxColumn = 120 |
|||
| 384 | continuationIndent.defnSite = 2 |
|||
| 385 | align.preset = some |
|||
| 386 | rewrite.rules = [SortImports] |
|||
| 387 | ``` |
|||
| 388 | ||||
| 389 | #### **11.2 Static Analysis** |
|||
| 390 | **Configure the following tools:** |
|||
| 391 | - Scalafix for refactoring |
|||
| 392 | - WartRemover for checking best practices |
|||
| 393 | - Scapegoat for identifying potential issues |
|||
| 394 | ||||
| 395 | ### **Appendix A: Examples** |
|||
| 396 | #### **A.1 Good Practices from the Code** |
|||
| 397 | **Using dependency injection:** |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 398 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 399 | class FuelGaugesRoutes @Inject()( |
| 400 | system: ActorSystem, |
|||
| 401 | userRepository: UserRepository, |
|||
| 402 | fuelGaugeRepository: FuelGaugeRepository, |
|||
| 403 | @Named("restActor") apiActor: ActorRef, |
|||
| 404 | config: Config |
|||
| 405 | )(implicit @Named("global") executionContext: ExecutionContext) |
|||
| 406 | ``` |
|||
| 407 | **Using type classes:** |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 408 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 409 | // Type class as trait with parameter |
| 410 | trait JsonWriter[A] { |
|||
| 411 | def write(value: A): Json |
|||
| 412 | } |
|||
| 413 | ||||
| 414 | // simple introduction JSON |
|||
| 415 | sealed trait Json |
|||
| 416 | case class JsString(value: String) extends Json |
|||
| 417 | case class JsNumber(value: Double) extends Json |
|||
| 418 | case class JsObject(fields: Map[String, Json]) extends Json |
|||
| 419 | ||||
| 420 | object JsonWriterInstances { |
|||
| 421 | // Instance for String |
|||
| 422 | implicit val stringWriter: JsonWriter[String] = |
|||
| 423 | (value: String) => JsString(value) |
|||
| 424 | ||||
| 425 | // Instance for Int |
|||
| 426 | implicit val intWriter: JsonWriter[Int] = |
|||
| 427 | (value: Int) => JsNumber(value.toDouble) |
|||
| 428 | ||||
| 429 | // Instance for Person |
|||
| 430 | case class Person(name: String, age: Int) |
|||
| 431 | ||||
| 432 | implicit val personWriter: JsonWriter[Person] = |
|||
| 433 | (person: Person) => JsObject(Map( |
|||
| 434 | "name" -> JsString(person.name), |
|||
| 435 | "age" -> JsNumber(person.age) |
|||
| 436 | )) |
|||
| 437 | ||||
| 438 | // Instance for Option (recursion instance) |
|||
| 439 | implicit def optionWriter[A](implicit writer: JsonWriter[A]): JsonWriter[Option[A]] = |
|||
| 440 | (option: Option[A]) => option match { |
|||
| 441 | case Some(value) => writer.write(value) |
|||
| 442 | case None => JsString("null") |
|||
| 443 | } |
|||
| 444 | } |
|||
| 445 | ||||
| 446 | object Json { |
|||
| 447 | def toJson[A](value: A)(implicit writer: JsonWriter[A]): Json = |
|||
| 448 | writer.write(value) |
|||
| 449 | } |
|||
| 450 | ||||
| 451 | // alternative syntax with context bound |
|||
| 452 | object JsonSyntax { |
|||
| 453 | implicit class JsonWriterOps[A](value: A) { |
|||
| 454 | def toJson(implicit writer: JsonWriter[A]): Json = |
|||
| 455 | writer.write(value) |
|||
| 456 | } |
|||
| 457 | } |
|||
| 458 | ``` |
|||
| 459 | ||||
| 460 | **Structuring configuration:** |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 461 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 462 | lazy val commonSettings = Seq[Def.SettingsDefinition]( |
| 463 | scalaVersion := "2.13.16", |
|||
| 464 | version := releaseVersion, |
|||
| 465 | organization := "dataroot" |
|||
| 466 | ) |
|||
| 467 | ``` |
|||
| 468 | ||||
| 469 | #### **A.2 Areas for Improvement** |
|||
| 470 | **Avoid overly long lines:** |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 471 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 472 | // Instead of: |
| 473 | val all = endpoint(request(Get, root /? (qs[Option[String]]("query") & qs[String]("sort_by") & qs[String]("asc") & qs[Int]("pageNumber") & qs[Int]("rowsNumber") /*& optQs [String]("filterParams")*/)), ok(jsonResponse[ResponseStatus Either GetResponse])) |
|||
| 474 | ||||
| 475 | // Break into: |
|||
| 476 | val all = endpoint( |
|||
| 477 | request( |
|||
| 478 | Get, |
|||
| 479 | root /? (qs[Option[String]]("query") & |
|||
| 480 | qs[String]("sort_by") & |
|||
| 481 | qs[String]("asc") & |
|||
| 482 | qs[Int]("pageNumber") & |
|||
| 483 | qs[Int]("rowsNumber") /*& optQs[String]("filterParams")*/) |
|||
| 484 | ), |
|||
| 485 | ok(jsonResponse[ResponseStatus Either GetResponse]) |
|||
| 486 | ) |
|||
| 487 | ||||
| 488 | ``` |
|||
| 489 | **Use explicit return types for public API:** |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 490 | ```Scala |
| 1b33c4 | Melisha Dsouza | 2026-01-15 17:28:50 | 491 | // Instead of: |
| 492 | def findAll2(user: User, parameters: GetParameters) = { |
|||
| 493 | // implementation |
|||
| 494 | } |
|||
| 495 | ||||
| 496 | // Use: |
|||
| 497 | def findAll2(user: User, parameters: GetParameters): Future[ResponseStatus Either GetResponse] = { |
|||
| 498 | // implementation |
|||
| 499 | } |
|||
| 500 | ||||
| 501 | ``` |
|||
| 502 | ||||
| 503 | **Appendix B: Code Review Checklist** |
|||
| 504 | - Compliance with naming standards |
|||
| 505 | - Line length does not exceed 120 characters |
|||
| 506 | - Correct indentation (2 spaces) |
|||
| 507 | - Explicit types for public API |
|||
| 508 | - No `null` and minimal use of `var` |
|||
| 509 | - Error handling via `Try`/`Either`/`Future` |
|||
| 510 | - Tests for new functionality |
|||
| 511 | - No commented-out code |
|||
| 512 | - Current TODO/FIXME with context |
|||
| 513 | - Correct Scaladoc comments for public API |
|||
| 514 | - Compliance with functional programming principles where appropriate |
|||
| 515 | - No blocking operations in asynchronous context |
|||
| 516 | - Efficient use of collections (without excessive copying) |
|||
| 8f5cc2 | Melisha Dsouza | 2026-01-16 10:12:49 | 517 | |
| 518 | **Document** - [Scala](https://docs.google.com/document/d/1gxq5pJsQ4cc5iDnf3h4ynMcpyM4A_sEUeKn9sNRjUec/edit?tab=t.0#heading=h.coq5eefrj3q) |