irahul
Joined 16 years ago
Joined 16 years ago
Is that why you made that absurd claim about sql injection being an explicit requirement? And that weird figure of 24 hours for handling sql injection, and api validation?
> Never assume a database or any IO call for that matter will always go right.
I said "db calls aren't randomly placed in try/catch - that will be absurd". Because they will be handled at app level to return uniform error messages. Now I am sure you will go on pretending that when you said "db calls aren't in try/catch", what you meant was db calls can throw an exception and app will handle it.
> Pretty much any large codebase, that passes objects around should always do Null pointer checks. This is because several times resource heavy objects are initialized only on certain conditions, and if such objects are passed around they must be checked.
What did I say about None checks not necessary because of something which is visible in the code? What do you think those marshmallow schemas and use_kwargs is for?
[1] There is a lot wrong with your "improvements". db calls aren't randomly placed in try/catch - that will be absurd. And the None checks aren't there because of something which you can very clearly see in the sample code but you also very clearly don't understand.
There is no laundry list. There is an expectation that a senior engineer writes codes like a senior engineer.
> You submitted code which doesn't have things in my laundry list. Noticeably your db calls aren't surrounded by try/except. You have written no documentation. You didn't ship the code with git repo. No unit or functional test cases. I also expect these days one would use Python's typing library. Most of this helps in code maintainability. The fact that your assignment has none of this means you can't be hired to write production code ....
Not sure if you are really this dense or playing dense - the point of the comment was to show that your assumption about api validation and sql injection being explicit requirements or taking too much time is ridiculous. It' simple that it can be written in a comment in about 10 minutes, not the "24 hours" or whatever you claim it is going to take.
The very fact that you think sql injection is an explicit requirement or takes work will be an instant deal breaker for any position with the possible exception of fresh grad positions.
> ... See where this is going?
Yes, I do. You are arguing reductio ad absurdum to hide the fact that the things which you claimed unreasonable are in fact routine, and your time estimates are off by order of 10.
No, not in 24 hours. In about 2 hours. The laundry list of things - api validation, error handling, db migrations, good naming - it's pretty routine. A person writing production apis will have no trouble integrating all of it in a very short period of time. This is after all what we do everyday. If a candidate thinks not having sql injection in the code is an explicit requirement or is going to take a lot of time, then that is not the person for the job.
Here is a pretty simple flask implementation of your laundry list - api validation, db migration, no sql injections, no n+1 queries, good naming, swagger ui...
from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_apispec import use_kwargs, marshal_with, MethodResource, FlaskApiSpec
from marshmallow import Schema, fields, validate, ValidationError
from sqlalchemy.orm import joinedload
# setup
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///dev.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
docs = FlaskApiSpec(app)
# Return validation errors as JSON
@app.errorhandler(422)
@app.errorhandler(400)
def handle_error(err):
headers = err.data.get("headers", None)
messages = err.data.get("messages", ["Invalid request."])
if headers:
return jsonify({"errors": messages}), err.code, headers
else:
return jsonify({"errors": messages}), err.code
# models
POST_TITLE_LENGTH_MAX = 80
POST_CONTENT_LENGTH_MAX = 5000
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(POST_TITLE_LENGTH_MAX), nullable=False)
content = db.Column(db.String(POST_CONTENT_LENGTH_MAX), nullable=False)
comments = db.relationship('Comment', back_populates='post')
COMMENTER_LENGTH_MAX = POST_TITLE_LENGTH_MAX
COMMENT_LENGTH_MAX = POST_CONTENT_LENGTH_MAX
class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
commenter = db.Column(db.String(COMMENTER_LENGTH_MAX), nullable=False)
comment = db.Column(db.String(COMMENT_LENGTH_MAX), nullable=False)
post_id = db.Column(db.ForeignKey('post.id'))
post = db.relationship('Post', uselist=False, back_populates='comments')
# schemas
class CommentSchema(Schema):
id = fields.Int(required=True, dump_only=True)
commenter = fields.Str(
required=True, validate=validate.Length(max=COMMENTER_LENGTH_MAX))
comment = fields.Str(
required=True, validate=validate.Length(max=COMMENT_LENGTH_MAX))
class PostSchema(Schema):
id = fields.Int(required=True, dump_only=True)
title = fields.Str(required=True, validate=validate.Length(
max=POST_TITLE_LENGTH_MAX))
content = fields.Str(required=True, validate=validate.Length(
max=POST_CONTENT_LENGTH_MAX))
comments = fields.Nested(CommentSchema, many=True, dump_only=True)
# dal
def get_post_list():
return Post.query.all()
def get_post(post_id):
return Post.query.options(joinedload(Post.comments)).get(post_id)
def create_post(title, content):
post = Post(title=title, content=content)
db.session.add(post)
db.session.commit()
return post
def add_comment_to_post(post_id, commenter, comment):
comment = Comment(commenter=commenter, comment=comment, post_id=post_id)
db.session.add(comment)
db.session.commit()
return comment
# views
class PostListResource(MethodResource):
@marshal_with(PostSchema(many=True))
def get(self):
return get_post_list()
@marshal_with(PostSchema)
@use_kwargs(PostSchema)
def post(self, title, content):
return create_post(title, content)
class PostResource(MethodResource):
@marshal_with(PostSchema)
def get(self, post_id):
return get_post(post_id)
class PostCommentResource(MethodResource):
@marshal_with(CommentSchema)
@use_kwargs(CommentSchema)
def post(self, post_id, commenter, comment):
return add_comment_to_post(post_id, commenter, comment)
app.add_url_rule('/posts', view_func=PostListResource.as_view('post_list'))
docs.register(PostListResource, endpoint='post_list')
app.add_url_rule('/posts/<int:post_id>',
view_func=PostResource.as_view('post'))
docs.register(PostResource, endpoint='post')
app.add_url_rule('/posts/<int:post_id>/comments',
view_func=PostCommentResource.as_view('post_comment'))
docs.register(PostCommentResource, endpoint='post_comment')Now you are telling me something I told you in the first place.
> What we might do here is to use two different keys symbols in different packages. We can have a ver2:keys and ver3:keys and control which of these dict.keys() uses in some scope. But that's not macros.
Right. So like I said, macros won't have helped, at all.
> Old syntax can be supported side by side with new syntax.
Creating a Frankenstein's monster was never the goal. And besides, they already had tools for code which can run both on 2 and 3.
https://pypi.python.org/pypi/future
> So then since we have a way to have old syntax and old API semantics, which is pretty much everything, we can have a nice migration path.
No, it's not a good migration path. 2to3 was a good migration path. Supporting n different versions of apis and syntax isn't a good migration path.
This has gone way too long. You made this claim:
"If Python had macros, Python 2 to 3 migration would be a non-issue."
That is patently false. I don't know why you can't simply accept you were wrong but I must check out now.
You are conflating "useless" with "secret sauce". I didn't claim they are useless. I said macros are a meme and are useful in very limited circumstances.
> if the hypothetical floop syntax changed there could be a ver2:floop and ver3:floop.
dict.keys() returned a list earlier, now it returns a "view". dict already had keys() and iterkeys(). Is that what you were referring to by your ver2:floop and ver3:floop? They changed keys() to act essentially like iterkeys() and removed iterkeys() because per them, this is the correct behavior.
Most changes in python 3 won't be helped by macros. Macros would have helped if they were adding say pattern match. But even then, it doesn't really matter much. If python itself is adding pattern match, they can write it in C, or python, or write a macro(if python had it) - it would have been all the same to me.
I am not saying macros aren't useful. I am saying macros are useful in limited circumstances and existence of macros won't have done anything for python 2 to 3 migration.
Are you following the discussion? The whole discussion arose from somehow macros make up for non-existence of libraries in Racket. Someone else wrote all those libraries for popular languages and I benefit from those existing libraries. Macros do fuck all if I have to wrap them myself. And even if I have to, most of the times it will be way simpler to wrap it in Python/Ruby.
You wrote a novella on your hypothetical macro use cases. I wrote I know what macros are. I don't know why you are throwing that at me.
> If Python had macros, Python 2 to 3 migration would be a non-issue. It wouldn't be a topic of discussion that non-Python-programmers know about.
This is what I mean when I say macros are a meme.
No, it won't have helped, at all. The changes in python 3 break the existing python 2 code.
> For example, this no longer works: k = d.keys(); k.sort(). Use k = sorted(d) instead (this works in Python 2.5 too and is just as efficient).
> The ordering comparison operators (<, <=, >=, >) raise a TypeError exception when the operands don’t have a meaningful natural ordering
> builtin.sorted() and list.sort() no longer accept the cmp argument providing a comparison function.
> The biggest difference with the 2.x situation is that any attempt to mix text and data in Python 3.0 raises TypeError, whereas if you were to mix Unicode and 8-bit strings in Python 2.x, it would work if the 8-bit string happened to contain only 7-bit (ASCII) bytes, but you would get UnicodeDecodeError if it contained non-ASCII values.
I could go on, but you get the idea.
I am not assuming the use of WSDL and macros still don't do much.
> Reducing boilerplate could make your code less buggy (bugs you catch with your eyes) and could make the meaning of the code more clear.
Macros aren't required for reducing boilerplate and don't necessarily reduce boilerplate compared to a non-macro solution in an expressive language.
I read almost all of racket's documentation cover to cover and learnt Clojure about 5 years ago. There are a lot of good things to say about them but as far as expressiveness go, but I didn't found them anymore expressive than Ruby or Python.
> Racket match is realy nice but it will shine if: > - You use a lot of immutable datasctructures. > - Explore shallow tree like data structures.
The things you pointed out are non-macro things. I like match, especially when it's well integrated in the lang. viz f#. I just don't like the difference that being able to cook up your match using macros makes a huge difference when it comes to programming productivity.
> i don't think macro are a meme
You misunderstand my point. Code generation with or without macros is useful. That's not a meme. "Macros are a secret sauce" is a meme.
I know what macros are and what macros can do. The parent poster made a comment that somehow macros can help overcome non-existence of wrappers in Racket. We both agree that macros won't help in this case, and my personal opinion is macros are a meme. They help some in very limited circumstances yet they are touted as a productivity multiplier. A pattern match over if-else doesn't really buy much. It's nicer, sure, but not by much.
Compare the raw format:
https://stripe.com/docs/api/curl#metadata
with Python:
https://stripe.com/docs/api/python#metadata
How are macros going to give me a better solution that the one which exists, is tested and have been used by others for some time? Besides, macros are a meme. What difference are macros going to make when wrapping a api? Can you show me an existing lisp/clojure wrapper which is more expressive than python/ruby?
All right. I will give it a last try. You would need a "list" if you are the one making a point that hiding your gut is just dignity while posting your abs online is narcissism. I was pointing out to parent poster that this point is not conducive as your are defining dignity and narcissism to suit your point of view. I don't understand how you missed it when it's written verbatim in the comment you replied to.
> Your comment was an own goal, I'm just beating a dead horse.
And here we go again. You think of something and put it down in your comment irrespective of context. What dead horse are you beating and why does this phrase make an appearance out of blue here?
> It's more mocking people who I consider lame.
At least we have the same agenda here. I too enjoy mocking bottom feeders who write diatribes out of their jealousy for people leading a better and more fulfilled lives than them.
> Which brings us back to your projected "Now you are making up arguments on my behalf and posting your retorts." haha.
Again, I am sure you think you have a point here and I am supposed to have an epiphany when I grok it, but honestly, all I see is random sentences chained together. I once saw a video of some pastor who brought a rock to a talk show as an irrefutable proof against evolution. I am kinda feeling the same as the talk host felt.
Cool man. You do you. Continue "caring for others" by, uh, posting comments on hn I suppose, and "being better", uh, again by posting comments on hn.
"I am so much better than insta influencers because, uh, I have a job? I don't seek validation from strangers? I am not sure but I sure know that they are the downfall of the humanity"