rcb
New to Elixir, finished first practice project, and would greatly appreciate feedback/tips for improvement
I’ve been learning Elixir during my month off between semesters. I started a practice project last week (a basic credit card validator application) that I just finished today. If anyone has some time that they wouldn’t mind sharing with me, I would really appreciate some feedback on my code — things like best practices, idiomatic Elixir code, extraneous functions or steps in algorithms, etc.
I’ve pushed the project to GitHub, which can be found here. The primary outer module (Cardinal) contains a simple driver function. The bulk of the work is done in the Cardinal.Validator and Cardinal.Checksum modules.
There are a few tasks/improvement areas that I know I need to address, which I’ve listed in the readme file. I’m sure that I’m missing a lot of areas for improvement, though; I had to rewrite a handful of things throughout the process as I discovered more and more built-in Elixir functions that made certain tasks much easier. Identifying more of such issues would be fantastic for learning more about Elixir.
Thank you very much to anyone willing to take a look and provide feedback.
Most Liked
rodrigues
Hi @rcb, good job, I see you’re catching up fast ![]()
![]()
A few points:
-
You should try
mix format
If you can change your editor to do it automatically on save, it gives you a nice feedback loop. On top of that, credo can also bring you some nice tips on style and code organization. -
Cardinal.Checksum.double_every_other/2could be like this instead, what do you think?
defp double_every_other([], _pos), do: []
defp double_every_other([head|tail], pos) when rem(pos, 2) == 0 do
[head | double_every_other(tail, pos + 1)]
end
defp double_every_other([head|tail], pos) when rem(pos, 2) == 1 do
[head * 2 | double_every_other(tail, pos + 1)]
end
Note that rem/2 can only be at the function head because it’s also a guard.
(EDIT: maybe just using Enum.with_index/1 and Enum.map/2 could be better than the above)
- Prefer
is_binary/1thanis_bitstring/1if you want a guard to guarantee it’s a String. Every binary is a bitstring, but not every bitstring is a binary.
Cheers!
rcb
Those look a lot cleaner than mine. The double_every_other() function was one I wrote early on when the program worked a bit differently and I don’t think I really revisited it much except for minor cleanup when the program changed. When I get back on my main machine, I’ll try this implementation out.
I didn’t realize that distinction was there between those two. I’ll change those out too.
Thanks for looking things over and taking the time to provide some guidance – I really appreciate it!
rcb
Thanks for the advice regarding passing IO to the private function. I’ve removed that and replaced it with regular IO.gets/puts calls. You’re right about the invalid data example too — I overlooked a pretty big error there. Thanks for the heads up on that, along with the link to the Luhn algorithm example and for taking the time to respond. I appreciate the help!
Also, thanks to both @srowley and @axelson for the excellent advice regarding the reduce_double_digits() function. I’ll work on implementing your suggestions too.
Thanks to everyone who took the time to review my code and provide such helpful advice. I really appreciate the help and guidance!








