Step 3 — Unit Design
A unit bazel target is defined via its implementation, corresponding tests and design.
So in a first step the class / sequence diagrams for a sw unit need to be defined:
class_design.puml
@startuml
' Class diagram for MyUnit — internal design of the key-value store unit.
class MyUnit {
- store_ : std::unordered_map<std::string, std::string>
+ configure(key : const string&, value : const string&) : void
+ get(key : const string&) : string
}
@enduml
src/my_unit.h
The public interface of the unit can be tied to its source symbols via a // trace: tag.
#pragma once
#include <string>
#include <unordered_map>
class MyUnit {
public:
// trace: MinimalExample.FEAT_001
void configure(const std::string &key, const std::string &value);
// trace: MinimalExample.FEAT_002
std::string get(const std::string &key) const;
private:
std::unordered_map<std::string, std::string> store_;
};
src/my_unit.cpp
#include "src/my_unit.h"
void MyUnit::configure(const std::string &key, const std::string &value) {
store_[key] = value;
}
std::string MyUnit::get(const std::string &key) const {
const auto it = store_.find(key);
return it != store_.end() ? it->second : "";
}
BUILD
Add a unit_design target, wire up the implementation, and reference both
from the unit:
load(
"@score_tooling//bazel/rules/rules_score:rules_score.bzl",
"unit",
"unit_design",
)
unit_design(
name = "MyUnit_design",
static = ["docs/class_design.puml"],
)
cc_library(
name = "my_unit_lib",
srcs = ["src/my_unit.cpp"],
hdrs = ["src/my_unit.h"],
)
unit(
name = "MyUnit",
implementation = [":my_unit_lib"],
scope = ["//:my_unit_lib"],
unit_design = [":MyUnit_design"],
tests = [],
)
The unit_design.static attribute accepts PlantUML files (class, state,
object diagrams); use dynamic for sequence and activity diagrams.
scope declares which targets the unit “owns” — targets outside the scope
that appear in the transitive implementation closure fail the scope check at
build time.
→ Full guide: Software Unit Design