node seneca_使用Node.js和Seneca编写国际象棋微服务,第2部分

node seneca

处理新需求而无需重构 (Handling new requirements without refactoring)

Part 1 of this series talked about defining and calling microservices using Seneca. A handful of services were created to return all legal moves of a lone chess piece on a chessboard. The series continues in Part 3.

本系列的第1部分讨论了使用Seneca定义和调用微服务。 创建了一些服务,以返回棋盘上一个单独的棋子的所有合法举动。 该系列在第3部分中继续。

快速回顾: (A quick review:)

  • Seneca services are identified by a pattern consisting of role and cmd properties. Additional properties can be added to the pattern as well.

    Seneca服务由包含rolecmd属性的模式标识。 附加属性也可以添加到模式中。

this.add({role: "movement",cmd: "legalMoves"   //, otherProp: value, ...}, (msg, reply) => {...}
  • Services also have an implementation that takes a msg object and a reply callback. Themsg object contains the pattern properties in addition to all other data sent to the service.

    服务还具有一个接受msg对象和回复回调的实现。 msg对象除了发送到该服务的所有其他数据之外,还包含模式属性。

  • Seneca.act()is used to indirectly invoke a service. The act method takes an object and a callback function. The object contains the role, cmd, and other properties that comprise the message to the service.

    Seneca.act()用于间接调用服务。 act方法带有一个对象和一个回调函数。 该对象包含rolecmd和其他属性,这些属性构成向服务发送的消息。

seneca.act({role: "movement",cmd: "legalMoves",piece: p,board: board}, (err, msg) => {
  • When an action could be handled by more than one service that matches the pattern, the service with the most specific pattern match will be invoked.

    当一个动作可以由多个与模式匹配的服务来处理时,具有最特定模式匹配的服务将被调用。

There were a handful of services defined in the first part of this series. One of threerawMoves services took a piece and its position as parameters and returned 15 x 15 movement mask. These were truncated to an 8 x 8 board using alegalSquares service. The result was that the services together can return all the legal moves of any piece on any legal square of the otherwise empty chessboard.

在本系列的第一部分中定义了一些服务。 三个rawMoves服务之一将一块及其位置作为参数,并返回15 x 15移动蒙版。 使用legalSquares服务将它们截断成8 x 8的木板。 结果是这些服务可以一起返回原本空的棋盘的任何合法广场上的任何棋子的所有合法移动。

微服务和技术债务 (Microservices and Technical Debt)

One of the motivations for microservices is to reduce technical debt. Every project has deadlines and, as they loom larger, expediency often trumps quality. FIXME and TODO comments litter the source code after a while. Those comments identify technical debt that “someday” will be taken care of.

微服务的动机之一是减少技术债务 。 每个项目都有最后期限,并且随着期限的增加,权宜之计往往比质量重要。 FIXME和TODO注释过了一会儿会乱码源代码。 这些评论指出了“某天”将得到解决的技术债务。

总有一天永远不会来 (Someday never comes)

Microservices focus on functional decomposition and loose coupling. Neither of those are new ideas, but it is a rethinking about how to implement those concepts. A microservice should be small, single-purposed, and extensible. Extending a service can happen with few or no side-effects. A new service can extend an existing service, and neither the old service nor the client that once called it will know the service implementation changed. Less refactoring of classes, methods, method signatures, process flow… all this makes it easier to deal with dreaded TD.

微服务专注于功能分解和松散耦合。 这些都不是新想法,但这是对如何实现这些概念的重新思​​考。 微服务应小型,单一用途且可扩展。 扩展服务几乎没有副作用。 新服务可以扩展现有服务,并且旧服务或曾经调用它的客户端都不会知道服务实现已更改。 更少的类,方法,方法签名,过程流的重构……所有这些使得处理可怕的TD更容易。

回到游戏进行中… (Back to the game in progress…)

Moving a single chess piece around a lonely board is not really all that entertaining. In a real chess game the chessboard is shared with friendly and hostile pieces, and these impact each other’s movement.

在一个孤独的棋盘上移动单个棋子并不是真正有趣的事情。 在真正的国际象棋游戏中,国际象棋棋盘与友善而敌对的棋子共享在一起,这些棋子相互影响着对方的动作。

Right now I have alegalSquares service which can be the basis of a more completelegalMovesservice. If you recall, the legalSquares service would invoke a rawMovesservice, then remove all the ‘bad’ squares that didn’t belong on a chessboard.

现在,我有一个legalSquares服务,可以作为更完整的legalMoves服务的基础。 如果您还记得的话, legalSquares服务将调用rawMoves服务,然后删除所有不属于棋盘的“坏”正方形。

The new legalMoves service will take into account other pieces, something that legalSquares didn’t. This requires an extra parameter, one called board. The board is just going to be an array of ChessPiece instances, and will assume that the pieces on the board have already been checked for validity. For instance, two pieces don’t occupy the same square, pawns aren’t on the first rank, kings aren’t be next to each other, and so forth.

新的legalMoves服务将考虑其他部分,而legalSquares没有。 这需要一个额外的参数,称为boardboard将只是一个ChessPiece实例的数组,并将假定棋盘上的棋子已经过有效性检查。 例如,两个棋子不在同一广场上,棋子不在第一位,国王不在彼此之间,依此类推。

The following pattern will identify the service:

以下模式将标识服务:

'role: movement;cmd: legalMoves'

This pattern is a stringified version of JSON called jsonic; you can use a regular JSON object if you prefer. The message to the service will contain the pattern. It will also contain a ChessPiece instance that has a piece type such as ‘K’ing, ‘Q’ueen, ‘R’ook and board position (see algebraic notation). Later I’ll add to this class a piece color (White or Black) so that the service can tell friend from foe. But for now the service will assume all pieces are friendly.

此模式是JSON的字符串化版本,称为jsonic ; 您可以根据需要使用常规JSON对象。 发送给服务的消息将包含该模式。 它还将包含一个ChessPiece实例,其实例类型为“ K”,“ Q”,“ R”和棋盘位置(参见代数表示法)。 稍后,我将在该类中添加一块颜色(白色或黑色),以便该服务可以将敌人告诉朋友。 但就目前而言,该服务将假定所有部件都友好。

Since a friendly piece cannot be captured, it will restrict movement of other friendly pieces. Determining those restrictions is a bit of work. I made it harder for myself in the implementation of the rawMoves service… which brings me to:

由于无法捕获一个友善的棋子,它将限制其他友善棋子的移动。 确定这些限制需要一些工作。 在执行rawMoves服务时,我自己变得更加困难……这使我从事以下工作:

微服务不是万能药 (Microservices are not a Panacea)

If you design a service that retrieves or calculates information and doesn’t pass that data on up the chain, some service upstream may have to redo that work later. In my example, rawMoves returned an array of move objects (file and rank positions on the board). Let’s take the method that generates diagonal moves for a piece using the rawMoves service:

如果您设计的服务可以检索或计算信息, 但不会在链上传递该数据,则上游的某些服务可能必须稍后重做。 在我的示例中, rawMoves返回了一组移动对象(板上的文件和排名位置)。 让我们采用使用rawMoves服务为一块生成对角线移动的方法:

module.exports = function diagonal(position, range = 7) {var moves = [];const cFile = position.file.charCodeAt()const cRank = position.rank.charCodeAt();for (var i = 1; i < range + 1; i++) {moves.push({file: String.fromCharCode(cFile - i),rank: String.fromCharCode(cRank - i)});moves.push({file: String.fromCharCode(cFile + i),rank: String.fromCharCode(cRank + i)});moves.push({file: String.fromCharCode(cFile - i),rank: String.fromCharCode(cRank + i)});moves.push({file: String.fromCharCode(cFile + i),rank: String.fromCharCode(cRank - i)});}return moves;
}

At first glance, there’s nothing wrong with this. But, those fourmove.push operations actually operate along movement vectors. I could have constructed four movement vectors, then returned a list of moves by concatenating them, like so:

乍看之下,这没有什么错。 但是,这四个move.push操作实际上是沿着运动矢量进行操作的。 我本可以构造四个运动矢量,然后通过将它们连接起来返回一个运动列表,如下所示:

function diagonalMoves(position, range) {var vectors = [[], [], [], []];const cFile = position.file.charCodeAt()const cRank = position.rank.charCodeAt();for (var i = 1; i < range + 1; i++) {vectors[0].push({file: String.fromCharCode(cFile - i),rank: String.fromCharCode(cRank - i)});vectors[1].push({file: String.fromCharCode(cFile + i),rank: String.fromCharCode(cRank + i)});vectors[2].push({file: String.fromCharCode(cFile - i),rank: String.fromCharCode(cRank + i)});vectors[3].push({file: String.fromCharCode(cFile + i),rank: String.fromCharCode(cRank - i)});}const moves = Array.prototype.concat(...vectors)return moves;
}

As it stood, there was no point in doing this. But later on those vectors would have come in handy for truncating movements along diagonals (or ranks or files) when a friendly piece is in the way. Instead, I had to decompose the move list along vectors in services upstream — more work and inefficiency which you will see later.

就目前而言,这样做是没有意义的。 但是后来,当友好片段出现时,这些矢量将可以方便地沿对角线(或等级或文件)截断运动。 取而代之的是,我不得不沿着上游服务中的向量分解移动列表,这会增加工作量和效率,这将在以后看到。

The real flaw, though, was that I returned an array, rather than a data object. Data objects have properties that are extendable, not so arrays. As a consequence, all my upstream services depend on receiving a movement array, and only a movement array. No flexibility. I can’t now add a list of movement vectors in addition to a move list. But I could if I had returned an object from this method and the service that called it instead.

但是,真正的缺陷是我返回了一个数组,而不是一个数据对象。 数据对象具有可扩展的属性,而不是数组。 结果,我所有的上游服务都依赖于接收移动数组, 并且只有一个运动数组。 没有灵活性。 我现在不能添加除了运动向量的列表 到移动列表。 但是我可以从该方法和调用它的服务中返回一个对象。

Lesson learned? Consider returning data objects from your services. Have your upstream services work on parts of the data, but pass all data they receive back upstream. Exceptions to this rule will abound, of course.

学过的知识? 考虑从服务中返回数据对象。 让上游服务处理部分数据,但将它们接收的所有数据传回上游。 当然,会有很多例外。

和像这样的朋友一起... (With Friends like These…)

In Part 1, there was a service under the pattern:

在第1部分中,使用以下模式提供服务:

role:"movement",cmd:"legalSquares"

role:"movement",cmd:"legalSquares"

It returned all moves of an unimpeded piece. Since this will be the base service for determining legal moves on a populated chessboard, I’ll rename the cmdto legalMoves. Now I want to extend that to take into account friendly pieces that might be blocking a path of my chosen piece.

它返回了一块畅通无阻的动作。 由于这将是确定填充棋盘上法律动作的基本服务,因此我将cmd重命名为legalMoves 。 现在,我想扩展该范围,以考虑到可能会阻碍我选择的作品路径的友好作品。

扩展服务 (The extended service)

The service that extends role:"movement",cmd:"legalMoves" is… role:"movement",cmd:"legalMoves" !

扩展role:"movement",cmd:"legalMoves"是… role:"movement",cmd:"legalMoves"

Yep, it has the same service pattern as the service it calls. You may recall that services are identified by pattern, and so how it this going to work? When the program acts on role:"movement",cmd:"legalMoves", it will use the most recently defined service. But the new service has to call the formerlegalMoves service. That can be solved easily:

是的,它具有与其调用的服务相同的服务模式。 您可能还记得,服务是通过模式来标识的,那么它如何工作? 当程序执行role:"movement",cmd:"legalMoves" ,它将使用最新定义的服务。 但是新服务必须调用以前的legalMoves服务。 这很容易解决:

this.add({role: "movement",cmd: "legalMoves"}, (msg, reply) => {//returns unimpeded moves}this.add('role:movement,cmd:legalMoves', function (msg, reply) {this.
prior(msg, function (err, moves) {if (msg.board) {const boardMoves = legalMovesWithBoard(msg, moves);reply(err, boardMoves);return;}reply(err, moves);});});

This new service is able to call the former service by using the prior() method in Seneca. If no board parameter is supplied in the incoming msg object, then this service will just act as a pass-thru to the former service. But what if there is a board?

通过使用Seneca中的Priority prior()方法,此新服务可以调用以前的服务。 如果传入的msg对象中未提供board参数,则此服务将msg当前一个服务的直通。 但是,如果有董事会呢?

I’m not going to show a complete code listing here (see link below), but the gist of it is:

我不会在此处显示完整的代码清单(请参见下面的链接),但是要点是:

module.exports = function (msg, moves) {if (!msg.board) return moves;const blockers = moves.filter(m => {return (msg.board.pieceAt(m))})var newMoves = [];const pp = msg.piece.position;const rangeChecks = {B: diagonalChecks,R: rankAndFileChecks,K: panopticonChecks,Q: panopticonChecks,P: pawnChecks,N: knightChecks};var rangeCheck = rangeChecks[msg.piece.piece];// console.error(msg.piece.piece, rangeCheck.name)newMoves = moves.filter(m => {return rangeCheck(m, blockers, pp);})return newMoves;
}

Remember our old friend diagonalMoves from the rawMoves service? In order to do a range check on diagonals without handy vectors, the new legalMoves service calls this:

还记得我们来自rawMoves服务的老朋友diagonalMoves rawMoves吗? 为了对不带方便向量的对角线进行范围检查,新的legalMoves服务将其称为:

Ugly, no? I’d be happy if some algorithmically-inclined reader reduced this to two lines in the comments section. Three, even.

丑陋,不是吗? 如果某些有算法倾向的读者在评论部分将其减少到两行,我将感到高兴。 三,甚至。

So that takes care of friendly pieces. The next installment will deal with hostile pieces, which can be captured.

这样就可以处理友好的片段。 下一部分将处理可捕获的敌对碎片。

Full source code for this article can be found at GitHub.

可以在GitHub上找到本文的完整源代码。

翻译自: https://www.freecodecamp.org/news/follow-the-rules-with-seneca-ii-c22074debac/

node seneca

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/395234.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【OCR技术系列之八】端到端不定长文本识别CRNN代码实现

CRNN是OCR领域非常经典且被广泛使用的识别算法&#xff0c;其理论基础可以参考我上一篇文章&#xff0c;本文将着重讲解CRNN代码实现过程以及识别效果。 数据处理 利用图像处理技术我们手工大批量生成文字图像&#xff0c;一共360万张图像样本&#xff0c;效果如下&#xff1a;…

mysql 修改字段类型死锁_mysql数据库死锁的产生原因及解决办法

数据库和操作系统一样&#xff0c;是一个多用户使用的共享资源。当多个用户并发地存取数据 时&#xff0c;在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据&#xff0c;破坏数据库的一致性。加锁是实现数据库并 发控制…

openwrt无盘服务器,搭建基于 OpenWrt/gPXE/iSCSI 的 Windows 无盘工作站

本文要介绍的是如何在 OpenWrt 平台上面搭建无盘工作站服务器以及 Windows 的 iSCSI 部署。当然&#xff0c;由于 OpenWrt 也可以算得上一种 Linux 发行版了&#xff0c;所以本文所介绍的一些方法&#xff0c;在其它 Linux 发行版上面仍有一定的参考价值。整个过程大概分为以下…

Ralink5350开发环境搭建

一、安装虚拟机(Oracle VM VirtualBox 或 VMware Workstation) 二、在虚拟机中安装linux操作系统&#xff08;当前使用的是Ubuntu1204桌面版&#xff09; 三、配置linux相关服务 安装、配置、启动ftp服务apt-get install vsftpd 改动 vsftpd 的配置文件 /etc/vsftpd.conf,将以…

figma下载_Figma重新构想的团队库

figma下载一个新的&#xff0c;功能更强大的界面&#xff0c;用于在整个组织中共享组件 (A new, more powerful interface for sharing Components across your organization) The Team Library in Figma is a set of shared Components across all files in a Team. Component…

boost python导出c++ map_使用Boost生成的Python模块:与C++签名不匹配

我正在使用名为Mitsuba的软件。它附带了一个用Boost包装的Python实现。 Python中的这一行&#xff1a;使用Boost生成的Python模块&#xff1a;与C签名不匹配scene SceneHandler.loadScene(fileResolver.resolve("model.xml"), paramMap)产生一个错误。根据文档&…

CSU-1982 小M的移动硬盘

CSU-1982 小M的移动硬盘 Description 最近小M买了一个移动硬盘来储存自己电脑里不常用的文件。但是他把这些文件一股脑丢进移动硬盘后&#xff0c;觉得这些文件似乎没有被很好地归类&#xff0c;这样以后找起来岂不是会非常麻烦&#xff1f; 小M最终决定要把这些文件好好归类&a…

杜比服务器系统安装教程,win10杜比音效如何安装?win10安装杜比音效的详细教程...

杜比音效想必大家都不陌生&#xff0c;听歌或者看电影开启杜比音效可以给人一种身临其境的感觉。不少朋友都升级了win10系统却不知道如何安装杜比音效&#xff1f;如何为自己的系统安装杜比音效呢&#xff1f;感兴趣的小伙伴请看下面的操作步骤。win10安装杜比音效的方法&#…

剑指Offer_52_正则表达式匹配

题目描述 请实现一个函数用来匹配包括.和的正则表达式。模式中的字符.表示任意一个字符&#xff0c;而表示它前面的字符可以出现任意次&#xff08;包含0次&#xff09;。 在本题中&#xff0c;匹配是指字符串的所有字符匹配整个模式。例如&#xff0c;字符串"aaa"与…

分布式系统开发注意点_分布式系统注意事项

分布式系统开发注意点by Shubheksha通过Shubheksha 分布式计算概述&#xff1a;分布式系统如何工作 (Distributed Computing in a nutshell: How distributed systems work) This post distills the material presented in the paper titled “A Note on Distributed Systems”…

前端if else_应该记录的一些项目代码(前端)

1.共享登录&#xff08;单点登录&#xff09;主要是前端部分主要是根据是否有cookie来判断是否已经登录主系统&#xff0c;然后再根据是否有当前系统的登录信息来&#xff08;这块主要是sessionStorage做的&#xff09;判断是否要再登录当前系统。设置、读取和设置cookie的方法…

Mac端解决(含修改8.0.13版的密码):Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)...

1. 安装mysql但是从来没启动过&#xff0c;今天一启动就报错&#xff1a; Cant connect to local MySQL server through socket /tmp/mysql.sock (2) 其实是mysql服务没起来。。。 localhost:~ miaoying$ mysql.server start Starting MySQL ... SUCCESS! 然后再去sudo mysql就…

塔塔建网站服务器,塔塔帝国忘记哪个区怎么办

7条解答1.在哪个区玩战舰帝国忘记了怎么办?忘了的话可以去官网登陆看看自己的 充值 或者礼包记录 有没有对应的区服 或者电话联系问问客服 通过账号 角色名字来查询2.我忘记在哪个区怎么找如果你有游戏人生资格的话&#xff0c;就很容易找了&#xff0c;在游戏人生的个人主页里…

Ixia推出首款太比特级网络安全测试平台

2016年11月18日&#xff0c;Ixia宣布推出全新CloudStorm平台。作为首款太比特级网络安全测试平台&#xff0c;该平台拥有前所未有的非凡性能&#xff0c;可用于测试及验证超大规模云数据中心不断扩大的容量、效率以及弹性。 ▲Ixia CloudStorm安全测试平台 CloudStorm的正式面市…

[转]oracle分析函数Rank, Dense_rank, row_number

oracle分析函数Rank, Dense_rank, row_number 分析函数2(Rank, Dense_rank, row_number) 目录1.使用rownum为记录排名2.使用分析函数来为记录排名3.使用分析函数为记录进行分组排名一、使用rownum为记录排名&#xff1a; 在前面一篇《Oracle开发专题之&#xff1a;分析函数》&a…

Bali BaloCSS天才

Today Bali Balo, a French designer and developer, published a new piece: a cube suspended in darkness that rotates on its own. As it does, it reveals different sides, each offering a glimpse into a different world:今天&#xff0c;法国设计师兼开发商Bali Bal…

luogu P2470 [SCOI2007]压缩

传送门 dalao们怎么状态都设的两维以上啊?qwq 完全可以一维状态的说 设\(f[i]\)为前缀i的答案,转移就枚举从前面哪里转移过来\(f[i]min(f[j-1]w(j,i))(j\in [1,i])\) 现在要知道\(w(i,j)\)怎么写,也就是区间\([i,j]\)的最小长度(要求区间最多只能在开头有一个W),首先不压缩的长…

服务器选择重装系统,云服务器重装系统选择

云服务器重装系统选择 内容精选换一换将外部镜像文件注册成云平台的私有镜像后&#xff0c;您可以使用该镜像创建新的云服务器&#xff0c;或对已有云服务器的系统进行重装和更换。本节介绍使用镜像创建云服务器的操作。您可以按照通过镜像创建云服务器中的操作指导创建弹性云服…

T-Mobile美国加速开展5G实验:28GHz频段成为新宠

据日经社报道&#xff0c;T-Mobile美国公司正在加速开展5G相关工作&#xff0c;在过去的一个月中动作频频。 T-Mobile美国与三星电子美国公司上月初共同宣布&#xff0c;将在今年下半年使用28GHz频段和配备三星的波束成形技术的5G验证实验系统&#xff0c;开展室外5G移动通信的…

软件项目可行性分析定义_如何定义最低可行产品

软件项目可行性分析定义by George Krasadakis通过乔治克拉萨达基斯(George Krasadakis) 如何定义最低可行产品 (How to define a Minimum Viable Product) 从概念转变为正确定义的MVP (Moving from a concept to a properly defined MVP) The Minimum Viable Product, althoug…