-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Code Review 2 #2
Comments
Thank you for a very comprehensive review! Better explanation about setting up a Lichess bot account is probably in order. The current experience of starting a game and there being no indication about the game ending are certainly not ideal and something I would like to improve. I intended for the bot to be capable of automatically accepting challenges as well, but the implementation of the more specific chess rules like castling, en passant etc. took longer than I expected. Multithreading is something that I didn't even think about, but would make a lot of sense as a future improvement. I come from a mostly JavaScript/Node-background and wanted to experiment with new, but also somewhat familiar technologies with this project. Deno differs from Node in having a native TypeScript support so there is no need for a separate Having I agree with the suggestions on typing. The current types are a bit of a mess as I lack experience with TypeScript and initially used the chess.js library for most of the game logic. The Lichess API requires using UCI notation, but I would otherwise have only used array indexes instead of a mix of them and UCI board positions. The double definitions are an unfortunate end result of me not being sure what kind of documentation is expected for the project. I typically go with the also not ideal "the code is the documentation"-approach so I might have gone overboard with pointless comments this time. When it comes to arrow functions, I personally feel like it's simpler to just use the same function notation for both regular and lambda functions etc. but using the |
Context
Some context that might be very relevant to understanding my review, is that
I've actually worked with JavaScript using JSDoc and Typescript as helping
tools, using Node.js professionally for years. This means I have quite a lot of
experience with Javascript/Typescript and Node, but I might be making
assumptions about pure typescript and Deno. I have looked into using Deno at
work too instead of Node, but I'm not too familiar with it.
I also apologize that I do have quite a bit to say, but do keep in mind that I
have formed somewhat strict mindsets about typescript in my years of coding and
overall I think the codebase looks pretty good!
Documentation and first glance
When doing the initial registering, Lichess seems to make you check a few
boxes that imply that I'm breaking quite a few ToS rules while doing this:
Now I do personally understand that apparently to create a bot account, you do
need to first create a fresh account, so logically obviously I would not be
breaking ToS while doing this, but you might want to add a mention for that.
The linked lichess guide seems to want me to create a
config.yaml
file, andis in general a little confusing and does not seem to completely match this
project, you might want to simply make a direct reference to the wanted bit of
guide instead.
Seems the issue with the previous review (Vertaisarviointi #1) still applies, nowhere a mention
that a game should already be running. I also have absolutely no experience
with lichess, so it's not exactly easy to figure out what I needed to do to
get the program running properly.
The UI for the terminal application while the bot is running is pretty nifty
though, fun to look at.
At least my first attemt in a game ended with the bot winning, and it wasn't
able to resolve itself and got stuck in "Waiting for player move...". Not
great for user comprehension.
deno coverage
as stated intestausdokumentti.md
does not work out of thebox. Apparently I would need to specify a list of files.
When testing I noticed that of my 24 CPU threads only one was used at a time.
Now usually this might not be a problem, but I also noticed that the
depth-searching does take quite a while to run. You might want to look into
implementing the minimax alpha-beta-pruning utilizing multithreading. I'm not
too familiar with deno, but at least node has capable tools for building
multithreaded applications using Worker Threads. From what I
understand the algorithm is possible to implement multithreadedly at the cost
of understandability, but I would at least try to see what kind of performance
improvement it could have.
Moving on to reading and reviewing the actual code
Typescript issues, such as imports ending with
.ts
(
allowImportingTsExtensions
), which is against regular typescriptconventions and some issues with typing here. The latter error
seems to be caused by
events
-array being not typed and havingobj
beingnot typed. One thing I try to tell my more junior coworkers, when writing
typescript/typed javascript it is best to avoid using implicit any's, and
actually to enforce this I would recommend having
noImplicitAny
enabled inthe typescript configuration to enforce this, so implicit any's are easily
missed.
tsconfig.json
would be highlybeneficial, as you could through that actually control what kinds of
typescript rules you want to use (or not use, ie
allowImportingTsExtensions
as mentioned above). Here's a guide for adding a
tsconfig.json
forDeno-projects:
https://deno.com/[email protected]/advanced/typescript/configuration. I believe
Deno comes with some of it's own formatting tooling and whatnot, but utilizing
all of the formatting and linting tools in your disposal will usually make
things easier for both yourself and the people reading your code.
situations like this you should still stick to using
type
(type alias), if the typing is not meant specifically for extending, which
this type at least does not seem to be. The difference between
type
andinterface
are very small, but can cause issues down the line:Index signature is missing in type (only on interfaces, not on type alias) microsoft/TypeScript#15300
example the game loop could I think very well just be inside
the
run
function. A lot of programmers seem to have a "fear of longfunctions" but I think it's somewhat unwarranted. A function is fine even if
it's a few hundreds of lines long as long as it's straightforward and doesn't
have too much indentation. If the function does a lot of going
back-and-forward or very deep indentations, those are good situations where to
split functions into smaller components. Otherwise for readability I find that
it's better to put "as much linear algorithmic code as possible" into one
function¹. Having functions split this much makes this code for me a little
bit hard to follow.
¹: the above exception of course, where function is too indented or
goes back-and-forth too much.
the project again a little bit hard to follow. An easy example to give is
src/ai/chess/moves/directions.ts
. I honestly feel a little bitlike combining all the code in the whole
moves
-folder might actually be notthat bad, most of the files in that folder are less than 100 lines long. If
the files are designed to be longer eventually, that's somewhat fair enough,
but personally I would keep files merged until they need to be split, rather
than the other way around.
have the same variables/parameters doubly-defined.
By this I mean the types are defined both in-line and in the comments, which
at least seems redundant, and in many (like this linked one) inconsistent and
incorrect. I tend to prefer implicit typings at work, when said types are
available, because that means less places where something breaks when you
change a type in one place, because the implicit typings will be propagated
along the pipeline. One place I do however tend to use explicit types even
when implicit types are available, is sometimes in return values (at least in
public API) to make sure that the return values are always the same, and
breaking changes in return values are spotted early.
functions for defining regular functions, such as
here. I would recommend defining these functions
simply with
function
keyword as I personally think it makes the code a bitmore readable. I think arrow-functions are great for situations where you need
a closure so you don't need to use
Function.prototype.bind
,but in other places where the function is meant to be used regularly in-place
I think the
function
keyword makes the intent of the functions more clear.Defining them as arrow-functions into
const
variables makes it seem, thatthe functions are indeed meant to be variables that simply contain functions,
instead of just named functions, which is semantically slightly different and
I think it's a somewhat important diffrence.
such as
w
,b
,e1
, etc., such as here, and thething that I start to wonder if Enums would do a better job at
minimizing "magic numbers". I understand that for positions
in the board, like
e1
it might not be efficient, but I somewhat think, thatespecially since you seem to a bit of conversion in how the board positions
are represented, I think it might be better to simply represent them as Enums.
In conclusion
In conclusion I would say that at least in a quick glance this codebase seems
pretty alright, although there are quite a few changes (at least in semantics)
that I would personally make. Good job on this project, the program is certainly
fun to watch as it goes, and good luck going forward!
The text was updated successfully, but these errors were encountered: