Gaode Business Framework (GBF): A Domain‑Driven Approach for Unified Portal Architecture
The Gaode Business Framework (GBF) is a lightweight, domain‑driven solution that unifies disparate industry portals by partitioning stable domains, standardizing interfaces, and providing customizable implementations, thereby eliminating duplicated glue code, improving design quality, reducing development costs, and enhancing stability and cross‑team collaboration.
Background
The Gaode Information Business US team provides aggregated downstream services (search, recommendation, advertising, offline, commerce, marketing, etc.) for various upstream channels such as end‑devices and car‑machines. Currently each industry portal (food, hotel, travel, entertainment, real‑estate, retail, etc.) is maintained in isolation, leading to duplicated "glue" code, inconsistent solution chains, and high maintenance costs.
Problems caused by this isolation include:
Inconsistent solution chains with multiple parallel implementations.
Repeated logic scattered across different applications.
Low design quality, higher fault rates, and linear growth of development cost with the number of portals.
Knowledge silos and poor cross‑team collaboration.
Unclear system boundaries increasing maintenance effort.
Goal
Provide a unified, standardized, and reasonable system design to improve reuse, reduce cost, and increase stability. Specific objectives are to:
Offer a stable implementation for fixed scenarios.
Improve design quality and maintainability, reducing fault rates.
Eliminate duplicate work and lower development cost.
Enhance knowledge management and team collaboration.
Clarify boundaries between teams and systems.
To achieve this, the team first identifies which parts of the business are frequently changing and which are relatively stable.
Design Overview
GBF (Gaode Business Framework) is a lightweight, domain‑driven framework that bridges product business and technical development across multiple industries and scenarios. It borrows concepts from TMF and DDD.
Why use GBF?
Higher analysis precision: Domains allow rapid pinpointing of requirements to specific problem areas.
Knowledge sharing and evolution: Domain experts maintain domain models, fostering collaboration.
Improved reusability and lower development cost: Similar functional modules are grouped into the same domain, enabling parallel development without coupling.
Increased stability: Decomposing the system into independent domains limits the impact of failures.
Example: Portal "Gold Bar" (金刚位) Component
Different industries implement the Gold Bar differently, causing code duplication. By treating the Gold Bar as a domain problem, GBF unifies its input, processing, and output.
Domain‑Driven Design Steps
1. Global domain partitioning – identify stable entities and behaviors.
2. Unified domain construction – define eight high‑level domains based on business analysis.
3. System layering – standardize input/output across layers.
4. Interface behavior unification with customizable implementations.
5. Portal overall architecture – define structure and process flow.
Code Example: Defining a Fetcher
@FetcherClient(name = "sug-fetcher")
public interface SugFetcher {
@FetcherMethod(name = "quicklink")
QuerySugResult<QuickLinkPO> getQuickLink(@RequestParam QuickLinkReqParam reqParam);
}Repository Interface and Implementation
public interface QuickLinkRepo {
@Annotation(title = "获取金刚位")
QuickLinkPO getQuickLink(QuickLinkReqParam reqParam);
}
@Service
public class QuickLinkRepoImpl implements QuickLinkRepo {
@Resource
SugFetcher sugFetcher;
@Override
public QuickLinkPO getQuickLink(QuickLinkReqParam reqParam) {
return Optional.ofNullable(sugFetcher.getQuickLink(reqParam))
.map(QuerySugResult::getData)
.orElse(null);
}
}Domain Service Definition
@DomainService(name = "运营领域金刚位服务", domain = OperationDomain.class)
public interface IQuickLinkDomainService {
QuickLinkDO getQuickLink(BaseRequest baseRequest);
}
@Service
public class QuickLinkDomainService implements IQuickLinkDomainService {
@Resource
QuickLinkRepo quickLinkRepo;
@Resource
IQuickLinkAbility quickLinkAbility;
@Override
public QuickLinkDO getQuickLink(BaseRequest baseRequest) {
QuickLinkReqParam param = quickLinkAbility.buildQueryParam(baseRequest);
QuickLinkPO po = quickLinkRepo.getQuickLink(param);
return quickLinkAbility.buildQuickLinkDO(po);
}
}Ability Interface and Default Implementation
@DomainAbility(name = "金刚位ability", domain = OperationDomain.class)
public interface IQuickLinkAbility {
@ActionExtensible(name = "构建金刚位请求参数")
QuickLinkReqParam buildQueryParam(BaseRequest request);
@ActionExtensible(name = "构建金刚位DO")
QuickLinkDO buildQuickLinkDO(QuickLinkPO po);
}
@Component
public class DefaultQuickLinkAction implements IQuickLinkAbility {
@Override
@Action(name = "构建金刚位请求参数")
public QuickLinkReqParam buildQueryParam(BaseRequest request) {
return new QuickLinkReqParam(request);
}
@Override
@Action(name = "构建金刚位DO")
public QuickLinkDO buildQuickLinkDO(QuickLinkPO po) {
return Optional.ofNullable(po)
.map(QuickLinkPO::getItems)
.map(Collection::stream)
.map(itemStream -> itemStream.map(p -> QuickLinkDO.ItemDO.builder()
.title(p.getTitle())
.icon(p.getIcon())
.iconHeight(p.getIconHeight())
.iconWidth(p.getIconWidth())
.logInfo(p.getLogInfo())
.toolTips(p.getToolTips())
.schema(p.getSchema())
.build())
.collect(Collectors.toList()))
.map(QuickLinkDO::new)
.orElse(null);
}
}Node Service and Process Registration
@ProcessNode(name = "QuickLinkService")
public class QuickLinkNodeService extends AbstractCommonNodeService<QuickLinkDO, BaseRequest> {
@Autowired
IQuickLinkDomainService quickLinkDomainService;
@Override
public QuickLinkDO doInvoke(BaseRequest request) {
return quickLinkDomainService.getQuickLink(request);
}
}
// Process configuration
BaseNodeConfigBuilder quickLinkNode = new NodeConfigBuilder()
.preJoinPoint(new JoinPoint<PortalParam, BaseRequest>() {
@Override
public BaseRequest join(PortalParam request) {
return request;
}
})
.nodeBeanName(BeanUtil.getBeanName(QuickLinkNodeService.class));
@Bean
public ProcessConfig portalProcess() {
return new ProcessConfigBuilder()
.request(Request.class)
.response(CommonResponse.class)
.nodes(userNode)
.nodes(filterTabNode)
.nodes(feedNode)
.nodes(bannerNode)
.nodes(quickLinkNode)
.build();
}Controller Registration
@RestController
@RequestMapping("/process")
public class ProcessController {
@GetMapping("/portal/{biz}")
@ResponseBody
public Result<Response> portal(@PathVariable String biz, PortalParam param) {
NodeService<Response, Request> process = BeanUtil.getSpringBean(
ProcessRegister.genericBeanName(PortalProcessConfig.BEAN_NAME));
param.setBizId(biz);
return process == null ? ProcessResult.fail("未找到流程") : process.invoke(param);
}
}Summary
By applying domain‑driven design through GBF, the US team achieves:
Standardized business processes and clear logic.
Decoupled domains that enable focused problem solving.
Reusable capabilities across different scenarios (nearby, event, generic search, etc.).
Improved knowledge sharing via visual process tools.
Enhanced stability and reduced coupling between functional nodes.
The framework’s strategy‑based routing (using bizId for industry and scenario for use‑case) allows a single interface to have multiple implementations, satisfying both uniformity and customization needs.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Amap Tech
Official Amap technology account showcasing all of Amap's technical innovations.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
